From f6fa9665422694d950fd549fe8f92c2566d95658 Mon Sep 17 00:00:00 2001 From: Peyton Morrison Date: Sat, 19 Apr 2025 16:39:17 -0400 Subject: [PATCH] fix longpoll not respecting longPollFallbackMs Signed-off-by: Peyton Morrison --- assets/js/phoenix/socket.js | 14 +++++++++----- assets/test/socket_test.js | 16 +++++++++++----- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/assets/js/phoenix/socket.js b/assets/js/phoenix/socket.js index a92452196e..b08a7b6421 100644 --- a/assets/js/phoenix/socket.js +++ b/assets/js/phoenix/socket.js @@ -121,6 +121,7 @@ export default class Socket { this.primaryPassedHealthCheck = false this.longPollFallbackMs = opts.longPollFallbackMs this.fallbackTimer = null + this.fallbackScheduled = false this.sessionStore = opts.sessionStorage || (global && global.sessionStorage) this.establishedConnections = 0 this.defaultEncoder = Serializer.encode.bind(Serializer) @@ -197,6 +198,7 @@ export default class Socket { replaceTransport(newTransport){ this.connectClock++ this.closeWasClean = true + this.fallbackScheduled = false clearTimeout(this.fallbackTimer) this.reconnectTimer.reset() if(this.conn){ @@ -240,6 +242,7 @@ export default class Socket { this.connectClock++ this.disconnecting = true this.closeWasClean = true + this.fallbackScheduled = false clearTimeout(this.fallbackTimer) this.reconnectTimer.reset() this.teardown(() => { @@ -384,16 +387,15 @@ export default class Socket { primaryTransport = false this.replaceTransport(fallbackTransport) this.transportConnect() + this.fallbackScheduled = false } if(this.getSession(`phx:fallback:${fallbackTransport.name}`)){ return fallback("memorized") } - this.fallbackTimer = setTimeout(fallback, fallbackThreshold) - errorRef = this.onError(reason => { this.log("transport", "error", reason) - if(primaryTransport && !established){ - clearTimeout(this.fallbackTimer) - fallback(reason) + if(this.transport === WebSocket && !established && !this.fallbackScheduled){ + this.fallbackScheduled = true + this.fallbackTimer = setTimeout(fallback, fallbackThreshold) } }) this.onOpen(() => { @@ -405,10 +407,12 @@ export default class Socket { } // if we've established primary, give the fallback a new period to attempt ping clearTimeout(this.fallbackTimer) + this.fallbackScheduled = true this.fallbackTimer = setTimeout(fallback, fallbackThreshold) this.ping(rtt => { this.log("transport", "connected to primary after", rtt) this.primaryPassedHealthCheck = true + this.fallbackScheduled = false clearTimeout(this.fallbackTimer) }) }) diff --git a/assets/test/socket_test.js b/assets/test/socket_test.js index ebbe958df6..ff794044c9 100644 --- a/assets/test/socket_test.js +++ b/assets/test/socket_test.js @@ -12,7 +12,7 @@ describe("with transports", function (){ const mockSend = jest.fn() const mockAbort = jest.fn() const mockSetRequestHeader = jest.fn() - + global.XMLHttpRequest = jest.fn(() => ({ open: mockOpen, send: mockSend, @@ -92,10 +92,16 @@ describe("with transports", function (){ mockServer.stop(() => { expect(socket.transport).toBe(WebSocket) socket.onError((_reason) => { - setTimeout(() => { - expect(replaceSpy).toHaveBeenCalledWith(LongPoll) - done() - }, 100) + let startTime = Date.now() + const interval = setInterval(() => { + if (socket.transport === LongPoll) { + expect(replaceSpy).toHaveBeenCalledWith(LongPoll) + const elapsed = Date.now() - startTime + clearInterval(interval) + expect(elapsed).toBeGreaterThan(19) + done() + } + }, 5) }) socket.connect() })