Hi all
I have a problem with a website which uses Server-Sent Events where the long
lived connection for the Server Events seems to be blocking other resources
from loading on iOS clients only and only when I have haproxy between client
and server.
This is my test case.
* Create a node express app which serves a html page which subscribes to an
EventSource and asynchronously adds 200 300x100px images to the DOM
* Node app is configured to serve resources with 500ms delay to reliably
reproduce the problem
* Configure basic haproxy between node app and client
* Reset cache on iOS device and connect to server
Expected result
* Client open 5 simultaneous http connections to the server
* 1 connection is blocked listening for events from the EventSource
* The remaining 4 connections are used to download the 200 images
Actual Result
* Connection to EventSource is established and events start to be logged to
the console
* Images start to download on the page
* Several of the images get blocked and never load
Clearing the device cache and connecting directly to the server, all resources
load, although the loading pattern of images is significantly different.
If anyone has any ideas I would greatly appreciate any suggestions??
Sources and config included below.
* index.html
<html>
<head>
<style>
img {
width: 30px;
height: 10px;
border-style: solid;
border-color: black;
border-width: 1px;
}
</style>
</head>
<body>
<script type="text/javascript">
var source = new EventSource('/events');
source.onmessage = function(e) {
console.log(e.data);
}
var body = document.querySelectorAll('body');
var createImage = function(i) {
var element = document.createElement('img');
element.src = '/' + i + '.png';
body[0].appendChild(element);
}
window.setTimeout(function() {
for (var i = 1; i < 200; i++) {
createImage(i);
}
}, 1000);
</script>
</body>
</html>
* app.js
var express = require('express');
var app = express();
app.get('/events', function(req, res) {
// let request last as long as possible
req.socket.setTimeout(Infinity);
var messageCount = 0;
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive'
});
res.write('\n');
var timeout;
var emitEvent = function() {
res.write('id:' + ++messageCount + '\n');
res.write('data:' + new Date().getTime() + '\n\n');
timeout = setTimeout(emitEvent, 3000);
}
req.on("close", function() {
clearTimeout(timeout);
});
emitEvent();
});
var staticHandler = express.static(__dirname + '/public');
app.use(function serveStatic(req, res, next) {
setTimeout(function() {
staticHandler(req, res, next);
}, 500);
});
var server = app.listen(3000, function() {
console.log('Listening on port %d', server.address().port);
});
* haproxy config
global
daemon
quiet
maxconn 1024
pidfile haproxy.pid
log 127.0.0.1 local0
log 127.0.0.1 local1 notice
defaults
log global
balance roundrobin
mode http
frontend external
bind :80
default_backend test
backend test
server test localhost:3000