The AISStream WebSocket error handler in server/utils/trackingFeed.js logs errors but never triggers a reconnect. Once the AIS socket hits an error (DNS failure, TCP reset, etc.), it stays in a broken state and will never recover without a server restart.
Problem
In server/utils/trackingFeed.js, the connectAisStream() function registers four event handlers on the AIS WebSocket: open, message, close, and error. The close handler calls scheduleAisReconnect(), but the error handler (line 218) only logs the error:
When an error occurs, the WebSocket enters a broken state. The close event may or may not fire depending on how the error occurred. Meanwhile, refreshFeedBboxes() checks state.aisSocket?.readyState === WebSocket.OPEN and falls through to else if (!state.aisSocket). Since state.aisSocket still references the broken socket object (it is truthy), neither branch reconnects it.
Result: any AIS stream error permanently disables AIS tracking until process restart.
Proposed work
Add a call to scheduleAisReconnect() inside the ws.on('error') handler in server/utils/trackingFeed.js. The existing guard (state.stopped) and closeAisSocket() cleanup are already handled by scheduleAisReconnect(), so a single line addition is sufficient:
The ws.on('error') handler in server/utils/trackingFeed.js calls scheduleAisReconnect() when the socket is not stopped.
After an AIS WebSocket error, the next refreshFeedBboxes() call or the scheduled reconnect timer initiates a new connection attempt with exponential backoff.
Existing tests in test/unit/trackingFeed.spec.js (if any) still pass after the change.
## Summary
The AISStream WebSocket error handler in `server/utils/trackingFeed.js` logs errors but never triggers a reconnect. Once the AIS socket hits an error (DNS failure, TCP reset, etc.), it stays in a broken state and will never recover without a server restart.
## Problem
In `server/utils/trackingFeed.js`, the `connectAisStream()` function registers four event handlers on the AIS WebSocket: `open`, `message`, `close`, and `error`. The `close` handler calls `scheduleAisReconnect()`, but the `error` handler (line 218) only logs the error:
```js
ws.on('error', (err) => {
console.error('[trackingFeed] AISStream error:', err?.message)
})
```
When an error occurs, the WebSocket enters a broken state. The `close` event may or may not fire depending on how the error occurred. Meanwhile, `refreshFeedBboxes()` checks `state.aisSocket?.readyState === WebSocket.OPEN` and falls through to `else if (!state.aisSocket)`. Since `state.aisSocket` still references the broken socket object (it is truthy), neither branch reconnects it.
Result: any AIS stream error permanently disables AIS tracking until process restart.
## Proposed work
Add a call to `scheduleAisReconnect()` inside the `ws.on('error')` handler in `server/utils/trackingFeed.js`. The existing guard (`state.stopped`) and `closeAisSocket()` cleanup are already handled by `scheduleAisReconnect()`, so a single line addition is sufficient:
```js
ws.on('error', (err) => {
console.error('[trackingFeed] AISStream error:', err?.message)
if (!state.stopped) scheduleAisReconnect()
})
```
## Acceptance criteria
- [ ] The `ws.on('error')` handler in `server/utils/trackingFeed.js` calls `scheduleAisReconnect()` when the socket is not stopped.
- [ ] After an AIS WebSocket error, the next `refreshFeedBboxes()` call or the scheduled reconnect timer initiates a new connection attempt with exponential backoff.
- [ ] Existing tests in `test/unit/trackingFeed.spec.js` (if any) still pass after the change.
<!-- jasper-fp:13d3f83bd7cd388c -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
The AISStream WebSocket error handler in
server/utils/trackingFeed.jslogs errors but never triggers a reconnect. Once the AIS socket hits an error (DNS failure, TCP reset, etc.), it stays in a broken state and will never recover without a server restart.Problem
In
server/utils/trackingFeed.js, theconnectAisStream()function registers four event handlers on the AIS WebSocket:open,message,close, anderror. Theclosehandler callsscheduleAisReconnect(), but theerrorhandler (line 218) only logs the error:When an error occurs, the WebSocket enters a broken state. The
closeevent may or may not fire depending on how the error occurred. Meanwhile,refreshFeedBboxes()checksstate.aisSocket?.readyState === WebSocket.OPENand falls through toelse if (!state.aisSocket). Sincestate.aisSocketstill references the broken socket object (it is truthy), neither branch reconnects it.Result: any AIS stream error permanently disables AIS tracking until process restart.
Proposed work
Add a call to
scheduleAisReconnect()inside thews.on('error')handler inserver/utils/trackingFeed.js. The existing guard (state.stopped) andcloseAisSocket()cleanup are already handled byscheduleAisReconnect(), so a single line addition is sufficient:Acceptance criteria
ws.on('error')handler inserver/utils/trackingFeed.jscallsscheduleAisReconnect()when the socket is not stopped.refreshFeedBboxes()call or the scheduled reconnect timer initiates a new connection attempt with exponential backoff.test/unit/trackingFeed.spec.js(if any) still pass after the change.