Search code examples
phpiisioserial-portblocking

How do I generate a custom response when a script times out due to blocking io?


Goal

I am developing a JSON endpoint that basically reads data from a server-side COM port into a file (on the server end) when a user sends a GET request to it. The response from the server has to be a properly formed JSON response containing the name of the file where the contents were dumped to. If the COM port takes too long to respond, the file is closed and still considered valid with whatever contents it did read from the COM port. A valid response is still provided.

Problem

When the COM port is no longer being fed data, it blocks until the script times out. This results in an error and IIS provides a generic error page on a json endpoint. This is not valid json, but it also does not contain the name of the file where the com data was dumped to.

Details

  • I have to use the PHP Direct IO extension to interface with a serial com port.
  • This is blocking IO, and on windows, asynchronous IO is not supported (as far as I have seen.)
  • register_shutdown_function does not guarantee it is executed while a connection is still open to the client, so I cannot use this to print a valid response.

Solution

  • For your JSON endpoint, you could create a wrapper script that calls your IO script. Set a timeout for your attempt to get a response from it, and then return JSON with either whatever it got from the script, or some custom message if the script timed out.

    $timeout = 5;  // some reasonable time less than the wrapper script timeout
    
    $data = ['filename' => 'something'];            // create the file name
    $q = http_build_query($data);                   // pass it to the IO script
    
    $context = stream_context_create(['http'=> ['timeout' => $timeout]]);
    $response =  file_get_contents("http://yourserver/io_script.php?$q", false, $context);
    
    echo json_encode($data + ['data' => $response ?: 'no data']);