From c8c40726faf00212be22e4a91558df601d7ce9f7 Mon Sep 17 00:00:00 2001 From: "Samuel EF. Tinnerholm" Date: Sun, 24 May 2026 19:47:48 +0300 Subject: [PATCH] fix: add 30s connection timeout to Chainlink and Binance feed WebSockets Fixes #252 Fixes #253 --- core/src/feeds/binance/binance-feed.ts | 10 ++++++++++ core/src/feeds/chainlink/chainlink-feed.ts | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/core/src/feeds/binance/binance-feed.ts b/core/src/feeds/binance/binance-feed.ts index 187d1820..5385f138 100644 --- a/core/src/feeds/binance/binance-feed.ts +++ b/core/src/feeds/binance/binance-feed.ts @@ -152,7 +152,15 @@ export class BinanceFeed extends BaseDataFeed { const ws = new WebSocket(url); + const connectionTimeout = setTimeout(() => { + ws.close(); + this.ws = null; + this.connectionPromise = null; + reject(new Error('BinanceFeed: WebSocket connection timed out (30s)')); + }, 30_000); + ws.on('open', () => { + clearTimeout(connectionTimeout); this.ws = ws; this.connectionPromise = null; ws.send(JSON.stringify({ op: 'subscribe_all' })); @@ -164,6 +172,7 @@ export class BinanceFeed extends BaseDataFeed { }); ws.on('close', () => { + clearTimeout(connectionTimeout); this.ws = null; this.connectionPromise = null; if (!this.isTerminated) { @@ -172,6 +181,7 @@ export class BinanceFeed extends BaseDataFeed { }); ws.on('error', (err: Error) => { + clearTimeout(connectionTimeout); this.ws = null; this.connectionPromise = null; if (!this.isTerminated) { diff --git a/core/src/feeds/chainlink/chainlink-feed.ts b/core/src/feeds/chainlink/chainlink-feed.ts index f2c0b36d..761a4eaa 100644 --- a/core/src/feeds/chainlink/chainlink-feed.ts +++ b/core/src/feeds/chainlink/chainlink-feed.ts @@ -259,7 +259,15 @@ export class ChainlinkFeed extends BaseDataFeed { const url = `${this.wsUrl}?key=${this.wsApiKey}`; const ws = new WebSocket(url); + const connectionTimeout = setTimeout(() => { + ws.close(); + this.ws = null; + this.connectionPromise = null; + reject(new Error('ChainlinkFeed: WebSocket connection timed out (30s)')); + }, 30_000); + ws.on('open', () => { + clearTimeout(connectionTimeout); this.ws = ws; this.connectionPromise = null; ws.send(JSON.stringify({ op: 'subscribe_all' })); @@ -271,12 +279,14 @@ export class ChainlinkFeed extends BaseDataFeed { }); ws.on('close', () => { + clearTimeout(connectionTimeout); this.ws = null; this.connectionPromise = null; if (!this.isTerminated) this.scheduleReconnect(); }); ws.on('error', (err: Error) => { + clearTimeout(connectionTimeout); this.ws = null; this.connectionPromise = null; if (!this.isTerminated) this.scheduleReconnect();