@love-moon/conductor-sdk 0.2.31 → 0.2.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -47,6 +47,10 @@ export interface StopTaskEvent {
47
47
  requestId?: string;
48
48
  reason?: string;
49
49
  }
50
+ export interface FlushPendingUpstreamEventsOptions {
51
+ timeoutMs?: number;
52
+ retryIntervalMs?: number;
53
+ }
50
54
  export declare class ConductorClient {
51
55
  private readonly config;
52
56
  private readonly env;
@@ -68,6 +72,10 @@ export declare class ConductorClient {
68
72
  constructor(init: ConductorClientInit);
69
73
  static connect(options?: ConductorClientConnectOptions): Promise<ConductorClient>;
70
74
  close(): Promise<void>;
75
+ flushPendingUpstreamEvents(options?: FlushPendingUpstreamEventsOptions): Promise<{
76
+ flushed: boolean;
77
+ remaining: number;
78
+ }>;
71
79
  forceReconnect(reason?: string): Promise<void>;
72
80
  createTaskSession(payload: Record<string, any>): Promise<Record<string, any>>;
73
81
  sendMessage(taskId: string, content: string, metadata?: Record<string, any>): Promise<Record<string, any>>;
package/dist/client.js CHANGED
@@ -91,10 +91,30 @@ export class ConductorClient {
91
91
  if (this.closed) {
92
92
  return;
93
93
  }
94
- this.closed = true;
95
94
  this.clearDurableOutboxTimer();
95
+ await this.flushPendingUpstreamEvents({
96
+ timeoutMs: 2_000,
97
+ retryIntervalMs: 100,
98
+ });
99
+ this.closed = true;
96
100
  await this.wsClient.disconnect();
97
101
  }
102
+ async flushPendingUpstreamEvents(options = {}) {
103
+ const timeoutMs = Math.max(0, options.timeoutMs ?? 5_000);
104
+ const retryIntervalMs = Math.max(10, options.retryIntervalMs ?? 250);
105
+ const startedAt = Date.now();
106
+ while (true) {
107
+ await this.requestDurableOutboxFlush(true);
108
+ const remaining = this.upstreamOutbox.load().length;
109
+ if (remaining === 0) {
110
+ return { flushed: true, remaining: 0 };
111
+ }
112
+ if (Date.now() - startedAt >= timeoutMs) {
113
+ return { flushed: false, remaining };
114
+ }
115
+ await sleep(retryIntervalMs);
116
+ }
117
+ }
98
118
  async forceReconnect(reason = 'manual_reconnect') {
99
119
  if (typeof this.wsClient.forceReconnect === 'function') {
100
120
  await this.wsClient.forceReconnect(reason);
@@ -41,6 +41,7 @@ export interface WebSocketDisconnectEvent {
41
41
  }
42
42
  export interface WebSocketClientOptions {
43
43
  reconnectDelay?: number;
44
+ duplicateHostReconnectDelay?: number;
44
45
  heartbeatInterval?: number;
45
46
  extraHeaders?: Record<string, string>;
46
47
  connectImpl?: ConnectImpl;
@@ -54,6 +55,7 @@ export declare class ConductorWebSocketClient {
54
55
  private readonly url;
55
56
  private readonly token;
56
57
  private readonly reconnectDelay;
58
+ private readonly duplicateHostReconnectDelay;
57
59
  private readonly heartbeatInterval;
58
60
  private readonly connectImpl;
59
61
  private readonly onConnected?;
@@ -83,6 +85,7 @@ export declare class ConductorWebSocketClient {
83
85
  private listenLoop;
84
86
  private heartbeatLoop;
85
87
  private handleConnectionLoss;
88
+ private getReconnectDelay;
86
89
  private dispatch;
87
90
  private notifyConnected;
88
91
  private notifyReconnected;
package/dist/ws/client.js CHANGED
@@ -12,6 +12,7 @@ export class ConductorWebSocketClient {
12
12
  url;
13
13
  token;
14
14
  reconnectDelay;
15
+ duplicateHostReconnectDelay;
15
16
  heartbeatInterval;
16
17
  connectImpl;
17
18
  onConnected;
@@ -32,6 +33,7 @@ export class ConductorWebSocketClient {
32
33
  this.url = config.resolvedWebsocketUrl;
33
34
  this.token = config.agentToken;
34
35
  this.reconnectDelay = options.reconnectDelay ?? 10_000;
36
+ this.duplicateHostReconnectDelay = options.duplicateHostReconnectDelay ?? Math.max(this.reconnectDelay, 2_000);
35
37
  this.heartbeatInterval = options.heartbeatInterval ?? 20_000;
36
38
  this.extraHeaders = {
37
39
  'x-conductor-host': options.hostName ?? defaultHostName(),
@@ -184,8 +186,16 @@ export class ConductorWebSocketClient {
184
186
  this.conn = null;
185
187
  this.runtime = null;
186
188
  this.notifyDisconnected(this.buildDisconnectEvent(runtime));
189
+ await wait(this.getReconnectDelay(runtime), this.waitController.signal);
187
190
  await this.openConnection(true);
188
191
  }
192
+ getReconnectDelay(runtime) {
193
+ if (runtime?.closeCode === 4002 &&
194
+ String(runtime?.closeReason || '').trim().toLowerCase() === 'duplicate-host') {
195
+ return this.duplicateHostReconnectDelay;
196
+ }
197
+ return this.reconnectDelay;
198
+ }
189
199
  async dispatch(message) {
190
200
  const now = Date.now();
191
201
  if (this.runtime) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@love-moon/conductor-sdk",
3
- "version": "0.2.31",
3
+ "version": "0.2.32",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,5 +27,5 @@
27
27
  "typescript": "^5.6.3",
28
28
  "vitest": "^2.1.4"
29
29
  },
30
- "gitCommitId": "7e0bd83"
30
+ "gitCommitId": "c749d4b"
31
31
  }