Skip to content

fix(arkade): dispose unused ContractWatcher to stop log flood#3932

Merged
TaprootFreak merged 1 commit into
developfrom
fix/arkade-dispose-unused-watcher
Jun 18, 2026
Merged

fix(arkade): dispose unused ContractWatcher to stop log flood#3932
TaprootFreak merged 1 commit into
developfrom
fix/arkade-dispose-unused-watcher

Conversation

@Danswar

@Danswar Danswar commented Jun 18, 2026

Copy link
Copy Markdown
Collaborator

Problem

dfx-api logs are flooded by the Arkade integration on both dev and prod (~1.6k errors/hr combined), in two forms:

  • Subscription error: ReferenceError: EventSource is not defined
  • ContractWatcher connection failed: ... {"code":13,"message":"subscription not found: <uuid>"}

Wallet.create (@arkade-os/sdk) starts a background ContractWatcher that streams live VTXO/contract events over SSE. ArkadeClient never uses those events — it polls for state (getTransactionfinalizePendingTxs/getVtxos). So the watcher is pure dead weight, and it's broken in our runtime:

  • Our image is Node 20 (node:20-alpine), which has no global EventSource (added in Node 22) → the SSE listen loop throws ReferenceError.
  • The SDK's resubscribe path (0.4.36) reuses a stale subscription id and its stale-detection regex (/subscription\s+\S+\s+not\s+found/i) doesn't match the server's subscription not found: <id> message → it loops forever on the dead id.

Net effect is log noise only — no broken functionality, since ArkadeClient doesn't consume watcher events — but it drowns the logs and masks real errors.

Fix

Stop the watcher right after wallet creation via the SDK's public ContractManager.dispose(). Disposal sets isWatching=false, so connect()/scheduleReconnect() short-circuit and the loop ends. It's wrapped best-effort (never fatal) so a transient indexer hiccup can't break wallet init.

All wallet operations ArkadeClient actually uses — getAddress, getBalance, getVtxos, sendBitcoin, finalizePendingTxs — are unaffected (dispose() only stops the live SSE watch, not the manager's data access).

Test

  • arkade-client.spec.ts + arkade.service.spec.ts: 30/30 pass (mocks updated with getContractManager).
  • nest build (tsc) green against @arkade-os/sdk@0.4.36; eslint + prettier clean.

Verify after merge

On dfxdev/dfxprd dfx-api: EventSource is not defined and subscription not found drain to ~0.

ArkadeClient polls for state (getTransaction/getVtxos) and never consumes
the SDK's live contract events, but Wallet.create starts a background
ContractWatcher anyway. On our Node 20 runtime the watcher has no global
EventSource and the SDK's resubscribe path loops on a stale subscription id,
flooding dfx-api logs on dev and prod (~1.6k errors/hr combined) with
"EventSource is not defined" and "subscription not found".

Stop the watcher right after wallet creation via the public
ContractManager.dispose(). Best-effort and non-fatal — all wallet
operations dfx-api actually uses (send/balance/vtxo/status) are unaffected.
@Danswar Danswar force-pushed the fix/arkade-dispose-unused-watcher branch from 8112561 to ecbc249 Compare June 18, 2026 12:54
@TaprootFreak TaprootFreak merged commit f14a97a into develop Jun 18, 2026
7 checks passed
@TaprootFreak TaprootFreak deleted the fix/arkade-dispose-unused-watcher branch June 18, 2026 13:17
TaprootFreak added a commit that referenced this pull request Jun 18, 2026
…e + Log-Flut) (#3935)

* fix(arkade): EventSource-Polyfill für Node-Runtime

Das @arkade-os/sdk öffnet seine Settlement- (Batch-) und Contract-Event-Streams
über ein globales EventSource. Node liefert EventSource nur hinter dem Flag
--experimental-eventsource, daher warf jeder Stream auf unserer Runtime
ReferenceError: EventSource is not defined.

Folgen auf PRD: der periodische VTXO-Settle (alle ~5 Min) schlug hart fehl
(Boarding-UTXOs wurden nicht eingebucht, ablaufende VTXOs nicht erneuert) und
flutete die Logs; zusätzlich der ContractWatcher-Boot-Fehler.

Fix: WHATWG-konformes eventsource@4 als globalen Polyfill in einem polyfills.ts
registrieren, das in main.ts als Erstes importiert wird (vor jedem SDK-Code).
Behebt beide Fehlerquellen an der Wurzel, ohne Node-Upgrade oder experimentelle
Flags. Der ContractWatcher-Dispose (#3932) bleibt korrekt, da der Watcher
ungenutzt ist.

* test(arkade): sichere EventSource-Polyfill-Registrierung ab

Fängt einen stillen Regress ab: ändert ein künftiger eventsource-Major die
Export-Form, würde der Polyfill undefined registrieren und die SDK-Streams
wieder werfen, ohne dass es jemand bemerkt.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants