@fluidframework/task-manager 2.41.0-338186 → 2.41.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 (42) hide show
  1. package/.eslintrc.cjs +5 -5
  2. package/CHANGELOG.md +4 -0
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/interfaces.d.ts +1 -1
  7. package/dist/interfaces.d.ts.map +1 -1
  8. package/dist/interfaces.js.map +1 -1
  9. package/dist/packageVersion.d.ts +1 -1
  10. package/dist/packageVersion.d.ts.map +1 -1
  11. package/dist/packageVersion.js +1 -1
  12. package/dist/packageVersion.js.map +1 -1
  13. package/dist/taskManager.d.ts +7 -6
  14. package/dist/taskManager.d.ts.map +1 -1
  15. package/dist/taskManager.js +21 -15
  16. package/dist/taskManager.js.map +1 -1
  17. package/dist/taskManagerFactory.d.ts +4 -4
  18. package/dist/taskManagerFactory.d.ts.map +1 -1
  19. package/dist/taskManagerFactory.js.map +1 -1
  20. package/lib/index.d.ts +1 -1
  21. package/lib/index.d.ts.map +1 -1
  22. package/lib/index.js.map +1 -1
  23. package/lib/interfaces.d.ts +1 -1
  24. package/lib/interfaces.d.ts.map +1 -1
  25. package/lib/interfaces.js.map +1 -1
  26. package/lib/packageVersion.d.ts +1 -1
  27. package/lib/packageVersion.d.ts.map +1 -1
  28. package/lib/packageVersion.js +1 -1
  29. package/lib/packageVersion.js.map +1 -1
  30. package/lib/taskManager.d.ts +7 -6
  31. package/lib/taskManager.d.ts.map +1 -1
  32. package/lib/taskManager.js +22 -16
  33. package/lib/taskManager.js.map +1 -1
  34. package/lib/taskManagerFactory.d.ts +4 -4
  35. package/lib/taskManagerFactory.d.ts.map +1 -1
  36. package/lib/taskManagerFactory.js.map +1 -1
  37. package/package.json +16 -16
  38. package/src/index.ts +1 -1
  39. package/src/interfaces.ts +1 -1
  40. package/src/packageVersion.ts +1 -1
  41. package/src/taskManager.ts +64 -56
  42. package/src/taskManagerFactory.ts +4 -4
@@ -4,26 +4,24 @@
4
4
  */
5
5
 
6
6
  import { EventEmitter } from "@fluid-internal/client-utils";
7
- import { ReadOnlyInfo } from "@fluidframework/container-definitions/internal";
7
+ import type { ReadOnlyInfo } from "@fluidframework/container-definitions/internal";
8
8
  import { assert, unreachableCase } from "@fluidframework/core-utils/internal";
