comfyui-node 1.5.0 → 1.6.0

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.
Files changed (41) hide show
  1. package/LICENSE +1 -1
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/call-wrapper.d.ts.map +1 -1
  4. package/dist/call-wrapper.js +133 -37
  5. package/dist/call-wrapper.js.map +1 -1
  6. package/dist/index.d.ts +3 -2
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/index.js.map +1 -1
  10. package/dist/pool/SmartPool.d.ts +144 -0
  11. package/dist/pool/SmartPool.d.ts.map +1 -0
  12. package/dist/pool/SmartPool.js +677 -0
  13. package/dist/pool/SmartPool.js.map +1 -0
  14. package/dist/pool/SmartPoolV2.d.ts +120 -0
  15. package/dist/pool/SmartPoolV2.d.ts.map +1 -0
  16. package/dist/pool/SmartPoolV2.js +587 -0
  17. package/dist/pool/SmartPoolV2.js.map +1 -0
  18. package/dist/pool/WorkflowPool.d.ts +23 -0
  19. package/dist/pool/WorkflowPool.d.ts.map +1 -1
  20. package/dist/pool/WorkflowPool.js +206 -59
  21. package/dist/pool/WorkflowPool.js.map +1 -1
  22. package/dist/pool/client/ClientManager.d.ts +4 -2
  23. package/dist/pool/client/ClientManager.d.ts.map +1 -1
  24. package/dist/pool/client/ClientManager.js +29 -9
  25. package/dist/pool/client/ClientManager.js.map +1 -1
  26. package/dist/pool/index.d.ts +2 -0
  27. package/dist/pool/index.d.ts.map +1 -1
  28. package/dist/pool/index.js +2 -0
  29. package/dist/pool/index.js.map +1 -1
  30. package/dist/pool/queue/QueueAdapter.d.ts +2 -0
  31. package/dist/pool/queue/QueueAdapter.d.ts.map +1 -1
  32. package/dist/pool/queue/adapters/memory.d.ts +2 -0
  33. package/dist/pool/queue/adapters/memory.d.ts.map +1 -1
  34. package/dist/pool/queue/adapters/memory.js +14 -2
  35. package/dist/pool/queue/adapters/memory.js.map +1 -1
  36. package/dist/pool/types/affinity.d.ts +6 -0
  37. package/dist/pool/types/affinity.d.ts.map +1 -0
  38. package/dist/pool/types/affinity.js +2 -0
  39. package/dist/pool/types/affinity.js.map +1 -0
  40. package/dist/pool/types/job.d.ts.map +1 -1
  41. package/package.json +2 -1
