@sovovs/bycli 2.1.43 → 2.1.44
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.
|
@@ -40,12 +40,14 @@ export interface AdapterSchedulerOptions {
|
|
|
40
40
|
leaseExpiryMs?: number;
|
|
41
41
|
runtimeCeiling?: number;
|
|
42
42
|
releasedLeaseRetentionMs?: number;
|
|
43
|
+
startIntervalMs?: number;
|
|
43
44
|
}
|
|
44
45
|
export declare class AdapterScheduler {
|
|
45
46
|
private readonly now;
|
|
46
47
|
private readonly leaseExpiryMs;
|
|
47
48
|
private readonly runtimeCeiling;
|
|
48
49
|
private readonly releasedLeaseRetentionMs;
|
|
50
|
+
private readonly startIntervalMs;
|
|
49
51
|
private readonly pools;
|
|
50
52
|
private readonly releasedLeaseIds;
|
|
51
53
|
private readonly generations;
|
|
@@ -74,6 +76,9 @@ export declare class AdapterScheduler {
|
|
|
74
76
|
grants: number;
|
|
75
77
|
};
|
|
76
78
|
private schedule;
|
|
79
|
+
private rejectExpiredQueued;
|
|
80
|
+
private clearPoolTimer;
|
|
81
|
+
private armPoolTimer;
|
|
77
82
|
private scheduleResources;
|
|
78
83
|
private releaseAllResourcesForLease;
|
|
79
84
|
private pruneReleasedLeaseIds;
|
|
@@ -12,6 +12,7 @@ export class AdapterScheduler {
|
|
|
12
12
|
leaseExpiryMs;
|
|
13
13
|
runtimeCeiling;
|
|
14
14
|
releasedLeaseRetentionMs;
|
|
15
|
+
startIntervalMs;
|
|
15
16
|
pools = new Map();
|
|
16
17
|
releasedLeaseIds = new Map();
|
|
17
18
|
generations = new Map();
|
|
@@ -20,10 +21,15 @@ export class AdapterScheduler {
|
|
|
20
21
|
resourceQueue = [];
|
|
21
22
|
sequence = 0;
|
|
22
23
|
constructor(options = {}) {
|
|
24
|
+
const startIntervalMs = options.startIntervalMs ?? 5_000;
|
|
25
|
+
if (!Number.isInteger(startIntervalMs) || startIntervalMs < 0) {
|
|
26
|
+
throw new Error('Adapter start interval must be a non-negative integer');
|
|
27
|
+
}
|
|
23
28
|
this.now = options.now ?? Date.now;
|
|
24
29
|
this.leaseExpiryMs = options.leaseExpiryMs ?? 45_000;
|
|
25
30
|
this.runtimeCeiling = options.runtimeCeiling ?? 3;
|
|
26
31
|
this.releasedLeaseRetentionMs = options.releasedLeaseRetentionMs ?? 300_000;
|
|
32
|
+
this.startIntervalMs = startIntervalMs;
|
|
27
33
|
}
|
|
28
34
|
acquire(request) {
|
|
29
35
|
this.validateRequest(request);
|
|
@@ -73,6 +79,7 @@ export class AdapterScheduler {
|
|
|
73
79
|
this.releasedLeaseIds.set(lease.leaseId, this.now() + this.releasedLeaseRetentionMs);
|
|
74
80
|
if (release.reason === 'auth_gate' || release.reason === 'rate_limited') {
|
|
75
81
|
pool.closed = release.reason;
|
|
82
|
+
this.clearPoolTimer(pool);
|
|
76
83
|
const error = this.poolClosedError(release.reason);
|
|
77
84
|
for (const pending of pool.queued.splice(0)) {
|
|
78
85
|
if (pending.timer)
|
|
@@ -144,14 +151,7 @@ export class AdapterScheduler {
|
|
|
144
151
|
const now = this.now();
|
|
145
152
|
this.pruneReleasedLeaseIds(now);
|
|
146
153
|
for (const pool of [...this.pools.values()]) {
|
|
147
|
-
|
|
148
|
-
if (pending.deadline > now)
|
|
149
|
-
continue;
|
|
150
|
-
pool.queued.splice(pool.queued.indexOf(pending), 1);
|
|
151
|
-
if (pending.timer)
|
|
152
|
-
clearTimeout(pending.timer);
|
|
153
|
-
pending.reject(new AdapterSchedulerError('ADAPTER_QUEUE_TIMEOUT', 'Timed out waiting for an Adapter command lease'));
|
|
154
|
-
}
|
|
154
|
+
this.rejectExpiredQueued(pool, now);
|
|
155
155
|
for (const lease of [...pool.running.values()]) {
|
|
156
156
|
if (lease.heartbeatDeadline > now)
|
|
157
157
|
continue;
|
|
@@ -176,6 +176,7 @@ export class AdapterScheduler {
|
|
|
176
176
|
}
|
|
177
177
|
reset() {
|
|
178
178
|
for (const pool of this.pools.values()) {
|
|
179
|
+
this.clearPoolTimer(pool);
|
|
179
180
|
for (const pending of pool.queued) {
|
|
180
181
|
if (pending.timer)
|
|
181
182
|
clearTimeout(pending.timer);
|
|
@@ -209,34 +210,69 @@ export class AdapterScheduler {
|
|
|
209
210
|
};
|
|
210
211
|
}
|
|
211
212
|
schedule(pool) {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
pool.
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
poolKey: pool.key,
|
|
227
|
-
contextId: eligible.request.contextId,
|
|
228
|
-
surface: 'adapter',
|
|
229
|
-
site: eligible.request.site,
|
|
230
|
-
adapterSession: eligible.request.adapterSession,
|
|
231
|
-
sessionKey: eligible.request.sessionKey,
|
|
232
|
-
generation: pool.generation,
|
|
233
|
-
grantedAt,
|
|
234
|
-
heartbeatDeadline: grantedAt + this.leaseExpiryMs,
|
|
235
|
-
};
|
|
236
|
-
pool.running.set(lease.leaseId, lease);
|
|
237
|
-
pool.activeSessions.add(lease.adapterSession);
|
|
238
|
-
eligible.resolve({ ...lease });
|
|
213
|
+
if (pool.closed)
|
|
214
|
+
return;
|
|
215
|
+
const now = this.now();
|
|
216
|
+
this.rejectExpiredQueued(pool, now);
|
|
217
|
+
if (pool.running.size >= pool.maxParallel)
|
|
218
|
+
return;
|
|
219
|
+
const eligible = pool.queued
|
|
220
|
+
.filter(entry => !pool.activeSessions.has(entry.request.adapterSession))
|
|
221
|
+
.sort((a, b) => a.enqueuedAt - b.enqueuedAt || a.sequence - b.sequence)[0];
|
|
222
|
+
if (!eligible)
|
|
223
|
+
return;
|
|
224
|
+
if (now < pool.nextGrantAt) {
|
|
225
|
+
this.armPoolTimer(pool, pool.nextGrantAt);
|
|
226
|
+
return;
|
|
239
227
|
}
|
|
228
|
+
pool.queued.splice(pool.queued.indexOf(eligible), 1);
|
|
229
|
+
if (eligible.timer)
|
|
230
|
+
clearTimeout(eligible.timer);
|
|
231
|
+
const grantedAt = now;
|
|
232
|
+
const lease = {
|
|
233
|
+
leaseId: crypto.randomUUID(),
|
|
234
|
+
requestId: eligible.request.requestId,
|
|
235
|
+
poolKey: pool.key,
|
|
236
|
+
contextId: eligible.request.contextId,
|
|
237
|
+
surface: 'adapter',
|
|
238
|
+
site: eligible.request.site,
|
|
239
|
+
adapterSession: eligible.request.adapterSession,
|
|
240
|
+
sessionKey: eligible.request.sessionKey,
|
|
241
|
+
generation: pool.generation,
|
|
242
|
+
grantedAt,
|
|
243
|
+
heartbeatDeadline: grantedAt + this.leaseExpiryMs,
|
|
244
|
+
};
|
|
245
|
+
pool.nextGrantAt = grantedAt + this.startIntervalMs;
|
|
246
|
+
pool.running.set(lease.leaseId, lease);
|
|
247
|
+
pool.activeSessions.add(lease.adapterSession);
|
|
248
|
+
eligible.resolve({ ...lease });
|
|
249
|
+
this.schedule(pool);
|
|
250
|
+
}
|
|
251
|
+
rejectExpiredQueued(pool, now) {
|
|
252
|
+
for (const pending of [...pool.queued]) {
|
|
253
|
+
if (pending.deadline > now)
|
|
254
|
+
continue;
|
|
255
|
+
pool.queued.splice(pool.queued.indexOf(pending), 1);
|
|
256
|
+
if (pending.timer)
|
|
257
|
+
clearTimeout(pending.timer);
|
|
258
|
+
pending.reject(new AdapterSchedulerError('ADAPTER_QUEUE_TIMEOUT', 'Timed out waiting for an Adapter command lease'));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
clearPoolTimer(pool) {
|
|
262
|
+
if (pool.scheduleTimer)
|
|
263
|
+
clearTimeout(pool.scheduleTimer);
|
|
264
|
+
pool.scheduleTimer = undefined;
|
|
265
|
+
}
|
|
266
|
+
armPoolTimer(pool, dueAt) {
|
|
267
|
+
if (pool.scheduleTimer)
|
|
268
|
+
return;
|
|
269
|
+
pool.scheduleTimer = setTimeout(() => {
|
|
270
|
+
pool.scheduleTimer = undefined;
|
|
271
|
+
if (this.pools.get(pool.key) !== pool)
|
|
272
|
+
return;
|
|
273
|
+
this.sweepExpired();
|
|
274
|
+
}, Math.max(0, dueAt - this.now()));
|
|
275
|
+
pool.scheduleTimer.unref?.();
|
|
240
276
|
}
|
|
241
277
|
scheduleResources() {
|
|
242
278
|
for (const pending of [...this.resourceQueue].sort((a, b) => a.sequence - b.sequence)) {
|
|
@@ -319,6 +355,7 @@ export class AdapterScheduler {
|
|
|
319
355
|
key,
|
|
320
356
|
generation,
|
|
321
357
|
maxParallel: Math.min(request.maxParallel, this.runtimeCeiling),
|
|
358
|
+
nextGrantAt: 0,
|
|
322
359
|
running: new Map(),
|
|
323
360
|
activeSessions: new Set(),
|
|
324
361
|
queued: [],
|
|
@@ -327,8 +364,14 @@ export class AdapterScheduler {
|
|
|
327
364
|
return pool;
|
|
328
365
|
}
|
|
329
366
|
removeDrainedPool(pool) {
|
|
330
|
-
if (pool.running.size
|
|
331
|
-
|
|
367
|
+
if (pool.running.size !== 0 || pool.queued.length !== 0)
|
|
368
|
+
return;
|
|
369
|
+
if (!pool.closed && this.now() < pool.nextGrantAt) {
|
|
370
|
+
this.armPoolTimer(pool, pool.nextGrantAt);
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
this.clearPoolTimer(pool);
|
|
374
|
+
this.pools.delete(pool.key);
|
|
332
375
|
}
|
|
333
376
|
poolClosedError(reason) {
|
|
334
377
|
return reason === 'auth_gate'
|