9
- import {
9
+ import type {
10
10
  IChannelAttributes,
11
11
  IFluidDataStoreRuntime,
12
12
  IChannelStorageService,
13
13
  } from "@fluidframework/datastore-definitions/internal";
14
- import {
15
- MessageType,
16
- ISequencedDocumentMessage,
17
- } from "@fluidframework/driver-definitions/internal";
14
+ import type { ISequencedDocumentMessage } from "@fluidframework/driver-definitions/internal";
15
+ import { MessageType } from "@fluidframework/driver-definitions/internal";
18
16
  import { readAndParse } from "@fluidframework/driver-utils/internal";
19
- import { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions/internal";
17
+ import type { ISummaryTreeWithStats } from "@fluidframework/runtime-definitions/internal";
18
+ import type { IFluidSerializer } from "@fluidframework/shared-object-base/internal";
20
19
  import {
21
- IFluidSerializer,
22
20
  SharedObject,
23
21
  createSingleBlobSummary,
24
22
  } from "@fluidframework/shared-object-base/internal";
25
23
 
26
- import { ITaskManager, ITaskManagerEvents } from "./interfaces.js";
24
+ import type { ITaskManager, ITaskManagerEvents } from "./interfaces.js";
27
25
 
28
26
  /**
29
27
  * Description of a task manager operation
@@ -75,7 +73,7 @@ export class TaskManagerClass
75
73
  * Mapping of taskId to a queue of clientIds that are waiting on the task. Maintains the consensus state of the
76
74
  * queue, even if we know we've submitted an op that should eventually modify the queue.
77
75
  */
78
- private readonly taskQueues: Map<string, string[]> = new Map();
76
+ private readonly taskQueues = new Map<string, string[]>();
79
77
 
80
78
  // opWatcher emits for every op on this data store. This is just a repackaging of processCore into events.
81
79
  private readonly opWatcher: EventEmitter = new EventEmitter();
@@ -92,17 +90,17 @@ export class TaskManagerClass
92
90
  /**
93
91
  * Tracks the most recent pending op for a given task
94
92
  */
95
- private readonly latestPendingOps: Map<string, IPendingOp> = new Map();
93
+ private readonly latestPendingOps = new Map<string, IPendingOp>();
96
94
 
97
95
  /**
98
96
  * Tracks tasks that are this client is currently subscribed to.
99
97
  */
100
- private readonly subscribedTasks: Set<string> = new Set();
98
+ private readonly subscribedTasks = new Set<string>();
101
99
 
102
100
  /**
103
101
  * Map to track tasks that have pending complete ops.
104
102
  */
105
- private readonly pendingCompletedTasks: Map<string, number[]> = new Map();
103
+ private readonly pendingCompletedTasks = new Map<string, number[]>();
106
104
 
107
105
  /**
108
106
  * Returns the clientId. Will return a placeholder if the runtime is detached and not yet assigned a clientId.
@@ -125,7 +123,11 @@ export class TaskManagerClass
125
123
  * @param runtime - data store runtime the task queue belongs to
126
124
  * @param id - optional name of the task queue
127
125
  */
128
- constructor(id: string, runtime: IFluidDataStoreRuntime, attributes: IChannelAttributes) {
126
+ public constructor(
127
+ id: string,
128
+ runtime: IFluidDataStoreRuntime,
129
+ attributes: IChannelAttributes,
130
+ ) {
129
131
  super(id, runtime, attributes, "fluid_taskManager_");
130
132
 
131
133
  this.opWatcher.on(
@@ -242,7 +244,7 @@ export class TaskManagerClass
242
244
  });
243
245
  }
244
246
 
245
- private submitVolunteerOp(taskId: string) {
247
+ private submitVolunteerOp(taskId: string): void {
246
248
  const op: ITaskManagerVolunteerOperation = {
247
249
  type: "volunteer",
248
250
  taskId,
@@ -255,7 +257,7 @@ export class TaskManagerClass
255
257
  this.latestPendingOps.set(taskId, pendingOp);
256
258
  }
257
259
 
258
- private submitAbandonOp(taskId: string) {
260
+ private submitAbandonOp(taskId: string): void {
259
261
  const op: ITaskManagerAbandonOperation = {
260
262
  type: "abandon",
261
263
  taskId,
@@ -268,7 +270,7 @@ export class TaskManagerClass
268
270
  this.latestPendingOps.set(taskId, pendingOp);
269
271
  }
270
272
 
271
- private submitCompleteOp(taskId: string) {
273
+ private submitCompleteOp(taskId: string): void {
272
274
  const op: ITaskManagerCompletedOperation = {
273
275
  type: "complete",
274
276
  taskId,
@@ -291,7 +293,7 @@ export class TaskManagerClass
291
293
  /**
292
294
  * {@inheritDoc ITaskManager.volunteerForTask}
293
295
  */
294
- public async volunteerForTask(taskId: string) {
296
+ public async volunteerForTask(taskId: string): Promise<boolean> {
295
297
  // If we have the lock, resolve immediately
296
298
  if (this.assigned(taskId)) {
297
299
  return true;
@@ -318,7 +320,7 @@ export class TaskManagerClass
318
320
 
319
321
  // This promise works even if we already have an outstanding volunteer op.
320
322
  const lockAcquireP = new Promise<boolean>((resolve, reject) => {
321
- const checkIfAcquiredLock = (eventTaskId: string) => {
323
+ const checkIfAcquiredLock = (eventTaskId: string): void => {
322
324
  if (eventTaskId !== taskId) {
323
325
  return;
324
326
  }
@@ -335,7 +337,7 @@ export class TaskManagerClass
335
337
  }
336
338
  };
337
339
 
338
- const checkIfAbandoned = (eventTaskId: string) => {
340
+ const checkIfAbandoned = (eventTaskId: string): void => {
339
341
  if (eventTaskId !== taskId) {
340
342
  return;
341
343
  }
@@ -347,7 +349,7 @@ export class TaskManagerClass
347
349
  reject(new Error("Abandoned before acquiring task assignment"));
348
350
  };
349
351
 
350
- const rejectOnDisconnect = () => {
352
+ const rejectOnDisconnect = (): void => {
351
353
  this.queueWatcher.off("queueChange", checkIfAcquiredLock);
352
354
  this.abandonWatcher.off("abandon", checkIfAbandoned);
353
355
  this.connectionWatcher.off("disconnect", rejectOnDisconnect);
@@ -355,7 +357,7 @@ export class TaskManagerClass
355
357
  reject(new Error("Disconnected before acquiring task assignment"));
356
358
  };
357
359
 
358
- const checkIfCompleted = (eventTaskId: string) => {
360
+ const checkIfCompleted = (eventTaskId: string): void => {
359
361
  if (eventTaskId !== taskId) {
360
362
  return;
361
363
  }
@@ -382,7 +384,7 @@ export class TaskManagerClass
382
384
  /**
383
385
  * {@inheritDoc ITaskManager.subscribeToTask}
384
386
  */
385
- public subscribeToTask(taskId: string) {
387
+ public subscribeToTask(taskId: string): void {
386
388
  if (this.subscribed(taskId)) {
387
389
  return;
388
390
  }
@@ -391,16 +393,16 @@ export class TaskManagerClass
391
393
  throw new Error("Attempted to subscribe with read-only permissions");
392
394
  }
393
395
 
394
- const submitVolunteerOp = () => {
396
+ const submitVolunteerOp = (): void => {
395
397
  this.submitVolunteerOp(taskId);
396
398
  };
397
399
 
398
- const disconnectHandler = () => {
400
+ const disconnectHandler = (): void => {
399
401
  // Wait to be connected again and then re-submit volunteer op
400
402
  this.connectionWatcher.once("connect", submitVolunteerOp);
401
403
  };
402
404
 
403
- const checkIfAbandoned = (eventTaskId: string) => {
405
+ const checkIfAbandoned = (eventTaskId: string): void => {
404
406
  if (eventTaskId !== taskId) {
405
407
  return;
406
408
  }
@@ -413,7 +415,7 @@ export class TaskManagerClass
413
415
  this.subscribedTasks.delete(taskId);
414
416
  };
415
417
 
416
- const checkIfCompleted = (eventTaskId: string) => {
418
+ const checkIfCompleted = (eventTaskId: string): void => {
417
419
  if (eventTaskId !== taskId) {
418
420
  return;
419
421
  }
@@ -462,7 +464,7 @@ export class TaskManagerClass
462
464
  /**
463
465
  * {@inheritDoc ITaskManager.abandon}
464
466
  */
465
- public abandon(taskId: string) {
467
+ public abandon(taskId: string): void {
466
468
  // Always allow abandon if the client is subscribed to allow clients to unsubscribe while disconnected.
467
469
  // Otherwise, we should check to make sure the client is both connected queued for the task before sending an
468
470
  // abandon op.
@@ -489,7 +491,7 @@ export class TaskManagerClass
489
491
  /**
490
492
  * {@inheritDoc ITaskManager.assigned}
491
493
  */
492
- public assigned(taskId: string) {
494
+ public assigned(taskId: string): boolean {
493
495
  if (this.isAttached() && !this.connected) {
494
496
  return false;
495
497
  }
@@ -505,7 +507,7 @@ export class TaskManagerClass
505
507
  /**
506
508
  * {@inheritDoc ITaskManager.queued}
507
509
  */
508
- public queued(taskId: string) {
510
+ public queued(taskId: string): boolean {
509
511
  if (this.isAttached() && !this.connected) {
510
512
  return false;
511
513
  }
@@ -567,24 +569,24 @@ export class TaskManagerClass
567
569
  * @returns the summary of the current state of the task manager
568
570
  */
569
571
  protected summarizeCore(serializer: IFluidSerializer): ISummaryTreeWithStats {
570
- if (this.runtime.clientId !== undefined) {
571
- // If the runtime has been assigned an actual clientId by now, we can replace the placeholder clientIds
572
- // and maintain the task assignment.
573
- this.replacePlaceholderInAllQueues();
574
- } else {
572
+ if (this.runtime.clientId === undefined) {
575
573
  // If the runtime has still not been assigned a clientId, we should not summarize with the placeholder
576
574
  // clientIds and instead remove them from the queues and require the client to re-volunteer when assigned
577
575
  // a new clientId.
578
576
  this.removeClientFromAllQueues(placeholderClientId);
577
+ } else {
578
+ // If the runtime has been assigned an actual clientId by now, we can replace the placeholder clientIds
579
+ // and maintain the task assignment.
580
+ this.replacePlaceholderInAllQueues();
579
581
  }
580
582
 
581
583
  // Only include tasks if there are clients in the queue.
582
584
  const filteredMap = new Map<string, string[]>();
583
- this.taskQueues.forEach((queue: string[], taskId: string) => {
585
+ for (const [taskId, queue] of this.taskQueues) {
584
586
  if (queue.length > 0) {
585
587
  filteredMap.set(taskId, queue);
586
588
  }
587
- });
589
+ }
588
590
  const content = [...filteredMap.entries()];
589
591
  return createSingleBlobSummary(snapshotFileName, JSON.stringify(content));
590
592
  }
@@ -594,26 +596,26 @@ export class TaskManagerClass
594
596
  */
595
597
  protected async loadCore(storage: IChannelStorageService): Promise<void> {
596
598
  const content = await readAndParse<[string, string[]][]>(storage, snapshotFileName);
597
- content.forEach(([taskId, clientIdQueue]) => {
599
+ for (const [taskId, clientIdQueue] of content) {
598
600
  this.taskQueues.set(taskId, clientIdQueue);
599
- });
601
+ }
600
602
  this.scrubClientsNotInQuorum();
601
603
  }
602
604
 
603
605
  /***/
604
- protected initializeLocalCore() {}
606
+ protected initializeLocalCore(): void {}
605
607
 
606
608
  /**
607
609
  * {@inheritDoc @fluidframework/shared-object-base#SharedObject.onDisconnect}
608
610
  */
609
- protected onDisconnect() {
611
+ protected onDisconnect(): void {
610
612
  this.connectionWatcher.emit("disconnect");
611
613
  }
612
614
 
613
615
  /**
614
616
  * {@inheritDoc @fluidframework/shared-object-base#SharedObject.onConnect}
615
617
  */
616
- protected onConnect() {
618
+ protected onConnect(): void {
617
619
  this.connectionWatcher.emit("connect");
618
620
  }
619
621
 
@@ -622,7 +624,7 @@ export class TaskManagerClass
622
624
  * Override resubmit core to avoid resubmission on reconnect. On disconnect we accept our removal from the
623
625
  * queues, and leave it up to the user to decide whether they want to attempt to re-enter a queue on reconnect.
624
626
  */
625
- protected reSubmitCore() {}
627
+ protected reSubmitCore(): void {}
626
628
 
627
629
  /**
628
630
  * Process a task manager operation
@@ -636,31 +638,36 @@ export class TaskManagerClass
636
638
  message: ISequencedDocumentMessage,
637
639
  local: boolean,
638
640
  localOpMetadata: unknown,
639
- ) {
641
+ ): void {
642
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
640
643
  if (message.type === MessageType.Operation) {
641
644
  const op = message.contents as ITaskManagerOperation;
642
645
  const messageId = localOpMetadata as number;
643
646
 
644
647
  switch (op.type) {
645
- case "volunteer":
648
+ case "volunteer": {
646
649
  this.opWatcher.emit("volunteer", op.taskId, message.clientId, local, messageId);
647
650
  break;
651
+ }
648
652
 
649
- case "abandon":
653
+ case "abandon": {
650
654
  this.opWatcher.emit("abandon", op.taskId, message.clientId, local, messageId);
651
655
  break;
656
+ }
652
657
 
653
- case "complete":
658
+ case "complete": {
654
659
  this.opWatcher.emit("complete", op.taskId, message.clientId, local, messageId);
655
660
  break;
661
+ }
656
662
 
657
- default:
663
+ default: {
658
664
  throw new Error("Unknown operation");
665
+ }
659
666
  }
660
667
  }
661
668
  }
662
669
 
663
- private addClientToQueue(taskId: string, clientId: string) {
670
+ private addClientToQueue(taskId: string, clientId: string): void {
664
671
  const pendingIds = this.pendingCompletedTasks.get(taskId);
665
672
  if (pendingIds !== undefined && pendingIds.length > 0) {
666
673
  // Ignore the volunteer op if we know this task is about to be completed
@@ -688,7 +695,7 @@ export class TaskManagerClass
688
695
  }
689
696
  }
690
697
 
691
- private removeClientFromQueue(taskId: string, clientId: string) {
698
+ private removeClientFromQueue(taskId: string, clientId: string): void {
692
699
  const clientQueue = this.taskQueues.get(taskId);
693
700
  if (clientQueue === undefined) {
694
701
  return;
@@ -710,7 +717,7 @@ export class TaskManagerClass
710
717
  }
711
718
  }
712
719
 
713
- private removeClientFromAllQueues(clientId: string) {
720
+ private removeClientFromAllQueues(clientId: string): void {
714
721
  for (const taskId of this.taskQueues.keys()) {
715
722
  this.removeClientFromQueue(taskId, clientId);
716
723
  }
@@ -720,7 +727,7 @@ export class TaskManagerClass
720
727
  * Will replace all instances of the placeholderClientId with the current clientId. This should only be called when
721
728
  * transitioning from detached to attached and this.runtime.clientId is defined.
722
729
  */
723
- private replacePlaceholderInAllQueues() {
730
+ private replacePlaceholderInAllQueues(): void {
724
731
  assert(
725
732
  this.runtime.clientId !== undefined,
726
733
  0x475 /* this.runtime.clientId should be defined */,
@@ -735,7 +742,7 @@ export class TaskManagerClass
735
742
 
736
743
  // This seems like it should be unnecessary if we can trust to receive the join/leave messages and
737
744
  // also have an accurate snapshot.
738
- private scrubClientsNotInQuorum() {
745
+ private scrubClientsNotInQuorum(): void {
739
746
  const quorum = this.runtime.getQuorum();
740
747
  for (const [taskId, clientQueue] of this.taskQueues) {
741
748
  const filteredClientQueue = clientQueue.filter(
@@ -752,8 +759,8 @@ export class TaskManagerClass
752
759
  }
753
760
  }
754
761
 
755
- protected applyStashedOp(content: any): void {
756
- const taskOp: ITaskManagerOperation = content;
762
+ protected applyStashedOp(content: unknown): void {
763
+ const taskOp: ITaskManagerOperation = content as ITaskManagerOperation;
757
764
  switch (taskOp.type) {
758
765
  case "abandon": {
759
766
  this.abandon(taskOp.taskId);
@@ -767,8 +774,9 @@ export class TaskManagerClass
767
774
  this.subscribeToTask(taskOp.taskId);
768
775
  break;
769
776
  }
770
- default:
777
+ default: {
771
778
  unreachableCase(taskOp);
779
+ }
772
780
  }
773
781
  }
774
782
  }
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import {
6
+ import type {
7
7
  IChannelAttributes,
8
8
  IChannelFactory,
9
9
  IFluidDataStoreRuntime,
@@ -11,7 +11,7 @@ import {
11
11
  } from "@fluidframework/datastore-definitions/internal";
12
12
  import { createSharedObjectKind } from "@fluidframework/shared-object-base/internal";
13
13
 
14
- import { ITaskManager } from "./interfaces.js";
14
+ import type { ITaskManager } from "./interfaces.js";
15
15
  import { pkgVersion } from "./packageVersion.js";
16
16
  import { TaskManagerClass } from "./taskManager.js";
17
17
 
@@ -27,11 +27,11 @@ export class TaskManagerFactory implements IChannelFactory<ITaskManager> {
27
27
  packageVersion: pkgVersion,
28
28
  };
29
29
 
30
- public get type() {
30
+ public get type(): typeof TaskManagerFactory.Type {
31
31
  return TaskManagerFactory.Type;
32
32
  }
33
33
 
34
- public get attributes() {
34
+ public get attributes(): typeof TaskManagerFactory.Attributes {
35
35
  return TaskManagerFactory.Attributes;
36
36
  }
37
37