reactphp / stream

Event-driven readable and writable streams for non-blocking I/O in ReactPHP.
https://reactphp.org/stream/
MIT License
626 stars 62 forks source link

Unable to set stream resource to non-blocking mode [not STDIN or STDOUT] #167

Closed CViniciusSDias closed 2 years ago

CViniciusSDias commented 2 years ago

I was able to reproduce the following error in several Windows machines: when trying to read a text file using ReadableResourceStream I receive RuntimeException: Unable to set stream resource to non-blocking mode.

Here is an example code:

<?php

use React\EventLoop\Factory;
use React\Stream\ReadableResourceStream;

require_once 'vendor/autoload.php';

$loop = Factory::create();

$arquivo = fopen('existing_file.txt', 'r+');
$stream = new ReadableResourceStream($arquivo, $loop);

$stream->on('data', function (string $data) {
    echo $data;
});

$loop->run();

And here is the full output:

PHP Fatal error:  Uncaught RuntimeException: Unable to set stream resource to non-blocking mode in C:\Users\carlo\OneDrive\Documentos\reactphp-windows\vendor\react\stream\src\ReadableResourceStream.php:58
Stack trace:
#0 C:\Users\carlo\OneDrive\Documentos\reactphp-windows\index.php(11): React\Stream\ReadableResourceStream->__construct(Resource id #17, Object(React\EventLoop\StreamSelectLoop))
#1 {main}
  thrown in C:\Users\carlo\OneDrive\Documentos\reactphp-windows\vendor\react\stream\src\ReadableResourceStream.php on line 58

Fatal error: Uncaught RuntimeException: Unable to set stream resource to non-blocking mode in C:\Users\carlo\OneDrive\Documentos\reactphp-windows\vendor\react\stream\src\ReadableResourceStream.php on line 58

RuntimeException: Unable to set stream resource to non-blocking mode in C:\Users\carlo\OneDrive\Documentos\reactphp-windows\vendor\react\stream\src\ReadableResourceStream.php on line 58

Call Stack:
    0.0002     393608   1. {main}() C:\Users\carlo\OneDrive\Documentos\reactphp-windows\index.php:0
    0.0046     612240   2. React\Stream\ReadableResourceStream->__construct($stream = resource(17) of type (stream), $loop = class React\EventLoop\StreamSelectLoop { private $futureTickQueue = class React\EventLoop\Tick\FutureTickQueue { private $queue = class SplQueue { ... } }; private $timers = class React\EventLoop\Timer\Timers { private $time = NULL; private $timers = [...]; private $schedule = [...]; private $sorted = TRUE; private $useHighResolution = TRUE }; private $readStreams = []; private $readListeners = []; private $writeStreams = []; private $writeListeners = []; private $running = NULL; private $pcntl = FALSE; private $pcntlPoll = FALSE; private $signals = class React\EventLoop\SignalsHandler { private $signals = [...] } }, $readChunkSize = ???) C:\Users\carlo\OneDrive\Documentos\reactphp-windows\index.php:11

System info:

SimonFrings commented 2 years ago

Hey @CViniciusSDias, thanks for all the input :+1:

When it comes to working with the filesystem it gets a bit tricky. The problem is that the filesystem is inherently blocking, so we have no choice to be blocking as well (fopen() is also blocking).

It is described inside the documentation that when you try to give something blocking into the ReadableResourceStream class, it tries to enable non-blocking mode on the stream resource which is not supported under Windows and will throw a RuntimeException.

As you can see we're aware of this behavior. If you want, you can get rid of the RuntimeException inside your project, but we can't do that inside our reactphp/stream component. You can also try the same under another operating system or take a look a the reactphp/filesystem (still experimental).

Maybe a non async approach is the way to go here, even if it's blocking, in most cases it might be fast enough.

I hope this helps.

CViniciusSDias commented 2 years ago

The documentation states that

this is not supported by pipes on Windows (STDIN etc.)

But what I am trying to open is not a pipe. It's a regular file. Is that also not supported?

SimonFrings commented 2 years ago

Beware not to take this sentence out of context. The full section of the documentation states:

Internally, this class tries to enable non-blocking mode on the stream resource which may not be supported for all stream resources. Most notably, this is not supported by pipes on Windows (STDIN etc.). If this fails, it will throw a RuntimeException:

We know this is not supported by pipes on Windows and your use case doesn't appear to be supported either. When it comes to working with the filesystem in combination with streams, the documentation also says this inside the usage chapter:

Note that this example uses fopen() for illustration purposes only. This should not be used in a truly async program because the filesystem is inherently blocking and each call could potentially take several seconds. See also creating streams for more sophisticated examples.

I hope this clears things up 👍

CViniciusSDias commented 2 years ago

@SimonFrings , actually that was not very clear but while I was writing an example of non-blocking code that runs on Windows I saw the note on PHP's documentation:

On Windows, this has no affect on local files. Non-blocking IO for local files is not supported on Windows.

So yes, now I understand the behavior. Thank you for replying. :-D

clue commented 2 years ago

I believe this has been answered, so I'm closing this for now. Please come back with more details if this problem persists and we can always reopen this :+1: