MCPcopy Create free account
hub / github.com/EvoMap/evolver / _scheduleOutbound

Method _scheduleOutbound

src/proxy/sync/engine.js:66–123  ·  view source on GitHub ↗
(delayMs)

Source from the content-addressed store, hash-verified

64 }
65
66 _scheduleOutbound(delayMs) {
67 if (!this._running) return;
68 this._outTimer = setTimeout(async () => {
69 // Defence-in-depth: a throw from this.outbound.flush(),
70 // this.store.countPending(), or any post-flush bookkeeping used
71 // to escape the setTimeout callback. Node logs the unhandled
72 // rejection and the next setTimeout was never armed — the
73 // outbound sync loop silently died until the process restarted,
74 // while `_running` stayed true (no signal to the caller).
75 //
76 // Mirrors the heartbeat-loop fix in PR #147 (issue #544): wrap
77 // the whole tick, schedule the next iteration in `finally` so a
78 // surprise throw cannot park the loop.
79 let nextDelay = DEFAULT_OUTBOUND_INTERVAL;
80 let hubRetryAfterMs = 0;
81 try {
82 if (!this._running) return;
83 this._outPending = true;
84 try {
85 const result = await this.outbound.flush();
86 if (result.sent > 0) this._lastActivity = Date.now();
87 if (result.retryAfterMs > 0) hubRetryAfterMs = result.retryAfterMs;
88 if ((result.sent > 0 || result.dropped > 0) && typeof this.onOutboundFlushed === 'function') {
89 try { this.onOutboundFlushed(result); } catch (e) {
90 this.logger.warn?.('[sync] onOutboundFlushed callback failed:', e.message);
91 }
92 }
93 } catch (err) {
94 if (err instanceof AuthError) {
95 await this._handleAuthError('outbound');
96 } else {
97 this.logger.error(`[sync] outbound error: ${err.message}`);
98 }
99 }
100 this._outPending = false;
101 if (hubRetryAfterMs > 0) {
102 nextDelay = Math.max(1_000, hubRetryAfterMs);
103 } else {
104 try {
105 const pending = this.store.countPending({ direction: 'outbound' });
106 if (pending > 0) nextDelay = 1_000;
107 } catch (err) {
108 // countPending threw (corrupt store, FS hiccup): keep the
109 // default cadence rather than parking the loop.
110 this.logger.error(`[sync] countPending threw (non-fatal): ${err && err.message}`);
111 }
112 }
113 } catch (err) {
114 // Anything that escaped the inner blocks above. Log and let
115 // finally re-arm the timer.
116 this.logger.error(`[sync] outbound tick threw (non-fatal): ${err && err.message}`);
117 this._outPending = false;
118 } finally {
119 if (this._running) this._scheduleOutbound(nextDelay);
120 }
121 }, delayMs);
122 if (this._outTimer.unref) this._outTimer.unref();
123 }

Callers 3

startMethod · 0.95
notifyNewOutboundMethod · 0.95

Calls 3

_handleAuthErrorMethod · 0.95
flushMethod · 0.80
countPendingMethod · 0.80

Tested by

no test coverage detected