Skip to content
Merged
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
7 changes: 2 additions & 5 deletions lib/web/eventsource/eventsource.js
Original file line number Diff line number Diff line change
Expand Up @@ -231,12 +231,9 @@ class EventSource extends EventTarget {

// 14. Let processEventSourceEndOfBody given response res be the following step: if res is not a network error, then reestablish the connection.
const processEventSourceEndOfBody = (response) => {
if (isNetworkError(response)) {
this.dispatchEvent(new Event('error'))
this.close()
if (!isNetworkError(response)) {
return this.#reconnect()
}

this.#reconnect()
}

// 15. Fetch request, with processResponseEndOfBody set to processEventSourceEndOfBody...
Expand Down
2 changes: 1 addition & 1 deletion lib/web/eventsource/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function isASCIINumber (value) {
// https://github.com/nodejs/undici/issues/2664
function delay (ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms).unref()
setTimeout(resolve, ms)
})
}

Expand Down
18 changes: 18 additions & 0 deletions test/eventsource/eventsource-connect.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const events = require('node:events')
const http = require('node:http')
const { test, describe } = require('node:test')
const { EventSource } = require('../../lib/web/eventsource/eventsource')
const { randomInt } = require('node:crypto')

describe('EventSource - sending correct request headers', () => {
test('should send request with connection keep-alive', async () => {
Expand Down Expand Up @@ -181,4 +182,21 @@ describe('EventSource - received response must have content-type to be text/even
server.close()
}
})

test('should try to connect again if server is unreachable', async () => {
const domain = 'bad.n' + randomInt(1e10).toString(36) + '.proxy'

const eventSourceInstance = new EventSource(`http://${domain}`)

const onerrorCalls = []
eventSourceInstance.onerror = (error) => {
onerrorCalls.push(error)
}

await new Promise(resolve => setTimeout(resolve, 8000))

eventSourceInstance.close()

assert.strictEqual(onerrorCalls.length, 3)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

3 errors?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, defaultReconnectTime is 3000. So 1. Is about after 50-100 ms, next is 3050-3100ms and the third is at 6050-6100ms. A fourth would be after 9050-9100 ms, but we just do 7000ms (or 8000?) and so we have only 3.

})
})
7 changes: 5 additions & 2 deletions test/node-platform-objects.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,19 @@ test('unserializable web instances should be uncloneable if node exposes the api
{ Uncloneable: MessageEvent, value: 'dummy event', brand: 'MessageEvent' },
{ Uncloneable: CloseEvent, value: 'dummy event', brand: 'CloseEvent' },
{ Uncloneable: ErrorEvent, value: 'dummy event', brand: 'ErrorEvent' },
{ Uncloneable: EventSource, value: 'http://localhost', brand: 'EventSource' },
{ Uncloneable: EventSource, value: 'http://localhost', brand: 'EventSource', doneCb: (entity) => entity.close() },
{ Uncloneable: Headers, brand: 'Headers' },
{ Uncloneable: WebSocket, value: 'http://localhost', brand: 'WebSocket' },
{ Uncloneable: Cache, value: kConstruct, brand: 'Cache' },
{ Uncloneable: CacheStorage, value: kConstruct, brand: 'CacheStorage' }
]
uncloneables.forEach((platformEntity) => {
t.throws(() => structuredClone(new platformEntity.Uncloneable(platformEntity.value)),
const entity = new platformEntity.Uncloneable(platformEntity.value)
t.throws(() => structuredClone(entity),
DOMException,
`Cloning ${platformEntity.brand} should throw DOMException`)

platformEntity.doneCb?.(entity)
})
}
})
Loading