Skip to content

Commit

Permalink
add new example to trigger deadlocks by improperly shutting down or r…
Browse files Browse the repository at this point in the history
…eloading a server

Signed-off-by: Demin Yin <deminy@deminy.net>
  • Loading branch information
deminy committed Dec 19, 2023
1 parent 2758639 commit ae7fb40
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions examples/csp/deadlocks/server-shutdown.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env php
<?php

declare(strict_types=1);

/**
* This example shows how deadlock happens when a server is shut down or reloaded improperly.
*
* How to run this script:
* docker run --rm -v $(pwd):/var/www -ti phpswoole/swoole php ./examples/csp/deadlocks/server-shutdown.php
* When the script is executed, it will print out the following error message:
* [FATAL ERROR]: all coroutines (count: 1) are asleep - deadlock!
* To fix the deadlock, uncomment line 41 and line 32, then rerun the script.
*/

use Swoole\Coroutine;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Swoole\Http\Server;
use Swoole\Timer;

$server = new Server('0.0.0.0');

$server->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();

0 comments on commit ae7fb40

Please sign in to comment.