@@ -0,0 +1,587 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { TypedEventTarget } from "../typed-event-target.js";
3
+ import { ComfyApi } from "../client.js";
4
+ import { PromptBuilder } from "../prompt-builder.js";
5
+ import { MemoryQueueAdapter } from "./queue/adapters/memory.js";
6
+ import { hashWorkflow } from "./utils/hash.js";
7
+ // ============================================================================
8
+ // MAIN CLASS
9
+ // ============================================================================
10
+ export class SmartPoolV2 extends TypedEventTarget {
11
+ // Client management
12
+ clientMap = new Map();
13
+ // Affinity groups and queues
14
+ affinityGroups = new Map();
15
+ defaultQueue;
16
+ // Job tracking
17
+ jobStore = new Map();
18
+ executionContexts = new Map();
19
+ // Server state
20
+ idleServers = new Set();
21
+ serverPerformance = new Map();
22
+ // Pool configuration
23
+ options;
24
+ // Pool state
25
+ isReady;
26
+ readyResolve;
27
+ // =========================================================================
28
+ // CONSTRUCTOR
29
+ // =========================================================================
30
+ constructor(clients, options) {
31
+ super();
32
+ this.options = {
33
+ connectionTimeoutMs: options?.connectionTimeoutMs ?? 10000,
34
+ jobExecutionTimeoutMs: options?.jobExecutionTimeoutMs ?? 5 * 60 * 1000, // 5 min
35
+ groupIdleTimeoutMs: options?.groupIdleTimeoutMs ?? 60 * 1000, // 60 sec
36
+ maxQueueDepth: options?.maxQueueDepth ?? 1000
37
+ };
38
+ // Initialize clients
39
+ for (const client of clients) {
40
+ if (typeof client === "string") {
41
+ const apiClient = new ComfyApi(client);
42
+ this.clientMap.set(apiClient.apiHost, apiClient);
43
+ }
44
+ else {
45
+ this.clientMap.set(client.apiHost, client);
46
+ }
47
+ }
48
+ // Create default queue for unaffinitized jobs
49
+ this.defaultQueue = this.createAffinityGroup("default", []);
50
+ // Setup ready promise
51
+ this.isReady = new Promise((resolve) => {
52
+ this.readyResolve = resolve;
53
+ });
54
+ }
55
+ // =========================================================================
56
+ // PUBLIC API
57
+ // =========================================================================
58
+ /**
59
+ * Initialize pool and connect all clients
60
+ */
61
+ async connect() {
62
+ const connectionPromises = [];
63
+ for (const [url, client] of this.clientMap.entries()) {
64
+ connectionPromises.push(new Promise((resolve, reject) => {
65
+ const timeout = setTimeout(() => {
66
+ client.abortReconnect();
67
+ reject(new Error(`Connection to client ${url} timed out`));
68
+ }, this.options.connectionTimeoutMs);
69
+ client
70
+ .init(1)
71
+ .then(() => {
72
+ clearTimeout(timeout);
73
+ console.log(`[SmartPoolV2] Connected to ${url}`);
74
+ this.idleServers.add(client.apiHost);
75
+ resolve();
76
+ })
77
+ .catch((err) => {
78
+ clearTimeout(timeout);
79
+ reject(err);
80
+ });
81
+ }));
82
+ }
83
+ await Promise.all(connectionPromises);
84
+ this.readyResolve?.();
85
+ }
86
+ /**
87
+ * Wait for pool to be ready
88
+ */
89
+ ready() {
90
+ return this.isReady;
91
+ }
92
+ /**
93
+ * Enqueue a workflow - automatically routed by workflow hash
94
+ * Optional preferredClientIds overrides default routing for this specific job
95
+ */
96
+ async enqueue(workflow, options) {
97
+ const jobId = randomUUID();
98
+ const workflowHash = workflow.structureHash || hashWorkflow(workflow.json || workflow);
99
+ const workflowJson = workflow.json || workflow;
100
+ const outputNodeIds = workflow.outputNodeIds || [];
101
+ const outputAliases = workflow.outputAliases || {};
102
+ // Find group by workflow hash, fall back to default
103
+ let groupId = workflowHash;
104
+ if (!this.affinityGroups.has(groupId)) {
105
+ groupId = "default";
106
+ }
107
+ const group = this.affinityGroups.get(groupId);
108
+ if (!group) {
109
+ throw new Error(`No affinity group for workflow hash "${workflowHash}"`);
110
+ }
111
+ // Create job record
112
+ const jobRecord = {
113
+ jobId,
114
+ workflow: workflowJson,
115
+ workflowHash,
116
+ options: {
117
+ maxAttempts: 3,
118
+ retryDelayMs: 1000,
119
+ priority: options?.priority ?? 0,
120
+ // Use per-job preferences if provided, otherwise use group defaults
121
+ preferredClientIds: options?.preferredClientIds?.length ? options.preferredClientIds : group.preferredServerIds,
122
+ excludeClientIds: [],
123
+ metadata: options?.metadata || {}
124
+ },
125
+ attempts: 0,
126
+ enqueuedAt: Date.now(),
127
+ workflowMeta: {
128
+ outputNodeIds,
129
+ outputAliases
130
+ },
131
+ status: "queued"
132
+ };
133
+ // Store job
134
+ this.jobStore.set(jobId, jobRecord);
135
+ // Enqueue to group
136
+ const payload = jobRecord;
137
+ await group.queueAdapter.enqueue(payload, { priority: options?.priority ?? 0 });
138
+ // Emit event
139
+ this.dispatchEvent(new CustomEvent("job:queued", { detail: { job: jobRecord } }));
140
+ // Trigger processing immediately (event-driven)
141
+ setImmediate(() => this.processAffinityGroup(groupId));
142
+ return jobId;
143
+ }
144
+ /**
145
+ * Set workflow affinity - auto-creates group by workflow hash
146
+ * Maps workflow hash to preferred servers
147
+ */
148
+ setAffinity(workflow, affinity) {
149
+ const workflowHash = hashWorkflow(workflow);
150
+ // Create group with hash as ID if doesn't exist
151
+ if (!this.affinityGroups.has(workflowHash)) {
152
+ this.createAffinityGroup(workflowHash, affinity.preferredClientIds || []);
153
+ }
154
+ const group = this.affinityGroups.get(workflowHash);
155
+ if (group) {
156
+ group.workflowHashes.add(workflowHash);
157
+ }
158
+ }
159
+ /**
160
+ * Get job by ID
161
+ */
162
+ getJob(jobId) {
163
+ return this.jobStore.get(jobId);
164
+ }
165
+ /**
166
+ * Shutdown pool
167
+ */
168
+ shutdown() {
169
+ // Cancel all timeouts
170
+ for (const group of this.affinityGroups.values()) {
171
+ if (group.idleTimeoutHandle) {
172
+ clearTimeout(group.idleTimeoutHandle);
173
+ }
174
+ }
175
+ if (this.defaultQueue?.idleTimeoutHandle) {
176
+ clearTimeout(this.defaultQueue.idleTimeoutHandle);
177
+ }
178
+ // Cancel all job timeouts
179
+ for (const ctx of this.executionContexts.values()) {
180
+ if (ctx.timeoutHandle) {
181
+ clearTimeout(ctx.timeoutHandle);
182
+ }
183
+ }
184
+ // Destroy clients
185
+ for (const client of this.clientMap.values()) {
186
+ try {
187
+ client.destroy();
188
+ }
189
+ catch (err) {
190
+ console.error(`[SmartPoolV2] Error destroying client: ${err}`);
191
+ }
192
+ }
193
+ }
194
+ /**
195
+ * Get server performance metrics
196
+ */
197
+ getServerPerformance(clientId) {
198
+ return this.serverPerformance.get(clientId);
199
+ }
200
+ // =========================================================================
201
+ // PRIVATE: AFFINITY GROUP MANAGEMENT
202
+ // =========================================================================
203
+ createAffinityGroup(groupId, preferredServerIds) {
204
+ const group = {
205
+ id: groupId,
206
+ preferredServerIds,
207
+ workflowHashes: new Set(),
208
+ queueAdapter: new MemoryQueueAdapter(),
209
+ isProcessing: false,
210
+ lastJobCompletedMs: Date.now(),
211
+ jobsEnqueued: 0,
212
+ jobsCompleted: 0,
213
+ jobsFailed: 0
214
+ };
215
+ this.affinityGroups.set(groupId, group);
216
+ return group;
217
+ }
218
+ // =========================================================================
219
+ // PRIVATE: QUEUE PROCESSING (EVENT-DRIVEN)
220
+ // =========================================================================
221
+ /**
222
+ * Process affinity group queue - triggered by events only (no polling)
223
+ */
224
+ async processAffinityGroup(groupId) {
225
+ const group = this.affinityGroups.get(groupId);
226
+ if (!group)
227
+ return;
228
+ // Reentrancy guard: if already processing, defer
229
+ if (group.isProcessing) {
230
+ if (!group.processingDeferred) {
231
+ group.processingDeferred = new Promise((resolve) => {
232
+ setImmediate(() => {
233
+ group.isProcessing = false;
234
+ this.processAffinityGroup(groupId).then(resolve);
235
+ });
236
+ });
237
+ }
238
+ return group.processingDeferred;
239
+ }
240
+ group.isProcessing = true;
241
+ try {
242
+ while (true) {
243
+ // Peek at waiting jobs first
244
+ const waitingJobs = await group.queueAdapter.peek(100);
245
+ if (waitingJobs.length === 0) {
246
+ break; // No waiting jobs
247
+ }
248
+ // Get the first waiting job
249
+ const jobPayload = waitingJobs[0];
250
+ const job = this.jobStore.get(jobPayload.jobId);
251
+ if (!job) {
252
+ // Job not found, discard from queue
253
+ await group.queueAdapter.discard(jobPayload.jobId, new Error("Job not found"));
254
+ continue;
255
+ }
256
+ // Find idle servers compatible with this specific job
257
+ // First check job's preferred clients, then group's preferred servers
258
+ const preferredServerIds = job.options.preferredClientIds?.length
259
+ ? job.options.preferredClientIds
260
+ : group.preferredServerIds;
261
+ const compatibleIdleServers = Array.from(this.idleServers).filter((serverId) => {
262
+ // If preferred servers specified (job or group), must match
263
+ if (preferredServerIds.length > 0) {
264
+ return preferredServerIds.includes(serverId);
265
+ }
266
+ return true;
267
+ });
268
+ if (compatibleIdleServers.length === 0) {
269
+ break; // No idle compatible servers for this job
270
+ }
271
+ // Sort compatible servers by performance (fastest first)
272
+ const sortedServers = this.sortServersByPerformance(compatibleIdleServers);
273
+ const selectedServerId = sortedServers[0];
274
+ const selectedClient = this.clientMap.get(selectedServerId);
275
+ if (!selectedClient) {
276
+ break;
277
+ }
278
+ // Reserve job
279
+ const reservation = await group.queueAdapter.reserveById(jobPayload.jobId);
280
+ if (!reservation) {
281
+ continue;
282
+ }
283
+ // Mark server as no longer idle (synchronous)
284
+ this.idleServers.delete(selectedServerId);
285
+ // Enqueue job on server (synchronous, fires in background)
286
+ await this.enqueueJobOnServer(job, selectedClient, groupId, reservation);
287
+ }
288
+ }
289
+ finally {
290
+ group.isProcessing = false;
291
+ // Check for deferred processing
292
+ if (group.processingDeferred) {
293
+ group.processingDeferred = undefined;
294
+ }
295
+ }
296
+ }
297
+ // =========================================================================
298
+ // PRIVATE: JOB EXECUTION (NO CALLWRAPPER)
299
+ // =========================================================================
300
+ /**
301
+ * Enqueue job on server and manage execution
302
+ */
303
+ async enqueueJobOnServer(job, client, groupId, reservation) {
304
+ const group = this.affinityGroups.get(groupId);
305
+ if (!group)
306
+ return;
307
+ job.attempts += 1;
308
+ job.status = "running";
309
+ job.clientId = client.apiHost;
310
+ job.startedAt = Date.now();
311
+ try {
312
+ // Clone workflow to avoid mutations
313
+ const workflowJson = JSON.parse(JSON.stringify(job.workflow));
314
+ const outputNodeIds = job.workflowMeta?.outputNodeIds || [];
315
+ // Auto-randomize seeds
316
+ try {
317
+ for (const node of Object.values(workflowJson)) {
318
+ const n = node;
319
+ if (n?.inputs?.seed === -1) {
320
+ n.inputs.seed = Math.floor(Math.random() * 2_147_483_647);
321
+ }
322
+ }
323
+ }
324
+ catch {
325
+ /* non-fatal */
326
+ }
327
+ // Build prompt
328
+ const pb = new PromptBuilder(workflowJson, [], outputNodeIds);
329
+ for (const nodeId of outputNodeIds) {
330
+ pb.setOutputNode(nodeId, nodeId);
331
+ }
332
+ const promptJson = pb.prompt;
333
+ // Append to server queue
334
+ let queueResponse;
335
+ try {
336
+ queueResponse = await client.ext.queue.appendPrompt(promptJson);
337
+ }
338
+ catch (err) {
339
+ throw new Error(`Failed to enqueue job: ${err}`);
340
+ }
341
+ const promptId = queueResponse.prompt_id;
342
+ job.promptId = promptId;
343
+ // Create execution context
344
+ const ctx = {
345
+ job,
346
+ groupId,
347
+ promptId
348
+ };
349
+ this.executionContexts.set(job.jobId, ctx);
350
+ // Emit accepted event
351
+ this.dispatchEvent(new CustomEvent("job:accepted", {
352
+ detail: { job, clientId: client.apiHost }
353
+ }));
354
+ this.dispatchEvent(new CustomEvent("job:started", {
355
+ detail: { job, clientId: client.apiHost, promptId }
356
+ }));
357
+ // Set up execution timeout (5 min)
358
+ ctx.timeoutHandle = setTimeout(() => {
359
+ console.warn(`[SmartPoolV2] Job ${job.jobId} execution timeout`);
360
+ this.handleJobTimeout(job.jobId);
361
+ }, this.options.jobExecutionTimeoutMs);
362
+ // Set up event listeners (strict prompt_id matching)
363
+ const outputMap = {};
364
+ let outputsCollected = 0;
365
+ const expectedOutputCount = outputNodeIds.length;
366
+ ctx.executedHandler = (ev) => {
367
+ // Strict prompt_id check
368
+ if (ev.detail.prompt_id !== promptId) {
369
+ return;
370
+ }
371
+ const nodeId = ev.detail.node;
372
+ const output = ev.detail.output;
373
+ outputMap[nodeId] = output;
374
+ outputsCollected++;
375
+ // All outputs collected?
376
+ if (outputsCollected === expectedOutputCount) {
377
+ this.handleJobCompletion(job.jobId, groupId, outputMap, client.apiHost);
378
+ }
379
+ };
380
+ ctx.executionSuccessHandler = async (ev) => {
381
+ if (ev.detail.prompt_id !== promptId) {
382
+ return;
383
+ }
384
+ // Try to get missing outputs from history if needed
385
+ if (outputsCollected < expectedOutputCount) {
386
+ try {
387
+ const history = await client.ext.history.getHistory(promptId);
388
+ if (history?.outputs) {
389
+ for (const [nodeIdStr, nodeOutput] of Object.entries(history.outputs)) {
390
+ const nodeId = nodeIdStr;
391
+ if (!outputMap[nodeId] && nodeOutput) {
392
+ outputMap[nodeId] = nodeOutput;
393
+ outputsCollected++;
394
+ }
395
+ }
396
+ }
397
+ }
398
+ catch {
399
+ /* non-fatal */
400
+ }
401
+ }
402
+ // Complete job regardless
403
+ this.handleJobCompletion(job.jobId, groupId, outputMap, client.apiHost);
404
+ };
405
+ ctx.executionErrorHandler = (ev) => {
406
+ if (ev.detail.prompt_id !== promptId) {
407
+ return;
408
+ }
409
+ const error = new Error(`Execution error: ${ev.detail.exception_type}`);
410
+ this.handleJobFailure(job.jobId, groupId, error);
411
+ };
412
+ // Attach listeners
413
+ client.on("executed", ctx.executedHandler);
414
+ client.on("execution_success", ctx.executionSuccessHandler);
415
+ client.on("execution_error", ctx.executionErrorHandler);
416
+ // Commit to queue
417
+ await group.queueAdapter.commit(reservation.reservationId);
418
+ }
419
+ catch (err) {
420
+ const error = err instanceof Error ? err : new Error(String(err));
421
+ // Retry or fail
422
+ if (job.attempts < job.options.maxAttempts) {
423
+ await group.queueAdapter.retry(reservation.reservationId, {
424
+ delayMs: job.options.retryDelayMs
425
+ });
426
+ }
427
+ else {
428
+ await group.queueAdapter.discard(reservation.reservationId, error);
429
+ this.handleJobFailure(job.jobId, groupId, error);
430
+ }
431
+ // Mark server idle again
432
+ this.idleServers.add(client.apiHost);
433
+ this.dispatchEvent(new CustomEvent("server:idle", {
434
+ detail: { clientId: client.apiHost, groupId }
435
+ }));
436
+ // Trigger processing
437
+ setImmediate(() => this.processAffinityGroup(groupId));
438
+ }
439
+ }
440
+ /**
441
+ * Handle job completion
442
+ */
443
+ handleJobCompletion(jobId, groupId, outputMap, clientId) {
444
+ const job = this.jobStore.get(jobId);
445
+ if (!job)
446
+ return;
447
+ const ctx = this.executionContexts.get(jobId);
448
+ if (ctx?.timeoutHandle) {
449
+ clearTimeout(ctx.timeoutHandle);
450
+ }
451
+ // Clean up listeners
452
+ if (ctx) {
453
+ const client = this.clientMap.get(clientId);
454
+ if (client) {
455
+ if (ctx.executedHandler)
456
+ client.off("executed", ctx.executedHandler);
457
+ if (ctx.executionSuccessHandler)
458
+ client.off("execution_success", ctx.executionSuccessHandler);
459
+ if (ctx.executionErrorHandler)
460
+ client.off("execution_error", ctx.executionErrorHandler);
461
+ }
462
+ }
463
+ // Update job
464
+ job.status = "completed";
465
+ job.result = outputMap;
466
+ job.completedAt = Date.now();
467
+ const executionTimeMs = job.completedAt - (job.startedAt || job.completedAt);
468
+ this.updateServerPerformance(clientId, executionTimeMs);
469
+ // Update group stats
470
+ const group = this.affinityGroups.get(groupId);
471
+ if (group) {
472
+ group.jobsCompleted++;
473
+ group.lastJobCompletedMs = Date.now();
474
+ // Reset idle timeout for this group
475
+ if (group.idleTimeoutHandle) {
476
+ clearTimeout(group.idleTimeoutHandle);
477
+ }
478
+ group.idleTimeoutHandle = setTimeout(() => {
479
+ this.dispatchEvent(new CustomEvent("group:idle-timeout", {
480
+ detail: { groupId, reason: "No jobs completed in idle threshold" }
481
+ }));
482
+ }, this.options.groupIdleTimeoutMs);
483
+ }
484
+ // Mark server idle
485
+ this.idleServers.add(clientId);
486
+ this.dispatchEvent(new CustomEvent("server:idle", {
487
+ detail: { clientId, groupId }
488
+ }));
489
+ // Emit completed event
490
+ this.dispatchEvent(new CustomEvent("job:completed", { detail: { job } }));
491
+ // Clean up context
492
+ this.executionContexts.delete(jobId);
493
+ // Trigger processing
494
+ setImmediate(() => this.processAffinityGroup(groupId));
495
+ }
496
+ /**
497
+ * Handle job failure
498
+ */
499
+ handleJobFailure(jobId, groupId, error) {
500
+ const job = this.jobStore.get(jobId);
501
+ if (!job)
502
+ return;
503
+ const ctx = this.executionContexts.get(jobId);
504
+ if (ctx?.timeoutHandle) {
505
+ clearTimeout(ctx.timeoutHandle);
506
+ }
507
+ // Clean up listeners
508
+ if (ctx && job.clientId) {
509
+ const client = this.clientMap.get(job.clientId);
510
+ if (client) {
511
+ if (ctx.executedHandler)
512
+ client.off("executed", ctx.executedHandler);
513
+ if (ctx.executionSuccessHandler)
514
+ client.off("execution_success", ctx.executionSuccessHandler);
515
+ if (ctx.executionErrorHandler)
516
+ client.off("execution_error", ctx.executionErrorHandler);
517
+ }
518
+ }
519
+ job.status = "failed";
520
+ job.lastError = error;
521
+ job.completedAt = Date.now();
522
+ // Update group stats
523
+ const group = this.affinityGroups.get(groupId);
524
+ if (group) {
525
+ group.jobsFailed++;
526
+ }
527
+ // Mark server idle
528
+ if (job.clientId) {
529
+ this.idleServers.add(job.clientId);
530
+ this.dispatchEvent(new CustomEvent("server:idle", {
531
+ detail: { clientId: job.clientId, groupId }
532
+ }));
533
+ }
534
+ // Emit failed event
535
+ this.dispatchEvent(new CustomEvent("job:failed", {
536
+ detail: { job, error, willRetry: false }
537
+ }));
538
+ // Clean up context
539
+ this.executionContexts.delete(jobId);
540
+ // Trigger processing
541
+ setImmediate(() => this.processAffinityGroup(groupId));
542
+ }
543
+ /**
544
+ * Handle job timeout
545
+ */
546
+ handleJobTimeout(jobId) {
547
+ const job = this.jobStore.get(jobId);
548
+ if (!job)
549
+ return;
550
+ const ctx = this.executionContexts.get(jobId);
551
+ const groupId = ctx?.groupId || "default";
552
+ const error = new Error(`Job execution timeout after ${this.options.jobExecutionTimeoutMs}ms`);
553
+ this.handleJobFailure(jobId, groupId, error);
554
+ }
555
+ // =========================================================================
556
+ // PRIVATE: PERFORMANCE TRACKING
557
+ // =========================================================================
558
+ updateServerPerformance(clientId, executionTimeMs) {
559
+ let metrics = this.serverPerformance.get(clientId);
560
+ if (!metrics) {
561
+ metrics = {
562
+ clientId,
563
+ totalJobsCompleted: 0,
564
+ totalExecutionTimeMs: 0,
565
+ averageExecutionTimeMs: 0
566
+ };
567
+ this.serverPerformance.set(clientId, metrics);
568
+ }
569
+ metrics.totalJobsCompleted++;
570
+ metrics.totalExecutionTimeMs += executionTimeMs;
571
+ metrics.lastJobDurationMs = executionTimeMs;
572
+ metrics.averageExecutionTimeMs = metrics.totalExecutionTimeMs / metrics.totalJobsCompleted;
573
+ }
574
+ sortServersByPerformance(serverIds) {
575
+ return [...serverIds].sort((a, b) => {
576
+ const metricsA = this.serverPerformance.get(a);
577
+ const metricsB = this.serverPerformance.get(b);
578
+ // Untracked servers go to end
579
+ if (!metricsA)
580
+ return 1;
581
+ if (!metricsB)
582
+ return -1;
583
+ return metricsA.averageExecutionTimeMs - metricsB.averageExecutionTimeMs;
584
+ });
585
+ }
586
+ }
587
+ //# sourceMappingURL=SmartPoolV2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmartPoolV2.js","sourceRoot":"","sources":["../../src/pool/SmartPoolV2.ts"],"names":[],"mappings":"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"}
@@ -4,10 +4,26 @@ import type { QueueAdapter, QueueStats } from "./queue/QueueAdapter.js";
4
4
  import type { FailoverStrategy } from "./failover/Strategy.js";
