Open Swoole 4.10.0 released with coroutine selector, HTTP2 SSE streaming, sleep data type bug fixes and more

Published:

Open Swoole v4.10.0 is a major release with new Coroutine Selector API co::select(), HTTP2 SSE and bug fixes, sleep/usleep data type fixes and enhancements.

Open Swoole 4.10Open Swoole 4.10

New feature: Co::select, non-blocking coroutine channel selector

In the previous version, we have introduced Coroutine WaitGroup to wait until the finish of multiple channels. The basic $chan->push() and $chan->pop() are blocking.

You can implement non-blocking channel operations with co::select since Open Swoole v4.10.0.

You will be able to wait for at least one channel to be closed, ready to read or write and implement non-blocking sends, receives, and even non-blocking multi-way selects.

<?php declare(strict_types = 1);

Co::set(['hook_flags' => SWOOLE_HOOK_ALL]);

function fetchUrl($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, true);
    $response = curl_exec($ch);
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $header = substr($response, 0, $header_size);
    curl_close($ch);
    return $header;
}

Co\run(function () {
    $chan1 = new chan(1);
    $chan2 = new chan(1);

    go(function() use ($chan1) {
        $header = fetchUrl('https://openswoole.com/');
        $chan1->push(['id' => 'chan1', 'header' => $header]);
    });

    go(function() use ($chan2) {
        $header = fetchUrl('https://www.google.com/');
        $chan2->push(['id' => 'chan2', 'header' => $header]);
    });

    go(function() use ($chan1, $chan2){
        while(1) {
            $ret = co::select([$chan1, $chan2], [], 3);
            if(sizeof($ret['read']) === 0) break;
            $ret = array_values($ret['read'])[0]->pop();
            var_dump($ret);
        }
    });
});

To eliminate long-tail latency on a high concurrent system, you can use coroutines and co::select in multiple identical concurrent requests and the fastest response win.

You can find more about this API at /docs/modules/swoole-coroutine-select.

New feature: HTTP2 SSE server-sent events

When not used over HTTP/2, SSE suffers from a limitation to the maximum number of open connections. HTTP2 SSE is supported since Open Swoole v4.10.0.

Open Swoole HTTP2 SSE server-sent eventsOpen Swoole HTTP2 SSE server-sent events

Server side:

<?php
$http = new Swoole\HTTP\Server("0.0.0.0", 9501, SWOOLE_BASE, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$http->set([
    'open_http2_protocol' => 1,
    'enable_coroutine' => true,
    'ssl_cert_file' => __DIR__ . '/example.com+4.pem',
    'ssl_key_file' => __DIR__ . '/example.com+4-key.pem',
]);

$http->on('request', function (Swoole\HTTP\Request $request, Swoole\HTTP\Response $response) {

    $response->header('Access-Control-Allow-Origin', '*');
    $response->header('Content-Type', 'text/event-stream');
    $response->header('Cache-Control', 'no-cache');
    $response->header('X-Accel-Buffering', 'no');

    while(1) {
        $response->write("event: ping\n\n");
        $r = $response->write("data: {\"time\": \"" . date(DATE_ISO8601) . "\"}\n\n");
        if(!$r) return;
        co::sleep(1);
    }
    // never reach
    $response->end('DONE');
});

$http->start();

Client side:

<script type="text/javascript">
const eventSrc = new EventSource("https://localhost:9501/");
eventSrc.addEventListener('open', function (event) {
  console.log(event.type);
});

eventSrc.addEventListener('message', function (event) {

  console.log(event.type);
  console.log(event.data);

});
</script>

You can use curl or nghttp to debug HTTP2 applications:

nghttp  --hexdump -nv https://localhost:9501/
# or
curl -vv https://localhost:9501/

Fixes: Argument data type fixed at sleep() and usleep() API

sleep and usleep data type issues are fixed in this release.

PHP developers use sleep or usleep to pause the execution of the request for a while. They are also considered evil under PHP-FPM applications because sleep holds up the memory resources of the process.

Open Swoole introduced coroutine sleep API and hooks for sleep and usleep, you can find more details at /docs/runtime-hooks/swoole-hook-sleep and /docs/modules/swoole-coroutine-sleep. Both these APIs are resources consuming friendly, you can use them without harming the performance of your application.

In the previous versions, you used to be able to pass float type $seconds into co::sleep() API or the hooked sleep, while the argument data type of PHP sleep is int.

This inconsistency is fixed in Open Swoole v4.10.0. You will only be able to pass int into co::sleep() or use co::usleep() inline with PHP language.

New feature: Improved channel stats

Since Open Swoole v4.10.0, channel stats include a new field id: /docs/modules/swoole-coroutine-channel-stats.

New method $chan->getId() is added since Open Swoole v4.10.0.

You will also be able to look up a channel on your server or cluster in the future versions even the channel is not on the same machine.

Fixes: HTTP2 and TLS bug fixes

In the previous version, there are multiple bugs related to the HTTP2 protocol and fixed in Open Swoole v4.10.0. Deprecated and removed TLS Next Protocol Negotiation. Fixed HTTP2 server-side TLS ALPN.

Now you can access Open Swoole HTTP2, HTTPS, WebSocket server with Chrome and Firefox with local testing SSL certificates generated with mkcert. You can find more info at How to enable HTTPS/TLS at Open Swoole Server.

Open Swoole is supported by MacPorts

Thanks the community, you can install Open Swoole with port command in the future if you are a MacPorts user.

sudo port install php-openswoole

Use Open Swoole metrics and dashboard in Laravel Octane

You will be able to use Open Swoole Metrics API and Open Swoole Dashboard in a popular PHP framework Laravel Octane with one line of code within Laravel Controllers:

<?php
app(WorkerState::class)->server->stats();

Thanks the Open Swoole Contributors

You can upgrade to Open Swoole v4.10.0 now:

pecl install openswoole

Or use Docker images:

docker pull openswoole/swoole:latest

If you need to install Open Swoole or look at other update methods, checkout the installation documentation and how to update Open Swoole.