Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions HISTORY.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# [1.1.0](https://github.com/dpatty/eventsource/compare/v1.0.8...v1.1.0)
* Allow configuring of the reconnection interval using an exponential backoff ([#126](https://github.com/EventSource/eventsource/pull/126) David Patty)

# [1.0.8](https://github.com/dpatty/eventsource/compare/v1.0.7...v1.0.8)
* Prevent simultaneous reconnection attempts on multiple errors ([#125](https://github.com/EventSource/eventsource/pull/125) David Patty)

# [1.0.7](https://github.com/EventSource/eventsource/compare/v1.0.6...v1.0.7)

* Add dispatchEvent to EventSource ([#101](https://github.com/EventSource/eventsource/pull/101) Ali Afroozeh)
Expand Down
33 changes: 32 additions & 1 deletion lib/eventsource.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function EventSource (url, eventSourceInitDict) {
})

var self = this
self.reconnectInterval = 1000
self.reconnectInterval = startingReconnectInterval
self.connectionInProgress = false

function onConnectionClosed (message) {
Expand All @@ -65,6 +65,13 @@ function EventSource (url, eventSourceInitDict) {
self.connectionInProgress = true
connect()
}, self.reconnectInterval)

increaseReconnectInterval()
}

function increaseReconnectInterval () {
self.reconnectInterval *= reconnectIntervalBackoffMultiple
self.reconnectInterval = Math.min(maxReconnectInterval, self.reconnectInterval)
}

var req
Expand Down Expand Up @@ -133,7 +140,9 @@ function EventSource (url, eventSourceInitDict) {
}

req = (isSecure ? https : http).request(options, function (res) {
// release the lock on making connections
self.connectionInProgress = false

// Handle HTTP errors
if (res.statusCode === 500 || res.statusCode === 502 || res.statusCode === 503 || res.statusCode === 504) {
_emit('error', new Event('error', {status: res.statusCode, message: res.statusMessage}))
Expand All @@ -160,6 +169,9 @@ function EventSource (url, eventSourceInitDict) {
}

readyState = EventSource.OPEN
// reset reconnect interval now that we've actually made a connection
self.reconnectInterval = startingReconnectInterval

res.on('close', function () {
res.removeAllListeners('close')
res.removeAllListeners('end')
Expand Down Expand Up @@ -351,6 +363,25 @@ EventSource.prototype.close = function () {
this._close()
}

// set defaults to 30s max, and exponentially back off @ 2^n
var startingReconnectInterval = 1000
var maxReconnectInterval = 1000 * 30
var reconnectIntervalBackoffMultiple = 2
// setMaxReconnectInterval allows consumers to configure the max reconnect interval, and the backoff
EventSource.prototype.setupReconnectInterval = function (starting, max, multiple) {
if (Number.isInteger(starting) && starting >= 0) {
startingReconnectInterval = starting
}
if (Number.isInteger(max) && max >= 0) {
maxReconnectInterval = max
}
if (Number.isFinite(multiple) && multiple > 0) {
reconnectIntervalBackoffMultiple = multiple
}

this.reconnectInterval = startingReconnectInterval
}

/**
* Emulates the W3C Browser based WebSocket interface using addEventListener.
*
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"name": "eventsource2",
"version": "1.0.8",
"description": "W3C compliant EventSource client for Node.js and browser (polyfill). Forked from http://github.com/EventSource/eventsource",
"version": "1.1.0",
"description": "W3C compliant EventSource client for Node.js and browser (polyfill) Forked from http://github.com/EventSource/eventsource",

"keywords": [
"eventsource",
"http",
Expand Down
73 changes: 62 additions & 11 deletions test/eventsource_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ describe('HTTPS Client Certificate Support', function () {
describe('Reconnection', function () {
it('is attempted when server is down', function (done) {
var es = new EventSource('http://localhost:' + _port)
es.reconnectInterval = 0
es.setupReconnectInterval(0)

es.onerror = function () {
es.onerror = null
Expand All @@ -669,7 +669,7 @@ describe('Reconnection', function () {

server.on('request', writeEvents(['data: hello\n\n']))
var es = new EventSource(server.url)
es.reconnectInterval = 0
es.setupReconnectInterval(0)

es.onmessage = function (m) {
assert.equal('hello', m.data)
Expand Down Expand Up @@ -701,7 +701,7 @@ describe('Reconnection', function () {
})

var es = new EventSource(server.url)
es.reconnectInterval = 0
es.setupReconnectInterval(0)

var errored = false

Expand Down Expand Up @@ -732,7 +732,7 @@ describe('Reconnection', function () {

server.on('request', writeEvents(['data: hello\n\n']))
var es = new EventSource(server.url)
es.reconnectInterval = 0
es.setupReconnectInterval(0)

es.onmessage = function (m) {
assert.equal('hello', m.data)
Expand Down Expand Up @@ -777,7 +777,7 @@ describe('Reconnection', function () {
})

var es = new EventSource(server.url)
es.reconnectInterval = 0
es.setupReconnectInterval(0)

es.onerror = function (e) {
assert.equal(e.status, 204)
Expand Down Expand Up @@ -814,7 +814,7 @@ describe('Reconnection', function () {
server.on('request', writeEvents(['id: 10\ndata: Hello\n\n']))

var es = new EventSource(server.url)
es.reconnectInterval = 0
es.setupReconnectInterval(0)

es.onmessage = function () {
server.close(function (err) {
Expand Down Expand Up @@ -854,7 +854,7 @@ describe('Reconnection', function () {
server.on('request', writeEvents(['data: Hello\n\n']))

var es = new EventSource(server.url)
es.reconnectInterval = 0
es.setupReconnectInterval(0)

es.onmessage = function () {
server.close(function (err) {
Expand Down Expand Up @@ -885,7 +885,7 @@ describe('Reconnection', function () {
var fn = writeEvents(events)
fn(req, res)
eventsSent++
// now cause a parse error!
// now cause a few errors
fn(req, res)
eventsSent++
} else {
Expand All @@ -897,13 +897,64 @@ describe('Reconnection', function () {

var es = new EventSource(server.url)
assert.equal(EventSource.CONNECTING, es.readyState)
es.reconnectInterval = 0
es.setupReconnectInterval(0)
es.onerror = function (err) {
console.log(err);
errorOccurred = !!(errorOccurred || err)
}
})
})

it('should allow configurability of reconnect interval', function (done) {
createServer(function (err, server) {
if (err) return done(err)

server.on('request', function (req, res) {
res.writeHead(500)
res.end()
})

var es = new EventSource(server.url)
es.setupReconnectInterval(5, 60, 1.5)
assert.equal(es.reconnectInterval, 5)

var errored = false
es.onerror = function () {
if (errored) return
errored = true
server.close(function (err) {
if (err) return done(err)
assert.equal(es.reconnectInterval, 5 * 1.5)
done()
})
}
})
})

it('attempts to reconnect should increase the reconnect interval exponentially', function (done) {
createServer(function (err, server) {
if (err) return done(err)
var eventsSent = 0
server.on('request', function (req, res) {
if (eventsSent === 0) {
res.writeHead(500)
res.end()
}
})

var es = new EventSource(server.url)
es.setupReconnectInterval(5, 25, 10)
var errored = false
es.onerror = function () {
if (errored) return
errored = true
server.close(function (err) {
if (err) return done(err)
assert.equal(es.reconnectInterval, 25)
done()
})
}
})
})
})

describe('readyState', function () {
Expand Down Expand Up @@ -946,7 +997,7 @@ describe('readyState', function () {

server.on('request', writeEvents([]))
var es = new EventSource(server.url)
es.reconnectInterval = 0
es.setupReconnectInterval(0)

es.onopen = function (m) {
server.close(function (err) {
Expand Down