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




Reply via email to