diff --git a/README.md b/README.md index 5336811..3baecee 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,7 @@ docker compose exec -ti client bash # Get a Bash shell in the client container. * [push data to a full channel](https://github.com/deminy/swoole-by-examples/blob/master/examples/csp/deadlocks/channel-is-full.php) * [try to lock a locked file while the existing lock never gets released](https://github.com/deminy/swoole-by-examples/blob/master/examples/csp/deadlocks/file-locking.php) * [acquire a locked lock from another coroutine](https://github.com/deminy/swoole-by-examples/blob/master/examples/csp/deadlocks/swoole-lock.php) + * [improperly shutdown or reload a server](https://github.com/deminy/swoole-by-examples/blob/master/examples/csp/deadlocks/server-shutdown.php) * When the only coroutine yields its execution. The examples are shown in the next section when we talk about `How to detect/handle deadlocks`. * How to detect/handle deadlocks. In the following examples, we trigger deadlocks by yielding the execution of the only coroutine in the program. * [show deadlock information (the default behavior)](https://github.com/deminy/swoole-by-examples/blob/master/examples/csp/deadlocks/coroutine-yielded-1.php) @@ -112,6 +113,7 @@ docker compose exec -ti client bash # Get a Bash shell in the client container. * [timer](https://github.com/deminy/swoole-by-examples/blob/master/examples/timer/timer.php) * There is [a 2nd example](https://github.com/deminy/swoole-by-examples/blob/master/examples/timer/coroutine-style.php) included to show how to implement timer using coroutines only. * To see how to setup cronjobs using the _\Swoole\Timer_ class in an application server, please check [integrated HTTP/1 server](https://github.com/deminy/swoole-by-examples/blob/master/examples/servers/http1-integrated.php). + * cronjobs * benchmark * base mode vs multi-process mode * advanced topics diff --git a/examples/csp/deadlocks/server-shutdown.php b/examples/csp/deadlocks/server-shutdown.php new file mode 100755 index 0000000..d9c8ed4 --- /dev/null +++ b/examples/csp/deadlocks/server-shutdown.php @@ -0,0 +1,53 @@ +#!/usr/bin/env php +on('workerStart', function (Server $server, int $workerId) { + if ($workerId === 0) { // The first event worker process is used in this example. + // Create a coroutine that sleeps forever. + $cid = Coroutine::create(function () { + while (true) { // @phpstan-ignore while.alwaysTrue + if (Coroutine::isCanceled()) { + // The deadlock can be resolved by uncommenting line 41 and line 32. + // break; #2: Quit the infinite loop after the coroutine is canceled. + } + Coroutine::sleep(0.01); + } + }); + + // Shutdown the server after 2 seconds. + Timer::after(2_000, function () use ($server, $cid) { // @phpstan-ignore closure.unusedUse + // The deadlock can be resolved by uncommenting line 41 and line 32. + // Coroutine::cancel($cid); #1: Cancel the coroutine before shutting down the server. + + echo 'The server is shutting down.', PHP_EOL; + $server->shutdown(); + }); + } +}); + +// A dummy callback for the "request" event is required for the HTTP server. It has nothing to do with this example. +$server->on('request', function (Request $request, Response $response) { + $response->end('OK' . PHP_EOL); +}); + +$server->start();