Event data loss during provider reconnection in web3.eth.Contract.subscribe
0 reputation · 22 Aug 2020, 18:18 UTC
0 reputation · 22 Aug 2020, 18:18 UTC
When using web3.eth.Contract.subscribe with a filter object, the library relies on the underlying WebSocket connection. While filters successfully offload event matching to the node to reduce noise, a significant functional gap exists when the provider disconnects and reconnects.
Once the connection is re-established, the subscription is typically reactivated, but events emitted during the downtime are not retrieved. There is no built-in state-sync mechanism or block-range tracking to catch up on missed logs between the last received block and the reconnection point.
Does web3.js provide a native way to recover missed events after a subscription gap? What is the recommended pattern for implementing a state-sync without manually polling logs for every event type?
32275 reputation · 22 Aug 2020, 22:40 UTC
web3.js does not provide a native mechanism to retrieve events that were emitted while the underlying provider was disconnected. When a web3.eth.Contract.subscribe subscription is created, it is bound to the provider instance at that moment; a provider reconnection does not transfer or resume the subscription, so any logs emitted during the downtime are lost.
Contract.subscribe is tied to the provider instance used at creation time (web3.js v1.x behavior).connect, end, or error events (e.g., via provider.on('connect', ...) and provider.on('end', ...)).await subscription.unsubscribe().connect event (or you confirm it is ready), create a fresh subscription with the same filter: const newSub = myContract.events.MyEvent({filter}, callback).new WebSocket(url, { reconnect: { auto: true, maxAttempts: Infinity } })) so that the connect/end events fire reliably.// 1. Log subscription ID before disconnect
console.log('sub id:', subscription.id);
// 2. Simulate provider disconnect (close WS or stop node)
// 3. Observe that no further events arrive
// 4. Reconnect provider, wait for 'connect' event
// 5. Unsubscribe old sub and create new one
await subscription.unsubscribe();
const newSub = myContract.events.MyEvent({filter}, handler);
console.log('new sub id:', newSub.id); // should differ
// 6. Confirm events resume after reconnection and none appear in the gap
If your WebSocket provider library already exposes an automatic reconnection option that transparently restores the underlying socket without emitting disconnect/reconnect events, the manual unsubscribe/resubscribe step may be unnecessary. Please confirm whether your provider’s constructor or options include a reconnect flag that guarantees the same socket instance is reused after a network interruption.
Use comments to ask for clarification. Post a solution as an answer.
32,275 reputation · 22 Aug 2020, 19:10 UTC
To build on the recommended reconnection pattern, it is important to clarify that simply resubscribing only prevents future data loss. To resolve the gap created during downtime, you must implement a manual catch-up mechanism using web3.eth.getPastEvents (or eth_getLogs).
The most reliable approach is to persist the block number of the last processed event. Upon detecting a reconnection, perform the following sequence before resuming the live subscription:
getPastEvents using fromBlock: lastProcessedBlock + 1 and toBlock: currentBlock.Note on Node Constraints: Be aware that pruned nodes may not retain logs for long gaps. If your application requires high reliability over extended outages, ensure you are connected to an archive node or a node with a high log retention limit.