diff --git a/config/autoload/entity-manager.global.php b/config/autoload/entity-manager.global.php index 89961f77..951c909f 100644 --- a/config/autoload/entity-manager.global.php +++ b/config/autoload/entity-manager.global.php @@ -1,7 +1,7 @@ 'data/proxies', ], 'connection' => [ - 'user' => Common\env('DB_USER'), - 'password' => Common\env('DB_PASSWORD'), - 'dbname' => Common\env('DB_NAME', 'shlink'), + 'user' => env('DB_USER'), + 'password' => env('DB_PASSWORD'), + 'dbname' => env('DB_NAME', 'shlink'), 'charset' => 'utf8', ], ], diff --git a/config/autoload/middleware-pipeline.global.php b/config/autoload/middleware-pipeline.global.php index 100fa714..1e7877f5 100644 --- a/config/autoload/middleware-pipeline.global.php +++ b/config/autoload/middleware-pipeline.global.php @@ -10,10 +10,18 @@ return [ 'middleware_pipeline' => [ 'pre-routing' => [ - 'middleware' => [ - ErrorHandler::class, - Expressive\Helper\ContentLengthMiddleware::class, - ], + 'middleware' => (function () { + $middleware = [ + ErrorHandler::class, + Expressive\Helper\ContentLengthMiddleware::class, + ]; + + if (Common\Exec\ExecutionContext::currentContextIsSwoole()) { + $middleware[] = Common\Middleware\CloseDbConnectionMiddleware::class; + } + + return $middleware; + })(), 'priority' => 12, ], 'pre-routing-rest' => [ diff --git a/module/Common/config/dependencies.config.php b/module/Common/config/dependencies.config.php index b03520a3..1762d819 100644 --- a/module/Common/config/dependencies.config.php +++ b/module/Common/config/dependencies.config.php @@ -31,6 +31,7 @@ return [ Template\Extension\TranslatorExtension::class => ConfigAbstractFactory::class, Middleware\LocaleMiddleware::class => ConfigAbstractFactory::class, + Middleware\CloseDbConnectionMiddleware::class => ConfigAbstractFactory::class, IpAddress::class => Middleware\IpAddressMiddlewareFactory::class, Image\ImageBuilder::class => Image\ImageBuilderFactory::class, @@ -78,6 +79,7 @@ return [ Template\Extension\TranslatorExtension::class => ['translator'], Middleware\LocaleMiddleware::class => ['translator'], + Middleware\CloseDbConnectionMiddleware::class => ['em'], IpGeolocation\IpApiLocationResolver::class => ['httpClient'], IpGeolocation\GeoLite2LocationResolver::class => [Reader::class], diff --git a/module/Common/src/Middleware/CloseDbConnectionMiddleware.php b/module/Common/src/Middleware/CloseDbConnectionMiddleware.php new file mode 100644 index 00000000..867ffe02 --- /dev/null +++ b/module/Common/src/Middleware/CloseDbConnectionMiddleware.php @@ -0,0 +1,33 @@ +em = $em; + } + + /** + * Process an incoming server request and return a response, optionally delegating + * response creation to a handler. + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + $handledRequest = $handler->handle($request); + $this->em->getConnection()->close(); + + return $handledRequest; + } +} diff --git a/module/Common/test/Middleware/CloseDbConnectionMiddlewareTest.php b/module/Common/test/Middleware/CloseDbConnectionMiddlewareTest.php new file mode 100644 index 00000000..dc45bde8 --- /dev/null +++ b/module/Common/test/Middleware/CloseDbConnectionMiddlewareTest.php @@ -0,0 +1,53 @@ +handler = $this->prophesize(RequestHandlerInterface::class); + $this->em = $this->prophesize(EntityManagerInterface::class); + + $this->middleware = new CloseDbConnectionMiddleware($this->em->reveal()); + } + + /** + * @test + */ + public function connectionIsClosedWhenMiddlewareIsProcessed() + { + $req = ServerRequestFactory::fromGlobals(); + $resp = new Response(); + + $conn = $this->prophesize(Connection::class); + $closeConn = $conn->close()->will(function () { + }); + $getConn = $this->em->getConnection()->willReturn($conn->reveal()); + $handle = $this->handler->handle($req)->willReturn($resp); + + $result = $this->middleware->process($req, $this->handler->reveal()); + + $this->assertSame($result, $resp); + $getConn->shouldHaveBeenCalledOnce(); + $closeConn->shouldHaveBeenCalledOnce(); + $handle->shouldHaveBeenCalledOnce(); + } +}