as the title says, I found a rather strange behaviour in my application. It seems like the browsers pause the EventSource
for about 4-5 seconds. The delay does not seem to come from my backend PHP script.
Detailed description
I am using the JavaScript EventSource
to be able to show a download progress of one specific ZIP file (about 60MB of downloadable size). After that ZIP is downloaded, it gets extracted. Also, the user gets current informations on which shell command is executed at the moment so the user always knows what the backend is doing. To start the process, the user can click a button, which triggers the following js-function (basically just calls download_update.php
and registers several event listeners for my EventSource
object):
startUpdate() {
this.updateRunning = true;
const eventSource = new EventSource(`download_update.php?jwt=${this.authUser.jwt}`);
eventSource.addEventListener('downloadProgress', (event) => {
const socketPayload = JSON.parse(event.data);
this.loadingPercent = socketPayload.percentage; // progress visible in loading circle
});
eventSource.addEventListener('updateError', (event) => {
eventSource.close(); // make sure event source is closed to prevent restarting update process every few seconds
this.updateRunning = false;
this.loadingStatus = 'error';
const errorPayload = JSON.parse(event.data);
this.updateErrors.push(errorPayload.message);
});
eventSource.addEventListener('updateProgress', (event) => {
this.updateProgressLogs.push(JSON.parse(event.data).log); // show specific update step
});
eventSource.addEventListener('updateFinished', () => {
eventSource.close();
this.updateRunning = false;
this.loadingStatus = 'successful';
});
},
I'm firing the Server Sent Events with the following PHP function
inside the called download_update.php
:
function fireEvent($name, $payload)
{
$payload['time'] = date('H:i:s'); // pass server time to compare with browser time
echo "retry: 1000\n"; // seems to have no impact on the delay
echo "event: $name\n";
echo 'data: ' . json_encode($payload);
echo "\n\n";
if (ob_get_contents()) {
ob_flush(); // took these two function calls as a suggestion from another post on SO
flush();
}
}
This PHP function is triggered inside the callback function which I passed to the CURL request:
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'downloadProgress'); // callback function 'downloadProgress' fires 'fireEvent' and passes the current downloadProgress in %
The script download_update.php
is only called once, which is the desired bevaviour (I've checked that in my Chrome Network tab).
But when I take a closer look at the results inside the Network tab of download_update.php
, I get the following:
As you can see in my screenshot, there is a sudden unexpected browser delay of about 6 seconds between the result I have highlighted and the previous one. The EventStream
clearly says {"percentage":91,"time":"16:46:47"}
(passed through backend PHP), but the browser is showing 16:46:52.319
as the time.
My page has HTTPS and is hosted on a local .test
domain (localhost).
- PHP Version 7.4.21
- Webserver:
nginx
version1.21.1
(used viaLaravel Valet 2.18.10
) - Tested on browsers:
Chrome 100.0.4896.75
,Firefox 99.0
,Safari 15.4
- Used hardware: MacBook Pro (16" 2021 M1), macOS Monterey Version 12.3.1
This behaviour occurs on all of the 3 browsers listed above, which leads me into thinking that the webserver nginx
might be the issue here. I've found a pretty interesting question regarding EventSource
and nginx
: EventSource / Server-Sent Events through Nginx
The accepted answer suggests putting the following lines into one of the nginx config files (location
section):
proxy_set_header Connection '';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
So I put those inside /usr/local/etc/nginx/valet/valet.conf
and restarted my webserver several times, without success.
Does anybody have any suggestions on how I can fix that delay?
Thank you very much in advance everyone.