-
-
Notifications
You must be signed in to change notification settings - Fork 63
Emit error event and close Stream when writing to stream resource fails #25
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Excellent troubleshooting @lysenkobv! I agree with you it doesn't look like a good resolution but PHP socket error handling probably doesn't allow something more elegant. Are you able to provide a unit test proving and fixing this or steps to reproduce so we can see/test this manually? |
Impressive find 👍 , it isn't not neat but it's the best we can get, LGTM 👍 |
Just testing to see if the above PR fixes out 100% CPU issues!
I wrote a test and found that BufferTest::testWritingToClosedStream() have the same logic I wrote. When if ($this->lastError['number'] > 0) { In this case, that part of code is not needed anymore: if (0 === $sent && feof($this->stream)) {
$this->emit('error', array(new \RuntimeException('Tried to write to closed stream.'), $this));
return;
} ...because in test To be sure I replaced part of code I mentioned above by checking if ($sent === false) {
$this->emit('error', array(new \RuntimeException('Send failed'), $this));
return;
} In conclusion error checking looks like that: if ($this->lastError['number'] > 0) {
$this->emit('error', array(
new \ErrorException(
$this->lastError['message'],
0,
$this->lastError['number'],
$this->lastError['file'],
$this->lastError['line']
),
$this
));
return;
}
if ($sent === false) {
$this->emit('error', array(new \RuntimeException('Send failed'), $this));
return;
} and $this->assertSame('fwrite(): send of 3 bytes failed with errno=32 Broken pipe', $error->getMessage()); All 66 tests have executed successfully. |
Is anybody here? 😄 |
👍 Again, just awesome work on this @lysenkobv! I'm very weary about changing the buffer code because of stupid strange edge cases that still haunt me to this day, but after much deliberation and testing am comfortable with this change. :-) |
if (0 === $sent && feof($this->stream)) { | ||
$this->emit('error', array(new \RuntimeException('Tried to write to closed stream.'), $this)); | ||
|
||
if ($sent === false) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately this change is known to cause issues with running the Autobahn testsuite against Ratchet. Thanks to @cboden for digging into this!
I'm currently looking into providing a test case so that this is properly covered in the Stream component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It ended up being line 90. The error I'm receiving is:
fwrite(): send of 8192 bytes failed with errno=11 Resource temporarily unavailable
On attempting to send a large amount of data (256k) to fwrite. The error simply states the buffer is full and to try again later, however the updated code now halts on all errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will be fixed via #52.
Hi.
I have Ratchet working 24/7 and sometimes it starting to use 100% of CPU. In this case I need to restart it and this helps. But it happend very often, so I debug it and found that
foef($this->stream)
do not returntrue
when client disconnects while event loop tick is not ended.Same with
is_resource($this->stream)
it returnstrue
.I'm using:
In this case after
$this->lastError['message']
contains an error:There is no way to catch such behavior using best practices, so I decide to check
$this->lastError['message']
on 'errno=10054'.Maybe it will be more efficient if we will check
$this->lastError['number']
on any error> 0
. But to prevent just on this case I decide to check only errno=10054 in message.I know this is not good resolution but it works.