TL;DR update: Whether closing an EventSource from the client or closing the client entirely, php continues to execute on the backend and fails to report the correct value for connection_aborted()
. Why might this be?
I have been all over Google and Stack Overflow looking for answers to this, but none of the suggested fixes resolve the issue: I have a simple page testing the functionality of server-sent events using JavaScript and php. Everything was working well until I realized that server script execution did not stop when a client navigated to another page or refreshed itself. This appears to be a common problem and the suggestions given in other questions have borne no fruit for me.
StackOverflow questions I've already investigated
PHP Event Source keeps executing (the comments on the accepted answer here almost led to something and then they pulled out to "continue this discussion in chat" and that link is apparently broken)
How do I put this on Real-Time? I already put (async: True) but it doesnt work
Linked articles & other material I've already investigated
I have stripped the code of everything that I thought could be a possible culprit and I'm still having the issue. I am especially surprised that connection_aborted
continues to report false
after the explicit EventSource.close()
call in the client or simply closing the client before the 10 second server loop has finished. Here is my exact code, after stripping out everything but the server-sent event stuff:
sse_tests.js
document.addEventListener('DOMContentLoaded', () => {
// Set up EventSource for receiving server-sent events.
const testEventSource = new EventSource('sse_tests.php');
testEventSource.addEventListener('test', (e) => {
const data = JSON.parse(e.data);
console.log(`count: ${data.count}`);
if (data.count >= 5) {
testEventSource.close();
}
});
});
sse_tests.php
<?php
// Set the event stream header(s).
header("Cache-Control: no-cache");
header("Content-Type: text/event-stream");
// XXX Override automatic detection of client abortion; we'll do it ourselves.
// (This was suggested in another answer, and I have the same issue with or without it)
ignore_user_abort(true);
// Initialize an arbitrary count parameter to investigate client communication.
$count = 1;
while ($count <= 10) {
$eventData = json_encode(array(
"count" => $count,
));
echo "event: test\n";
echo "data: ${eventData}";
echo "\n\n";
ob_flush();
flush();
$aborted = connection_aborted();
error_log("count: ${count}, connection_aborted: ${aborted}");
if ($aborted) {
break;
}
$count++;
sleep(1);
}
The client successfully opens the connection, tracks it for 5 emissions of the test
event and then stops seeing any further emissions of the test
event, but the server continues to execute for the full count of 10, even after the testEventSource.close()
call or a closing of the browser window before the full count of 10, as evidenced by the server log contents here:
count: 1, connection_aborted: 0
count: 2, connection_aborted: 0
count: 3, connection_aborted: 0
count: 4, connection_aborted: 0
count: 5, connection_aborted: 0
count: 6, connection_aborted: 0
count: 7, connection_aborted: 0
count: 8, connection_aborted: 0
count: 9, connection_aborted: 0
count: 10, connection_aborted: 0
I'm on shared hosting with php 7.2 and minimal tweaks to server configuration. Let me know if that could be the source of strife, and I'll try to investigate more of the default configurations and share whatever else is needed.
connection_status()
? – Warwickshireoutput_buffering = 0 implicit_flush = 1
– WarwickshirePHP Notice: ob_flush(): failed to flush buffer. No buffer to flush in /home/brijtpxm/dev_includes/cody/controllers/sse_tests.php on line 25
. Line 25 is the call to ob_flush – Exteriorize