Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Async PHP Requests & Reactive Responses with PHP-FPM

Async PHP Requests & Reactive Responses with PHP-FPM

There are many approaches to execute PHP sub-tasks asynchronously or to parallelise PHP execution. While some solutions require extra extensions, individual PHP builds or a lot of process control management, this talk will show you how to configure and use the built-in PHP FastCGI Process Manager (php-fpm) to execute requests asynchronously in an isolated, tunable process pool and eventually handle their responses in a reactive way.

Meetup talk at PHP USERGROUP DRESDEN, Germany.

Holger Woltersdorf

June 08, 2017
Tweet

More Decks by Holger Woltersdorf

Other Decks in Programming

Transcript

  1. June 8th 2017 • PHPUGDD • Dresden • Check24 HOLGER WOLTERSDORF
    Async PHP Requests
    & Reactive Responses with PHP-FPM

    View Slide

  2. HOLGER WOLTERSDORF
    CIO • FATHER • HUSBAND • PHP DEV WITH ♥
    github.com/hollodotme
    @hollodotme

    View Slide

  3. View Slide

  4. SEPTEMBER 22nd
    ARNE
    BLANKERTS
    thePHPcc
    SEBASTIAN
    HEUER
    kartenmacherei
    JAN
    BURKL
    ZEND
    MARCO
    PIVETTA
    Ocramius
    STEPHAN
    HOCHDÖRFER
    bitExpert
    ALEXANDER
    MIERTSCH
    prooph software
    CHRISTIAN
    LÜCK
    reactPHP

    View Slide

  5. + async

    View Slide

  6. USE CASE
    PDF CREATION SERVICE

    View Slide

  7. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WE TRIED…
    7
    exec('php "/create-pdf.php" > /dev/null 2>&1 &');
    # OR
    shell_exec('php "/create-pdf.php" > /dev/null 2>&1 &');
    PHP 4 - 2001

    View Slide

  8. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WORKS, BUT…
    8
    ๏ PHP SCRIPT IS CALLED IN CLI MODE (DIFFERENT ENVIRONMENT)
    ๏ COMMAND GETS QUIET MESSY WHEN A LOT OF DATA SHOULD BE PASSED
    ๏ DATA HANDLING IN CALLED SCRIPT BASED ON $ARGV ARRAY
    ๏ RESPONSE ENDS UP IN NIRWANA
    ๏ DEBUGGING IS A NIGHTMARE (ESPECIALLY IN PRODUCTION)

    View Slide

  9. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WE TRIED…
    9
    $scriptUrl = 'http://www.yoursite.com/create-pdf.php';
    $ch = curl_init();
    curl_setopt( $ch, CURLOPT_URL, $scriptUrl );
    curl_setopt( $ch, CURLOPT_FRESH_CONNECT, true );
    curl_setopt( $ch, CURLOPT_TIMEOUT_MS, 1 );
    curl_exec( $ch );
    curl_close( $ch );
    PHP 5.2.3 - 2009
    $scriptUrl = 'http://www.yoursite.com/create-pdf.php';
    $ch = curl_init();
    curl_setopt( $ch, CURLOPT_URL, $scriptUrl );
    curl_setopt( $ch, CURLOPT_FRESH_CONNECT, true );
    curl_setopt( $ch, CURLOPT_TIMEOUT_MS, 1 );
    curl_exec( $ch );
    curl_close( $ch );

    View Slide

  10. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WORKS, BUT…
    10
    ๏ WEBSERVER ALWAYS INVOLVED (= OVERHEAD + ERROR SOURCE)
    ๏ MAYBE A LOAD BALANCER INVOLVED, TOO
    ๏ AT LEAST 2 ENVIRONMENTS TO MAINTAIN
    ๏ CURL EXTENSION NEEDED
    ๏ RESPONSE ENDS UP IN NIRWANA
    ๏ CALLED SCRIPT MUST BE EXPOSED (UNDER DOMAIN’S DOCUMENT ROOT)

    View Slide

  11. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WE TRIED VERY HARD…
    11
    $pdo->query(
    "INSERT INTO queue (id, script, data)
    VALUES ('123', '/create-pdf.php', '{json}')"
    );
    #/>$ crontab -e
    */1 * * * * php "/path/to/queue-processor.php"
    +

    View Slide

  12. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WORKS, BUT…
    12
    ๏ NO ON-DEMAND EXECUTION
    ๏ NEEDS A LOT OF LOCKING AND LOGGING
    ๏ RAISE CONDITIONS FOR THE WIN!
    ๏ ERRORS CAN PILE UP UNTIL SERVER IS DEAD
    ๏ HEAVY DATABASE LOAD FOR TECHNICALLY ELUSIVE DATA (HINT: BAD IDEA)
    ๏ MAINTENANCE OUTSIDE PHP PROJECT NEEDED (CRONTAB)
    ๏ HARD TO TEST

    View Slide

  13. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WE TRIED TO BE CLEVER…
    13
    function runInBackground()
    {
    include '/create-pdf.php';
    }
    register_shutdown_function( 'runInBackground' );
    header( 'Location: /show/user/a/page.php', true, 301 );
    flush();

    View Slide

  14. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WORKS, BUT…
    14
    ๏ WEBSERVER INVOLVED
    ๏ RESPONSE ENDS UP IN NIRWANA
    ๏ MEMORY LEAKS FOR THE WIN!
    ๏ PRETTY HARD ERROR HANDLING
    ๏ NO EXECUTION TIME LIMIT
    ๏ WTF? - DON’T TRY TO BE CLEVER!

    View Slide

  15. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WE COULD USE…
    15
    pthreads

    View Slide

  16. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WE COULD USE…
    16
    pthreads
    ๏ NEEDS CUSTOM PHP BUILD
    ๏ NOT ALL EXTENSIONS ARE THREAD-SAFE
    ๏ NOT WORKING IN WEB ENVIRONMENT
    ๏ BASIC KNOWLEDGE ABOUT MULTI THREADING NEEDED
    ๏ FEATURE AND CONFIG OVERHEAD FOR SIMPLE ASYNC TASKS
    ๏ PROCESS / THREAD MANAGEMENT IS UP TO YOU

    View Slide

  17. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WE COULD USE…
    17
    pcntl

    View Slide

  18. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WE COULD USE…
    18
    pcntl
    ๏ NEEDS CUSTOM PHP BUILD
    ๏ NOT WORKING ON WINDOWS
    ๏ BASIC KNOWLEDGE ABOUT UNIX PROCESSES NEEDED
    ๏ PROCESS MANAGEMENT IS UP TO YOU

    View Slide

  19. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WE COULD USE…
    19
    ๏ NEEDS ANOTHER PIECE OF INFRASTRUCTURE + PHP EXTENSION
    ๏ FEATURE RICH, BUT OVERLOADED FOR SIMPLE ASYNC TASKS
    ๏ A LOT OF SETUP FOR LOCAL DEVELOPMENT

    View Slide

  20. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WHAT DO WE WANT?
    20
    ๏ MAKE ASYNC CALLS TO PHP
    ๏ EVENTUALLY GET THE RESPONSES
    ๏ NO ADDITIONAL INFRASTRUCTURE
    ๏ NO ADDITIONAL EXTENSIONS
    ๏ WEB-REQUEST LIKE DATA HANDLING (BECAUSE WE’RE USED TO IT)
    ๏ BACKGROUND WORKERS NOT EXPOSED TO "PUBLIC"
    ๏ TUNEABLE PROCESS MANAGEMENT

    View Slide

  21. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    THE IDEA…
    21
    TALK BY ARNE BLANKERTS AT CONFOO / IPC IN 2016

    View Slide

  22. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WHAT I FOUND…
    22
    ๏ SEEMED OUTDATED AND UNMAINTAINED
    ๏ BUT DID A GOOD PART OF THE JOB
    PIERRICK CHARRON
    ๏ DESIGNED TO SEND SINGLE
    (A)SYNCHRONOUS REQUEST

    View Slide

  23. hollodotme/fast-cgi-client

    View Slide

  24. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    WHAT I DID…
    24
    ๏ UPDATED PHP LANGUAGE LEVEL TO 7.X
    ๏ Releases v1.x for PHP 7.0.x
    ๏ Releases v2.x for PHP 7.1.x
    ๏ SPLIT CODE INTO MULTIPLE CLASSES
    ๏ ADDED UNIT AND INTEGRATION TESTS
    ๏ POLISHED THE CONNECTION, CLIENT, REQUEST & RESPONSE INTERFACES
    ๏ ADDED FEATURES FOR MULTI-REQUESTS AND LOOP INTEGRATION
    ๏ ADDED USAGE DOCUMENTATION

    View Slide

  25. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    FACTS
    25
    ๏ LOC
    ๏ Lines of code 1036
    ๏ Logical lines of code 823
    ๏ Comment lines of code 213
    ๏ Average volume 218.58
    ๏ Average comment weight 30.19
    ๏ Average intelligent content 30.19
    ๏ Logical lines of code by class 37
    ๏ Logical lines of code by method 9
    ๏ OBJECT ORIENTED PROGRAMMING
    ๏ Classes 22
    ๏ Interface 5
    ๏ Methods 92
    ๏ Methods by class 4.18
    ๏ Lack of cohesion of methods 0.56
    ๏ Average afferent coupling 1.81
    ๏ Average efferent coupling 2.04
    ๏ Average instability 0.45

    View Slide

  26. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    CONNECT TO UNIX DOMAIN SOCKET
    26
    namespace YourVendor\YourProject;
    use hollodotme\FastCGI\Client;
    use hollodotme\FastCGI\SocketConnections\UnixDomainSocket;
    $connection = new UnixDomainSocket(
    # Socket path to php-fpm
    'unix:///var/run/php/php7.1-fpm.sock',
    # Connect timeout in milliseconds (default: 5000)
    5000,
    # Read/write timeout in milliseconds (default: 5000)
    5000
    );
    $client = new Client( $connection );

    View Slide

  27. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    PHP-FPM POOL CONFIG UNIX DOMAIN SOCKET
    27
    ; Pool name
    [background]
    ; Process ownership
    user = www-data
    group = www-data
    ; Socket path
    listen = /var/run/php/php7.1-fpm-background.sock
    ; Socket ownership
    listen.owner = www-data
    listen.group = www-data
    ; Process management
    pm = ondemand
    ; Maximum of children that can be alive at the same time
    pm.max_children = 5
    ; Number of seconds after which an idle children will be killed
    pm.process_idle_timeout = 10s

    View Slide

  28. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    CONNECT TO NETWORK SOCKET
    28
    namespace YourVendor\YourProject;
    use hollodotme\FastCGI\Client;
    use hollodotme\FastCGI\SocketConnections\NetworkSocket;
    $connection = new NetworkSocket(
    # Hostname or IP
    '127.0.0.1',
    # Port
    9000,
    # Connect timeout in milliseconds (default: 5000)
    5000,
    # Read/write timeout in milliseconds (default: 5000)
    5000
    );
    $client = new Client( $connection );

    View Slide

  29. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    PHP-FPM POOL CONFIG NETWORK SOCKET
    29
    ; Pool name
    [background]
    ; Process ownership
    user = www-data
    group = www-data
    ; Socket IP and Port
    listen = 127.0.0.1:9001
    ; Socket ownership
    listen.owner = www-data
    listen.group = www-data
    ; Process management
    pm = ondemand
    ; Maximum of children that can be alive at the same time
    pm.max_children = 5
    ; Number of seconds after which an idle children will be killed
    pm.process_idle_timeout = 10s

    View Slide

  30. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    SEND A SYNCHRONOUS REQUEST
    30
    # Content-type: ’application/x-www-form-urlencoded’ (default)
    $content = http_build_query( ['key' => 'value'] );
    # Simulate HTTP Verbs: GET, POST, PUT, PATCH, DELETE
    $request = new PostRequest( '/create-pdf.php', $content );
    $response = $client->sendRequest( $request );
    echo $response->getBody();

    View Slide

  31. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    RESPONSE INTERFACE
    31
    namespace hollodotme\FastCGI\Interfaces;
    interface ProvidesResponseData
    {
    public function getRequestId() : int;
    public function getHeaders() : array;
    public function getHeader( string $headerKey ) : string;
    public function getBody() : string;
    public function getRawResponse() : string;
    public function getDuration() : float;
    }

    View Slide

  32. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    ASYNC FIRE & FORGET
    32
    $client = new Client( new NetworkSocket( '127.0.0.1', 9000 ) );
    $content = http_build_query( ['key' => 'value'] );
    $request = new PostRequest( '/create-pdf.php', $content );
    $requestId = $client->sendAsyncRequest( $request );
    echo "Request sent, got ID: {$requestId}";

    View Slide

  33. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    ASYNC REQUEST + WAIT FOR RESPONSE
    33
    # ...
    $requestId = $client->sendAsyncRequest( $request );
    echo "Request sent, got ID: {$requestId}";
    # Do something in the meanwhile here ...
    $response = $client->readResponse( $requestId );
    # Blocking call until response is received or read timed out
    echo $response->getBody();

    View Slide

  34. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    USING RESPONSE CALLBACKS
    34
    # Response callbacks expect a ProvidesResponseData instance
    # ...variadic function
    $request->addResponseCallbacks(
    function( ProvidesResponseData $response ) {
    echo $response->getBody();
    }
    );
    # Failure callbacks expect a \Throwable instance
    # ...variadic function
    $request->addFailureCallbacks(
    function ( \Throwable $throwable ) {
    echo $throwable->getMessage();
    }
    );
    $requestId = $client->sendAsyncRequest( $request );

    View Slide

  35. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    USING RESPONSE CALLBACKS
    35
    # ...
    $client->waitForResponse( $requestId ); # Inner loop
    # ... is the same as
    while(true) # Outer loop
    {
    if ( $client->hasResponse( $requestId ) )
    {
    $client->handleResponse( $requestId );
    break;
    }
    }

    View Slide

  36. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    MULTIPLE REQUESTS - ORDERED RESPONSES
    36
    $requestIds = [];
    $requestIds[] = $client->sendAsyncRequest( $request1 );
    $requestIds[] = $client->sendAsyncRequest( $request2 );
    $requestIds[] = $client->sendAsyncRequest( $request3 );
    echo 'Sent requests: ' . implode( ', ', $requestIds ) . "\n";
    # Do something else here in the meanwhile ...
    # Blocking call until all responses are received or read timed out
    foreach ($client->readResponses(5000, ...$requestIds) as $response)
    {
    echo $response->getBody() . "\n";
    }

    View Slide

  37. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    MULTIPLE REQUESTS - ORDERED RESPONSES
    37
    # PRINTS
    Response #1
    Response #2
    Response #3
    ๏ NO MATTER HOW LONG EACH
    WORKER TOOK TO RESPOND

    View Slide

  38. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    MULTIPLE REQUESTS - REACTIVE RESPONSES
    38
    $requestIds = [];
    $requestIds[] = $client->sendAsyncRequest( $request1 );
    $requestIds[] = $client->sendAsyncRequest( $request2 );
    $requestIds[] = $client->sendAsyncRequest( $request3 );
    echo 'Sent requests: ' . implode( ', ', $requestIds ) . "\n";
    # Do something else here in the meanwhile ...
    while ( $client->hasUnhandledResponses() )
    {
    # read all ready responses
    foreach ( $client->readReadyResponses() as $response )
    {
    echo $response->getBody() . "\n";
    }

    echo '.';
    }

    View Slide

  39. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    MULTIPLE REQUESTS - REACTIVE RESPONSES
    39
    # ... is the same as
    while ( $client->hasUnhandledResponses() )
    {
    $readyRequestIds = $client->getRequestIdsHavingResponse();
    # read all ready responses
    foreach ( $readyRequestIds as $requestId )
    {
    $response = $client->readResponse( $requestId );
    echo $response->getBody() . "\n";
    }

    echo '.';
    }

    View Slide

  40. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    MULTIPLE REQUESTS - REACTIVE RESPONSES
    40
    # PRINTS
    .....Response #2
    .......Response #3
    ..........Response #1
    ๏ ORDERED BY RESPONSE TIME

    View Slide

  41. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    MULTIPLE REQUESTS - REACTIVE CALLBACKS
    41
    $client->waitForResponses(); # Inner loop
    # ... is the same as
    while ( $client->hasUnhandledResponses() ) # Outer loop
    {
    $client->handleReadyResponses();
    }
    # ... is the same as
    while ( $client->hasUnhandledResponses() ) # Outer loop
    {
    $readyRequestIds = $client->getRequestIdsHavingResponse();
    foreach ( $readyRequestIds as $requestId )
    {
    $client->handleResponse( $requestId );
    }
    }

    View Slide

  42. QUESTIONS?

    View Slide

  43. THANK YOU!
    github.com/hollodotme
    @hollodotme / @F9T3ch
    fortuneglobe.com
    phpug-dresden.org
    @phpugdd
    HOLGER WOLTERSDORF
    icehawk.github.io
    speakerdeck.com/hollodotme
    Slides available at:

    View Slide

  44. ASYNC PHP REQUESTS AND REACTIVE RESPONSES WITH PHP-FPM • JUNE 8th 2017 • PHPUGDD. • DRESDEN • CHECK24 HOLGER WOLTERSDORF
    LINKS / REFERENCES
    44
    ๏ PHP USERGROUP DRESDEN e.V. http://phpug-dresden.org
    ๏ PHP Developer Day 2017: https://bit.ly/PHPDD17EN
    ๏ Asynchronous cURL Requests: http://www.paul-norman.co.uk/2009/06/asynchronous-curl-requests/
    ๏ Arne Blankerts’ talk about nodejs + PHP: https://thephp.cc/dates/2016/02/confoo/just-married-node-js-and-php
    ๏ Original PHP FastCGI Client by Pierrick Charron: https://github.com/adoy/PHP-FastCGI-Client/
    ๏ PHP FastCGI Client: https://github.com/hollodotme/fast-cgi-client
    ๏ PHP FastCGI Client Demo: https://github.com/hollodotme/fast-cgi-client-demo
    ๏ FastCGI Specification: http://www.mit.edu/~yandros/doc/specs/fcgi-spec.html
    ๏ Experimental use-case with rabbitMQ: https://hollo.me/php/experimental-async-php-volume-2.html

    View Slide