-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[possible bug?] worker_max_concurrency, requests queue and greaceful shutdown #5614
Comments
Because you have enabled |
I tried change reload_async => it is not changed behaviour above. $http->on('request', function ($request, $response) use ($http) {
$startTime = round(microtime(true),6);
$reqStartTime = $request->server['request_time_float'];
$info = $http->getClientInfo($response->fd);
echo "Worker {$http->worker_id} received request {$startTime} \n";
echo "Request CLIENT_STARTED_TIME: {$request->get['time']}\n";
echo "Request SWOOLE_STARTED_TIME: {$reqStartTime}\n";
echo "Request SWOOLE_LAST_TIME: {$info['last_recv_time']}\n";
echo "Request SWOOLE_LAST_SEND_TIME: {$info['last_dispatch_time']}\n";
sleep((int) $request->get['sleep'] ?? 1);
$response->end("<h1>Hello Swoole. #".rand(1000, 9999)."</h1>");
$endTime = round(microtime(true),6);
echo "Worker {$http->worker_id} finished request $endTime\n";
});
$http->on('start', function ($server) {
echo "Swoole http server is started at http://{$server->host}:{$server->port}\n";
swoole_set_process_name("swoole_http_server_master");
});
$http->on('workerStart', function ($server, $workerId) {
swoole_set_process_name("swoole_http_server_worker");
echo "Worker {$workerId} started\n";
});
$http->on('workerStop', function ($server, $workerId) {
echo "Worker {$workerId} stopped\n";
});
$http->on('workerError', function ($server, $workerId, $workerPid, $exitCode, $signal) {
echo "Worker {$workerId} error\n";
});
$http->on('shutdown', function ($server) {
echo "Swoole http server is shutdown\n";
});
$http->on('beforeShutdown', function ($server) {
echo "Before shutdown\n";
foreach ($server->connections as $fd) {
var_dump($fd);
}
});
$http->on('managerStart', function ($server) {
swoole_set_process_name("swoole_http_server_manager");
echo "Manager started\n";
});
$http->on('managerStop', function ($server) {
echo "Manager stopped\n";
});
$http->on('workerExit', function ($server, $workerId) {
echo "Worker {$workerId} exit\n";
});
$http->on('beforeReload', function ($server) {
echo "Before reload\n";
});
$http->on('afterReload', function ($server) {
echo "After reload\n";
});
$http->start(); Then run 1.php Make 2 curl requests (in parallel shell tabs):
First request pass to worker and sleep on 10sec (IO wait) In this moment we stop server
And here final result in server console:
As we see second request not going to worker after Before shutdown event. And we see here both connections. Second curl request fail.
|
What is the version of Swoole? |
I checked on Swoole v5.1.5 and also v6.0.0-rc1 (build on latest PHP 8.3) Video - https://imgur.com/a/yA3RH8v |
I'm not sure Anyway I made trace log by situation in shared video. Looks on |
When the process restarts, it attempts to complete the current request within a specified time, which is controlled by |
If queued requests will remain in If we will not set limit 'worker_max_concurrency' then worker will just start all requests in coroutines and restart/graceful shutdown will works as expected. But in my case I use worker_max_concurrency == to DB pool size - no sense take much request because of limit on DB pool size, so internal swoole request queue - great opportunity |
I wrote test to demonstrate what I'm saying. If you change const BTW: @matyhtf what you think about it? --TEST--
swoole_http_server: swoole should same behavior with any number of worker_max_concurrency
--SKIPIF--
<?php require __DIR__ . '/../include/skipif.inc'; ?>
--FILE--
<?php
require __DIR__ . '/../include/bootstrap.php';
const WORKER_MAX_CONCURRENCY = 2; // value with "1" produce test fail!
$pm = new ProcessManager;
$pm->parentFunc = function () use ($pm) {
go(function () use ($pm) {
$list[] = go (function () use ($pm) {
echo httpGetBody("http://127.0.0.1:{$pm->getFreePort()}/test?id=1") . PHP_EOL;
});
usleep(100_000); // first request should by start first
$list[] = go (function () use ($pm) {
echo httpGetBody("http://127.0.0.1:{$pm->getFreePort()}/test?id=2") . PHP_EOL;
});
usleep(100_000); // second request should start after first request
$pm->kill(); // then shutdown server until all request are done
\Swoole\Coroutine::join($list);
});
};
$pm->childFunc = function () use ($pm) {
$server = new Swoole\Http\Server('0.0.0.0', $pm->getFreePort(), SWOOLE_PROCESS);
$server->set([
'log_file' => '/dev/null',
'worker_num' => 1,
'enable_coroutine' => true,
'hook_flags' => SWOOLE_HOOK_ALL,
'enable_preemptive_scheduler' => true,
'max_concurrency' => 10,
'worker_max_concurrency' => WORKER_MAX_CONCURRENCY,
'reload_async' => true,
'max_wait_time' => 30,
'dispatch_mode' => 1,
'discard_timeout_request' => false,
]);
$server->on('start', function () use ($pm) {
$pm->wakeup();
});
$server->on('request', function (Swoole\Http\Request $request, Swoole\Http\Response $response) use ($pm) {
usleep(300_000); // we should wait processing until server will not start shutdown process
$response->end('OK'.$request->get['id'] ?? 0);
});
$server->start();
};
$pm->childFirst();
$pm->run();
?>
--EXPECT--
OK1
OK2 |
When the process is restarted, the requests in the queue will be discarded and not executed; otherwise, the process would take a long time to restart successfully. |
So you think it is normal just drop silently all requests in the queue? |
You're right; it would be better to return an error code to the client before rejecting these requests. I'll see how to modify it. |
Lets say we have max_concurrency > worker_max_concurrency settings like in example below:
If we make 2 LONG request (response time will be 10sec for each) to server, then 1 request will be handled onRequest() callback immediately, but second will wait in some queue backlog - it is expected and worked fine.
If after these 2 request we will start shutdown process (for example send SIGTERM to master process), then swoole will run
then first request will be done and send response to client
BUT second request will get
Questions:
The text was updated successfully, but these errors were encountered: