Skip to content

Commit bd2990c

Browse files
committed
HttpWorker - fix worker getting stuck due to missing 'continue' when out of app uncaught exception happens
1 parent d132b7f commit bd2990c

File tree

2 files changed

+49
-34
lines changed

2 files changed

+49
-34
lines changed

config/services.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
false,
8181
service(KernelInterface::class),
8282
service(EventDispatcherInterface::class),
83+
expr('env("APP_ENV") == "prod"'),
8384
service(SentryHubInterface::class)->nullOnInvalid(),
8485
service(HttpFoundationFactoryInterface::class)->nullOnInvalid(),
8586
])

src/Worker/HttpWorker.php

Lines changed: 48 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
use Spiral\RoadRunner;
1616
use Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory;
1717
use Symfony\Bridge\PsrHttpMessage\HttpFoundationFactoryInterface;
18+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
1819
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1920
use Symfony\Component\HttpFoundation\BinaryFileResponse;
2021
use Symfony\Component\HttpFoundation\Request;
22+
use Symfony\Component\HttpFoundation\Response;
2123
use Symfony\Component\HttpFoundation\StreamedJsonResponse;
2224
use Symfony\Component\HttpFoundation\StreamedResponse;
2325
use Symfony\Component\HttpKernel\Kernel;
@@ -38,6 +40,7 @@ public function __construct(
3840
private readonly bool $lazyBoot,
3941
private readonly KernelInterface $kernel,
4042
private readonly EventDispatcherInterface $eventDispatcher,
43+
private readonly bool $isProduction,
4144
private readonly ?SentryHubInterface $sentryHubInterface = null,
4245
?HttpFoundationFactoryInterface $httpFoundationFactory = null,
4346
)
@@ -75,53 +78,64 @@ public function start(): void
7578

7679
$this->eventDispatcher->dispatch(new WorkerBootingEvent());
7780

78-
try {
79-
while ($request = $worker->waitRequest()) {
81+
while (true) {
82+
try {
83+
$request = $worker->waitRequest();
84+
if ($request === null) {
85+
break;
86+
}
87+
} catch (\Throwable $throwable) {
88+
$worker->respond(new Psr7\Response(Response::HTTP_BAD_REQUEST));
89+
continue;
90+
}
91+
92+
try {
8093
$this->sentryHubInterface?->pushScope();
8194

82-
try {
83-
$this->eventDispatcher->dispatch(new WorkerRequestReceivedEvent());
95+
$this->eventDispatcher->dispatch(new WorkerRequestReceivedEvent());
8496

85-
$symfonyRequest = $this->httpFoundationFactory->createRequest($request);
86-
$symfonyResponse = $this->kernel->handle($symfonyRequest);
97+
$symfonyRequest = $this->httpFoundationFactory->createRequest($request);
98+
$symfonyResponse = $this->kernel->handle($symfonyRequest);
8799

88-
$content = match (true) {
89-
$symfonyResponse instanceof StreamedJsonResponse => StreamedJsonResponseWrapper::wrap($symfonyResponse),
90-
$symfonyResponse instanceof StreamedResponse => StreamedResponseWrapper::wrap($symfonyResponse),
91-
$symfonyResponse instanceof BinaryFileResponse => BinaryFileResponseWrapper::wrap($symfonyResponse, $symfonyRequest),
92-
default => DefaultResponseWrapper::wrap($symfonyResponse),
93-
};
100+
$content = match (true) {
101+
$symfonyResponse instanceof StreamedJsonResponse => StreamedJsonResponseWrapper::wrap($symfonyResponse),
102+
$symfonyResponse instanceof StreamedResponse => StreamedResponseWrapper::wrap($symfonyResponse),
103+
$symfonyResponse instanceof BinaryFileResponse => BinaryFileResponseWrapper::wrap($symfonyResponse, $symfonyRequest),
104+
default => DefaultResponseWrapper::wrap($symfonyResponse),
105+
};
94106

95-
$worker->getHttpWorker()->respond(
96-
$symfonyResponse->getStatusCode(),
97-
$content,
98-
$symfonyResponse->headers->all(),
99-
);
107+
$worker->getHttpWorker()->respond(
108+
$symfonyResponse->getStatusCode(),
109+
$content,
110+
$symfonyResponse->headers->all(),
111+
);
100112

101-
$this->eventDispatcher->dispatch(new WorkerResponseSentEvent());
113+
$this->eventDispatcher->dispatch(new WorkerResponseSentEvent());
102114

103-
if ($this->kernel instanceof TerminableInterface) {
104-
$this->kernel->terminate($symfonyRequest, $symfonyResponse);
105-
}
115+
if ($this->kernel instanceof TerminableInterface) {
116+
$this->kernel->terminate($symfonyRequest, $symfonyResponse);
117+
}
118+
} catch (\Throwable $throwable) {
119+
$this->sentryHubInterface?->captureException($throwable);
106120

107-
} catch (\Throwable $throwable) {
108-
$this->sentryHubInterface?->captureException($throwable);
109-
$worker->getWorker()->error((string)$throwable);
121+
if($this->isProduction) {
122+
$worker->respond(new Psr7\Response(Response::HTTP_INTERNAL_SERVER_ERROR));
123+
} else {
124+
$worker->respond(new Psr7\Response(Response::HTTP_INTERNAL_SERVER_ERROR, body: (string)$throwable));
125+
}
110126

111-
} finally {
112-
$result = $this->sentryHubInterface?->getClient()?->flush();
127+
$worker->getWorker()->error((string)$throwable);
113128

114-
// sentry v4 compatibility
115-
if ($result instanceof PromiseInterface) {
116-
$result->wait(false);
117-
}
129+
} finally {
130+
$result = $this->sentryHubInterface?->getClient()?->flush();
118131

119-
$this->sentryHubInterface?->popScope();
132+
// sentry v4 compatibility
133+
if ($result instanceof PromiseInterface) {
134+
$result->wait(false);
120135
}
136+
137+
$this->sentryHubInterface?->popScope();
121138
}
122-
} catch (\Throwable $throwable) {
123-
$worker->getWorker()->stop();
124-
throw $throwable;
125139
}
126140
}
127141
}

0 commit comments

Comments
 (0)