5
5
  import type { JobRecord, WorkflowInput, WorkflowJobOptions, JobId } from "./types/job.js";
6
6
  import type { WorkflowPoolEventMap } from "./types/events.js";
7
+ import type { WorkflowAffinity } from "./types/affinity.js";
7
8
  /**
8
9
  * Configuration options for WorkflowPool.
9
10
  */
10
11
  export interface WorkflowPoolOpts {
12
+ /**
13
+ * An array of workflow affinity rules to establish a default mapping
14
+ * between workflows and specific clients.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const pool = new WorkflowPool(clients, {
19
+ * workflowAffinities: [
20
+ * { workflowHash: "hash1", preferredClientIds: ["client-a"] },
21
+ * { workflowHash: "hash2", excludeClientIds: ["client-b"] },
22
+ * ]
23
+ * });
24
+ * ```
25
+ */
26
+ workflowAffinities?: WorkflowAffinity[];
11
27
  /**
12
28
  * Queue adapter for managing job queue operations.
13
29
  *
@@ -153,11 +169,18 @@ export declare class WorkflowPool extends TypedEventTarget<WorkflowPoolEventMap>
153
169
  private opts;
154
170
  private jobStore;
155
171
  private jobFailureAnalysis;
172
+ private affinities;
156
173
  private initPromise;
157
174
  private processing;
175
+ private processQueued;
158
176
  private activeJobs;
177
+ private readonly queueDebug;
178
+ private debugLog;
159
179
  constructor(clients: ComfyApi[], opts?: WorkflowPoolOpts);
160
180
  ready(): Promise<void>;
181
+ setAffinity(affinity: WorkflowAffinity): void;
182
+ removeAffinity(workflowHash: string): boolean;
183
+ getAffinities(): WorkflowAffinity[];
161
184
  enqueue(workflowInput: WorkflowInput, options?: WorkflowJobOptions): Promise<JobId>;
162
185
  getJob(jobId: string): JobRecord | undefined;
163
186
  cancel(jobId: string): Promise<boolean>;