@fluidframework/task-manager 2.63.0-359734 → 2.63.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.
- package/CHANGELOG.md +4 -0
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.d.ts.map +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/taskManager.d.ts +5 -0
- package/dist/taskManager.d.ts.map +1 -1
- package/dist/taskManager.js +26 -27
- package/dist/taskManager.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.d.ts.map +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/taskManager.d.ts +5 -0
- package/lib/taskManager.d.ts.map +1 -1
- package/lib/taskManager.js +26 -27
- package/lib/taskManager.js.map +1 -1
- package/package.json +16 -16
- package/src/packageVersion.ts +1 -1
- package/src/taskManager.ts +30 -31
package/src/taskManager.ts
CHANGED
|
@@ -101,6 +101,8 @@ export class TaskManagerClass
|
|
|
101
101
|
private readonly completedWatcher: EventEmitter = new EventEmitter();
|
|
102
102
|
// rollbackWatcher emits an event whenever a pending op is rolled back.
|
|
103
103
|
private readonly rollbackWatcher: EventEmitter = new EventEmitter();
|
|
104
|
+
// attachedWatcher emits an event whenever the client becomes attached.
|
|
105
|
+
private readonly attachedWatcher: EventEmitter = new EventEmitter();
|
|
104
106
|
|
|
105
107
|
private nextPendingMessageId: number = 0;
|
|
106
108
|
/**
|
|
@@ -116,8 +118,8 @@ export class TaskManagerClass
|
|
|
116
118
|
/**
|
|
117
119
|
* Returns the clientId. Will return a placeholder if the runtime is detached and not yet assigned a clientId.
|
|
118
120
|
*/
|
|
119
|
-
private get clientId(): string
|
|
120
|
-
return this.
|
|
121
|
+
private get clientId(): string {
|
|
122
|
+
return this.runtime.clientId ?? placeholderClientId;
|
|
121
123
|
}
|
|
122
124
|
|
|
123
125
|
/**
|
|
@@ -220,11 +222,6 @@ export class TaskManagerClass
|
|
|
220
222
|
return;
|
|
221
223
|
}
|
|
222
224
|
|
|
223
|
-
// Exit early if we are still catching up on reconnect -- we can't be the leader yet anyway.
|
|
224
|
-
if (this.clientId === undefined) {
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
225
|
if (oldLockHolder !== this.clientId && newLockHolder === this.clientId) {
|
|
229
226
|
this.emit("assigned", taskId);
|
|
230
227
|
} else if (oldLockHolder === this.clientId && newLockHolder !== this.clientId) {
|
|
@@ -234,8 +231,6 @@ export class TaskManagerClass
|
|
|
234
231
|
);
|
|
235
232
|
|
|
236
233
|
this.connectionWatcher.on("disconnect", () => {
|
|
237
|
-
assert(this.clientId !== undefined, 0x1d3 /* "Missing client id on disconnect" */);
|
|
238
|
-
|
|
239
234
|
// Emit "lost" for any tasks we were assigned to.
|
|
240
235
|
for (const [taskId, clientQueue] of this.taskQueues.entries()) {
|
|
241
236
|
if (this.isAttached() && clientQueue[0] === this.clientId) {
|
|
@@ -325,7 +320,6 @@ export class TaskManagerClass
|
|
|
325
320
|
|
|
326
321
|
if (this.isDetached()) {
|
|
327
322
|
// Simulate auto-ack in detached scenario
|
|
328
|
-
assert(this.clientId !== undefined, 0x472 /* clientId should not be undefined */);
|
|
329
323
|
this.addClientToQueue(taskId, this.clientId);
|
|
330
324
|
return true;
|
|
331
325
|
}
|
|
@@ -382,6 +376,7 @@ export class TaskManagerClass
|
|
|
382
376
|
};
|
|
383
377
|
|
|
384
378
|
const rejectOnDisconnect = (): void => {
|
|
379
|
+
this.abandon(taskId);
|
|
385
380
|
removeListeners();
|
|
386
381
|
reject(new Error("Disconnected before acquiring task assignment"));
|
|
387
382
|
};
|
|
@@ -430,6 +425,7 @@ export class TaskManagerClass
|
|
|
430
425
|
}
|
|
431
426
|
|
|
432
427
|
let volunteerOpMessageId: number | undefined;
|
|
428
|
+
let abandoned = false;
|
|
433
429
|
|
|
434
430
|
const submitVolunteerOp = (): void => {
|
|
435
431
|
volunteerOpMessageId = this.nextPendingMessageId;
|
|
@@ -445,14 +441,16 @@ export class TaskManagerClass
|
|
|
445
441
|
const removeListeners = (): void => {
|
|
446
442
|
this.abandonWatcher.off("abandon", checkIfAbandoned);
|
|
447
443
|
this.connectionWatcher.off("disconnect", disconnectHandler);
|
|
448
|
-
this.connectionWatcher.off("connect", submitVolunteerOp);
|
|
449
444
|
this.completedWatcher.off("completed", checkIfCompleted);
|
|
450
445
|
this.rollbackWatcher.off("rollback", checkIfRolledBack);
|
|
451
446
|
};
|
|
452
|
-
|
|
453
447
|
const disconnectHandler = (): void => {
|
|
454
|
-
//
|
|
455
|
-
|
|
448
|
+
// If we are disconnected and have not already sent a volunteer op, then we should
|
|
449
|
+
// submit another volunteer op while disconnected. This will allow the op to be
|
|
450
|
+
// picked up by resubmitCore() and resubmitted when we reconnect.
|
|
451
|
+
if (!this.queuedOptimistically(taskId)) {
|
|
452
|
+
submitVolunteerOp();
|
|
453
|
+
}
|
|
456
454
|
};
|
|
457
455
|
|
|
458
456
|
const checkIfAbandoned = (eventTaskId: string, messageId: number | undefined): void => {
|
|
@@ -475,6 +473,7 @@ export class TaskManagerClass
|
|
|
475
473
|
}
|
|
476
474
|
removeListeners();
|
|
477
475
|
this.subscribedTasks.delete(taskId);
|
|
476
|
+
abandoned = true;
|
|
478
477
|
};
|
|
479
478
|
|
|
480
479
|
const checkIfCompleted = (eventTaskId: string, messageId: number | undefined): void => {
|
|
@@ -506,23 +505,18 @@ export class TaskManagerClass
|
|
|
506
505
|
|
|
507
506
|
if (this.isDetached()) {
|
|
508
507
|
// Simulate auto-ack in detached scenario
|
|
509
|
-
assert(this.clientId !== undefined, 0x473 /* clientId should not be undefined */);
|
|
510
508
|
this.addClientToQueue(taskId, this.clientId);
|
|
511
509
|
// Because we volunteered with placeholderClientId, we need to wait for when we attach and are assigned
|
|
512
510
|
// a real clientId. At that point we should re-enter the queue with a real volunteer op (assuming we are
|
|
513
511
|
// connected).
|
|
514
|
-
this.
|
|
512
|
+
this.attachedWatcher.once("attached", () => {
|
|
515
513
|
// We call scrubClientsNotInQuorum() in case our clientId changed during the attach process.
|
|
516
514
|
this.scrubClientsNotInQuorum();
|
|
517
|
-
|
|
515
|
+
// Make sure abandon() was not called while we were detached.
|
|
516
|
+
if (!abandoned) {
|
|
518
517
|
submitVolunteerOp();
|
|
519
|
-
} else {
|
|
520
|
-
this.connectionWatcher.once("connect", submitVolunteerOp);
|
|
521
518
|
}
|
|
522
519
|
});
|
|
523
|
-
} else if (!this.connected) {
|
|
524
|
-
// If we are disconnected (and attached), wait to be connected and submit volunteer op
|
|
525
|
-
disconnectHandler();
|
|
526
520
|
} else if (!this.queuedOptimistically(taskId)) {
|
|
527
521
|
// We don't need to send a second volunteer op if we just sent one.
|
|
528
522
|
submitVolunteerOp();
|
|
@@ -543,7 +537,6 @@ export class TaskManagerClass
|
|
|
543
537
|
|
|
544
538
|
if (this.isDetached()) {
|
|
545
539
|
// Simulate auto-ack in detached scenario
|
|
546
|
-
assert(this.clientId !== undefined, 0x474 /* clientId is undefined */);
|
|
547
540
|
this.removeClientFromQueue(taskId, this.clientId);
|
|
548
541
|
this.abandonWatcher.emit("abandon", taskId);
|
|
549
542
|
return;
|
|
@@ -573,7 +566,6 @@ export class TaskManagerClass
|
|
|
573
566
|
return false;
|
|
574
567
|
}
|
|
575
568
|
|
|
576
|
-
assert(this.clientId !== undefined, 0x07f /* "clientId undefined" */);
|
|
577
569
|
return this.taskQueues.get(taskId)?.includes(this.clientId) ?? false;
|
|
578
570
|
}
|
|
579
571
|
|
|
@@ -624,7 +616,7 @@ export class TaskManagerClass
|
|
|
624
616
|
* @returns the summary of the current state of the task manager
|
|
625
617
|
*/
|
|
626
618
|
protected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {
|
|
627
|
-
if (this.
|
|
619
|
+
if (this.clientId === placeholderClientId) {
|
|
628
620
|
// If the runtime has still not been assigned a clientId, we should not summarize with the placeholder
|
|
629
621
|
// clientIds and instead remove them from the queues and require the client to re-volunteer when assigned
|
|
630
622
|
// a new clientId.
|
|
@@ -688,6 +680,12 @@ export class TaskManagerClass
|
|
|
688
680
|
);
|
|
689
681
|
assert(pendingOpIndex !== -1, 0xc43 /* Could not match pending op on resubmit attempt */);
|
|
690
682
|
pendingOps.splice(pendingOpIndex, 1);
|
|
683
|
+
if (
|
|
684
|
+
content.type === "volunteer" &&
|
|
685
|
+
pendingOps[pendingOps.length - 1]?.type !== "abandon"
|
|
686
|
+
) {
|
|
687
|
+
this.submitVolunteerOp(content.taskId);
|
|
688
|
+
}
|
|
691
689
|
if (pendingOps.length === 0) {
|
|
692
690
|
this.latestPendingOps.delete(content.taskId);
|
|
693
691
|
}
|
|
@@ -837,12 +835,6 @@ export class TaskManagerClass
|
|
|
837
835
|
* for the latest pending ops.
|
|
838
836
|
*/
|
|
839
837
|
private queuedOptimistically(taskId: string): boolean {
|
|
840
|
-
if (this.isAttached() && !this.connected) {
|
|
841
|
-
return false;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
assert(this.clientId !== undefined, 0xc44 /* clientId undefined */);
|
|
845
|
-
|
|
846
838
|
const inQueue = this.taskQueues.get(taskId)?.includes(this.clientId) ?? false;
|
|
847
839
|
const latestPendingOps = this.latestPendingOps.get(taskId);
|
|
848
840
|
|
|
@@ -896,4 +888,11 @@ export class TaskManagerClass
|
|
|
896
888
|
}
|
|
897
889
|
this.rollbackWatcher.emit("rollback", content.taskId);
|
|
898
890
|
}
|
|
891
|
+
|
|
892
|
+
/**
|
|
893
|
+
* {@inheritDoc @fluidframework/shared-object-base#SharedObject.didAttach}
|
|
894
|
+
*/
|
|
895
|
+
protected didAttach(): void {
|
|
896
|
+
this.attachedWatcher.emit("attached");
|
|
897
|
+
}
|
|
899
898
|
}
|