Skip to content
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

Swoole HTTP server doesn't trigger ManagerStart event #5654

Open
Ser5 opened this issue Jan 5, 2025 · 10 comments
Open

Swoole HTTP server doesn't trigger ManagerStart event #5654

Ser5 opened this issue Jan 5, 2025 · 10 comments
Labels

Comments

@Ser5
Copy link
Contributor

Ser5 commented Jan 5, 2025

Please answer these questions before submitting your issue.

  1. What did you do? If possible, provide a simple script for reproducing the error.

Launched my script php server.php with the following code:

<?php
$server = new \Swoole\Http\Server('0.0.0.0', 9501);

$server->on('ManagerStart', function (\Swoole\Server $server) {
    echo "ManagerStart\n";
    \Swoole\Process::signal(SIGUSR1, function () use ($server) {
        $server->reload();
    });
});

$server->on('Connect', function (\Swoole\Server $server, int $fd, int $reactorId) {
    echo "Connect\n";
});

$server->on('Request', function ($request, $response) {
    echo "Request\n";
    $response->header('Content-Type', 'text/html; charset=utf-8');
    $response->end('<h1>Rand. #' . rand(1000, 9999) . '</h1>');
});

$server->start();

Then sent SIGUSR1 from the console:

kill -SIGUSR1 $(pgrep -f "php server.php")
  1. What did you expect to see?

"ManagerStart" in the console. Then reloading after receiving SIGUSR1.

  1. What did you see instead?

"ManagerStart" isn't printed in the console. SIGUSR1 shows an error:

WARNING swoole_signalfd_event_callback() (ERRNO 721): Unable to find callback function for signal User defined signal 1: 10

However, "Connect" and "Request" messages are displayed correctly.

  1. What version of Swoole are you using (show your php --ri swoole)?
swoole

Swoole => enabled
Author => Swoole Team <[email protected]>
Version => 6.0.0
Built => Dec 17 2024 05:36:37
coroutine => enabled with boost asm context
epoll => enabled
eventfd => enabled
signalfd => enabled
cpu_affinity => enabled
spinlock => enabled
rwlock => enabled
sockets => enabled
openssl => OpenSSL 1.1.1f  31 Mar 2020
dtls => enabled
http2 => enabled
json => enabled
curl-native => enabled
pcre => enabled
c-ares => 1.15.0
mutex_timedlock => enabled
pthread_barrier => enabled
futex => enabled
mysqlnd => enabled
coroutine_pgsql => enabled
coroutine_sqlite => enabled

Directive => Local Value => Master Value
swoole.enable_library => On => On
swoole.enable_fiber_mock => Off => Off
swoole.enable_preemptive_scheduler => Off => Off
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.unixsock_buffer_size => 8388608 => 8388608
  1. What is your machine environment used (show your uname -a & php -v & gcc -v) ?

uname -a
Linux us 5.4.0-204-generic #224-Ubuntu SMP Thu Dec 5 13:38:28 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

php -v

PHP 8.3.15 (cli) (built: Dec 24 2024 06:09:34) (NTS)
Copyright (c) The PHP Group
Zend Engine v4.3.15, Copyright (c) Zend Technologies
    with Zend OPcache v8.3.15, Copyright (c), by Zend Technologies

I didn't compiled Swoole with GCC, I installed it with

sudo apt install php8.3-swoole
@NathanFreeman
Copy link
Member

Please set the value of worker_num to be greater than 1.

$server->set([
    'worker_num' => 4
]);

@Ser5
Copy link
Contributor Author

Ser5 commented Jan 6, 2025

@NathanFreeman , hey, thank you! I tried your advice - but got even more confusing results.

Here is my current test script:

<?php
$server = new \Swoole\Http\Server('0.0.0.0', 9501);

$server->set([
    'worker_num' => 4,
]);

$server->on('ManagerStart', function (\Swoole\Server $server) {
    echo "ManagerStart\n";
    \Swoole\Process::signal(SIGUSR1, function () use ($server) {
        echo "SIGUSR1 callback\n";
        $server->reload();
    });
});

$server->on('Request', function ($request, $response) {
    echo "Request\n";
    $response->header('Content-Type', 'text/html; charset=utf-8');
    $response->end('<h1>Rand. #' . rand(1000, 9999) . '</h1>');
});

$server->start();

When I launch it, I see this:

php server.php
ManagerStart
PHP Warning:  Swoole\Process::signal(): signal [10] processor has been registered by the system in /var/www/custom/htdocs/server.php on line 10

Then I try to change the text in response to any other value and send the signal:
kill -SIGUSR1 $(pgrep -f "php server.php")

I get this messages:

[2025-01-06 05:26:23 *2891.1]   WARNING swoole_signalfd_event_callback() (ERRNO 721): Unable to find callback function for signal User defined signal 1: 10
[2025-01-06 05:26:23 $2889.0]   INFO    Server is reloading all workers now
[2025-01-06 05:26:23 *2892.2]   WARNING swoole_signalfd_event_callback() (ERRNO 721): Unable to find callback function for signal User defined signal 1: 10
[2025-01-06 05:26:23 *2890.0]   WARNING swoole_signalfd_event_callback() (ERRNO 721): Unable to find callback function for signal User defined signal 1: 10
[2025-01-06 05:26:23 *2893.3]   WARNING swoole_signalfd_event_callback() (ERRNO 721): Unable to find callback function for signal User defined signal 1: 10

The text from echo "SIGUSR1 callback\n"; isn't displayed.

Upon reloading the page I see that the output in the browser don't change - it still shows "Rand. #something".

Swoole triggers "ManagerStart", warns that the signal processor has been registered, says that the workers are reloaded - but doesn't actually reload them.

@NathanFreeman
Copy link
Member

You don't need to manually listen for the SIGUSR1 signal, as Swoole has already taken care of it for you. You just need to send the SIGUSR1 signal to the master process to restart the worker processes. The SIGUSR2 signal is used to restart both the worker and task processes.

@Ser5
Copy link
Contributor Author

Ser5 commented Jan 6, 2025

@NathanFreeman , yes, it seems Swoole tries to reload workers, but unsuccessfully.

<?php
$server = new \Swoole\Http\Server('0.0.0.0', 9501);

$server->set(['worker_num' => 4]);

$server->on('Request', function ($request, $response) {
    $response->header('Content-Type', 'text/html; charset=utf-8');
    $response->end('<h1>Rand. #' . rand(1000, 9999) . '</h1>');
});

$server->start();

Upon sending SIGUSR1 I still see the errors:

[2025-01-06 11:47:36 $7312.0]   INFO    Server is reloading all workers now
[2025-01-06 11:47:36 *7314.1]   WARNING swoole_signalfd_event_callback() (ERRNO 721): Unable to find callback function for signal User defined signal 1: 10
[2025-01-06 11:47:36 *7316.3]   WARNING swoole_signalfd_event_callback() (ERRNO 721): Unable to find callback function for signal User defined signal 1: 10
[2025-01-06 11:47:36 *7313.0]   WARNING swoole_signalfd_event_callback() (ERRNO 721): Unable to find callback function for signal User defined signal 1: 10
[2025-01-06 11:47:36 *7315.2]   WARNING swoole_signalfd_event_callback() (ERRNO 721): Unable to find callback function for signal User defined signal 1: 10

Swoole is missing something responsible for processing SIGUSR1.

@Ser5
Copy link
Contributor Author

Ser5 commented Jan 6, 2025

@NathanFreeman , by the way: when I started developing test scripts for Swoole, reloading did work. But after a few hours it disappeared and I started getting those errors. I can't imagine what caused this. Weird.

@NathanFreeman
Copy link
Member

NathanFreeman commented Jan 6, 2025

You only need to send the signal to the master process; the child processes do not listen for the SIGUSR1 signal, so it won't have any effect.

@Ser5
Copy link
Contributor Author

Ser5 commented Jan 6, 2025

Should I see the changes in the script in the browser upon sending SIGUSR1?

For example, if I first write
$response->end('<h1>Rand. #' . rand(1000, 9999) . '</h1>');

then change it to
$response->end('<h1>Changed response rand. #' . rand(1000, 9999) . '</h1>');

then send SIGUSR1.

Currently I don't see that any response changes. I only see them after restarting the server script.

@NathanFreeman
Copy link
Member

This is the expected behavior because the child process is forked from the parent process, so the code of the parent process remains unchanged

@Ser5
Copy link
Contributor Author

Ser5 commented Jan 6, 2025

Well, then can you please tell me how to reload the server without dropping the connections, like nginx nginx -s reload? It's required for hot reloading in dev mode and for updating the code on prod.

@NathanFreeman
Copy link
Member

Swoole does not support hot reload; you can only reload PHP files in the workerStart event.

// test.php
function response($response) {
    $response->end('Hello World');
}
$server->on('WorkerStart', function (\Swoole\Server $server) {
    require "test.php";
});

$server->on('Request', function ($request, $response) {
    test($response);
});

$server->start();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants