@fluidframework/container-runtime 2.4.0-297385 → 2.4.0-299707

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 (50) hide show
  1. package/container-runtime.test-files.tar +0 -0
  2. package/dist/containerRuntime.d.ts +8 -0
  3. package/dist/containerRuntime.d.ts.map +1 -1
  4. package/dist/containerRuntime.js +94 -111
  5. package/dist/containerRuntime.js.map +1 -1
  6. package/dist/gc/garbageCollection.d.ts +1 -1
  7. package/dist/gc/garbageCollection.d.ts.map +1 -1
  8. package/dist/gc/garbageCollection.js +2 -6
  9. package/dist/gc/garbageCollection.js.map +1 -1
  10. package/dist/opLifecycle/batchManager.d.ts +2 -0
  11. package/dist/opLifecycle/batchManager.d.ts.map +1 -1
  12. package/dist/opLifecycle/batchManager.js.map +1 -1
  13. package/dist/opLifecycle/outbox.d.ts.map +1 -1
  14. package/dist/opLifecycle/outbox.js +16 -10
  15. package/dist/opLifecycle/outbox.js.map +1 -1
  16. package/dist/packageVersion.d.ts +1 -1
  17. package/dist/packageVersion.js +1 -1
  18. package/dist/packageVersion.js.map +1 -1
  19. package/dist/pendingStateManager.d.ts +8 -2
  20. package/dist/pendingStateManager.d.ts.map +1 -1
  21. package/dist/pendingStateManager.js +14 -7
  22. package/dist/pendingStateManager.js.map +1 -1
  23. package/lib/containerRuntime.d.ts +8 -0
  24. package/lib/containerRuntime.d.ts.map +1 -1
  25. package/lib/containerRuntime.js +94 -111
  26. package/lib/containerRuntime.js.map +1 -1
  27. package/lib/gc/garbageCollection.d.ts +1 -1
  28. package/lib/gc/garbageCollection.d.ts.map +1 -1
  29. package/lib/gc/garbageCollection.js +3 -7
  30. package/lib/gc/garbageCollection.js.map +1 -1
  31. package/lib/opLifecycle/batchManager.d.ts +2 -0
  32. package/lib/opLifecycle/batchManager.d.ts.map +1 -1
  33. package/lib/opLifecycle/batchManager.js.map +1 -1
  34. package/lib/opLifecycle/outbox.d.ts.map +1 -1
  35. package/lib/opLifecycle/outbox.js +16 -10
  36. package/lib/opLifecycle/outbox.js.map +1 -1
  37. package/lib/packageVersion.d.ts +1 -1
  38. package/lib/packageVersion.js +1 -1
  39. package/lib/packageVersion.js.map +1 -1
  40. package/lib/pendingStateManager.d.ts +8 -2
  41. package/lib/pendingStateManager.d.ts.map +1 -1
  42. package/lib/pendingStateManager.js +14 -7
  43. package/lib/pendingStateManager.js.map +1 -1
  44. package/package.json +22 -21
  45. package/src/containerRuntime.ts +133 -147
  46. package/src/gc/garbageCollection.ts +5 -12
  47. package/src/opLifecycle/batchManager.ts +3 -0
  48. package/src/opLifecycle/outbox.ts +21 -10
  49. package/src/packageVersion.ts +1 -1
  50. package/src/pendingStateManager.ts +26 -8
@@ -32,16 +32,23 @@ import { ScheduleManager } from "./scheduleManager.js";
32
32
  import { DocumentsSchemaController, OrderedClientCollection, OrderedClientElection, RetriableSummaryError, RunWhileConnectedCoordinator, Summarizer, SummarizerClientElection, SummaryCollection, SummaryManager, aliasBlobName, chunksBlobName, createRootSummarizerNodeWithGC, electedSummarizerBlobName, extractSummaryMetadataMessage, idCompressorBlobName, metadataBlobName, rootHasIsolatedChannels, summarizerClientType, wrapSummaryInChannelsTree, } from "./summary/index.js";
33
33
  import { Throttler, formExponentialFn } from "./throttler.js";
34
34
  /**
35
- * Utility to implement compat behaviors given an unknown message type
35
+ * Creates an error object to be thrown / passed to Container's close fn in case of an unknown message type.
36
36
  * The parameters are typed to support compile-time enforcement of handling all known types/behaviors
37
37
  *
38
- * @param _unknownContainerRuntimeMessageType - Typed as something unexpected, to ensure all known types have been
38
+ * @param unknownContainerRuntimeMessageType - Typed as something unexpected, to ensure all known types have been
39
39
  * handled before calling this function (e.g. in a switch statement).
40
- * @param compatBehavior - Typed redundantly with CompatModeBehavior to ensure handling is added when updating that type
40
+ *
41
+ * @param codePath - The code path where the unexpected message type was encountered.
42
+ *
43
+ * @param sequencedMessage - The sequenced message that contained the unexpected message type.
44
+ *
41
45
  */
42
- function compatBehaviorAllowsMessageType(_unknownContainerRuntimeMessageType, compatBehavior) {
43
- // undefined defaults to same behavior as "FailToProcess"
44
- return compatBehavior === "Ignore";
46
+ function getUnknownMessageTypeError(unknownContainerRuntimeMessageType, codePath, sequencedMessage) {
47
+ return DataProcessingError.create("Runtime message of unknown type", codePath, sequencedMessage, {
48
+ messageDetails: {
49
+ type: unknownContainerRuntimeMessageType,
50
+ },
51
+ });
45
52
  }
46
53
  /**
47
54
  * @legacy
@@ -814,7 +821,7 @@ export class ContainerRuntime extends TypedEventEmitter {
814
821
  parentContext.submitSignal = (type, content, targetClientId) => {
815
822
  const envelope1 = content;
816
823
  const envelope2 = this.createNewSignalEnvelope(envelope1.address, type, envelope1.contents);
817
- return this.submitSignalFn(envelope2, targetClientId);
824
+ return this.submitEnvelopedSignal(envelope2, targetClientId);
818
825
  };
819
826
  let snapshot = getSummaryForDatastores(baseSnapshot, metadata);
820
827
  if (snapshot !== undefined && snapshotWithContents !== undefined) {
@@ -1389,22 +1396,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1389
1396
  // GC op is only sent in summarizer which should never have stashed ops.
1390
1397
  throw new LoggingError("GC op not expected to be stashed in summarizer");
1391
1398
  default: {
1392
- // This should be extremely rare for stashed ops.
1393
- // It would require a newer runtime stashing ops and then an older one applying them,
1394
- // e.g. if an app rolled back its container version
1395
- const compatBehavior = opContents.compatDetails?.behavior;
1396
- if (!compatBehaviorAllowsMessageType(opContents.type, compatBehavior)) {
1397
- const error = DataProcessingError.create("Stashed runtime message of unexpected type", "applyStashedOp", undefined /* sequencedMessage */, {
1398
- messageDetails: JSON.stringify({
1399
- type: opContents.type,
1400
- compatBehavior,
1401
- }),
1402
- });
1403
- this.closeFn(error);
1404
- throw error;
1405
- }
1406
- // Note: Even if its compat behavior allows it, we don't know how to apply this stashed op.
1407
- // All we can do is ignore it (similar to on process).
1399
+ const error = getUnknownMessageTypeError(opContents.type, "applyStashedOp" /* codePath */);
1400
+ this.closeFn(error);
1401
+ throw error;
1408
1402
  }
1409
1403
  }
1410
1404
  }
@@ -1724,23 +1718,9 @@ export class ContainerRuntime extends TypedEventEmitter {
1724
1718
  this.documentsSchemaController.processDocumentSchemaOp(message.contents, local, message.sequenceNumber);
1725
1719
  break;
1726
1720
  default: {
1727
- const compatBehavior = message.compatDetails?.behavior;
1728
- if (!compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
1729
- const error = DataProcessingError.create(
1730
- // Former assert 0x3ce
1731
- "Runtime message of unknown type", "OpProcessing", message, {
1732
- local,
1733
- messageDetails: JSON.stringify({
1734
- type: message.type,
1735
- contentType: typeof message.contents,
1736
- compatBehavior,
1737
- batch: message.metadata?.batch,
1738
- compression: message.compression,
1739
- }),
1740
- });
1741
- this.closeFn(error);
1742
- throw error;
1743
- }
1721
+ const error = getUnknownMessageTypeError(message.type, "validateAndProcessRuntimeMessage" /* codePath */, message);
1722
+ this.closeFn(error);
1723
+ throw error;
1744
1724
  }
1745
1725
  }
1746
1726
  this.emit("op", message, true /* runtimeMessage */);
@@ -1763,6 +1743,60 @@ export class ContainerRuntime extends TypedEventEmitter {
1763
1743
  this._signalTracking.signalTimestamp = 0;
1764
1744
  this._signalTracking.totalSignalsSentInLatencyWindow = 0;
1765
1745
  }
1746
+ /**
1747
+ * Updates signal telemetry including emitting telemetry events.
1748
+ */
1749
+ processSignalForTelemetry(envelope) {
1750
+ const { clientBroadcastSignalSequenceNumber } = envelope;
1751
+ if (clientBroadcastSignalSequenceNumber === undefined) {
1752
+ return;
1753
+ }
1754
+ if (this._signalTracking.trackingSignalSequenceNumber === undefined ||
1755
+ this._signalTracking.minimumTrackingSignalSequenceNumber === undefined) {
1756
+ return;
1757
+ }
1758
+ if (clientBroadcastSignalSequenceNumber >= this._signalTracking.trackingSignalSequenceNumber) {
1759
+ // Calculate the number of signals lost and log the event.
1760
+ const signalsLost = clientBroadcastSignalSequenceNumber -
1761
+ this._signalTracking.trackingSignalSequenceNumber;
1762
+ if (signalsLost > 0) {
1763
+ this._signalTracking.signalsLost += signalsLost;
1764
+ this.mc.logger.sendErrorEvent({
1765
+ eventName: "SignalLost",
1766
+ signalsLost, // Number of lost signals detected.
1767
+ trackingSequenceNumber: this._signalTracking.trackingSignalSequenceNumber, // The next expected signal sequence number.
1768
+ clientBroadcastSignalSequenceNumber, // Actual signal sequence number received.
1769
+ });
1770
+ }
1771
+ // Update the tracking signal sequence number to the next expected signal in the sequence.
1772
+ this._signalTracking.trackingSignalSequenceNumber =
1773
+ clientBroadcastSignalSequenceNumber + 1;
1774
+ }
1775
+ else if (
1776
+ // Check if this is a signal in range of interest.
1777
+ clientBroadcastSignalSequenceNumber >=
1778
+ this._signalTracking.minimumTrackingSignalSequenceNumber) {
1779
+ this._signalTracking.signalsOutOfOrder++;
1780
+ this.mc.logger.sendTelemetryEvent({
1781
+ eventName: "SignalOutOfOrder",
1782
+ type: envelope.contents.type, // Type of signal that was received out of order.
1783
+ trackingSequenceNumber: this._signalTracking.trackingSignalSequenceNumber, // The next expected signal sequence number.
1784
+ clientBroadcastSignalSequenceNumber, // Sequence number of the out of order signal.
1785
+ });
1786
+ }
1787
+ if (this._signalTracking.roundTripSignalSequenceNumber !== undefined &&
1788
+ clientBroadcastSignalSequenceNumber >= this._signalTracking.roundTripSignalSequenceNumber) {
1789
+ if (clientBroadcastSignalSequenceNumber ===
1790
+ this._signalTracking.roundTripSignalSequenceNumber) {
1791
+ // Latency tracked signal has been received.
1792
+ // We now log the roundtrip duration of the tracked signal.
1793
+ // This telemetry event also logs metrics for signals sent, signals lost, and out of order signals received.
1794
+ // These metrics are reset after logging the telemetry event.
1795
+ this.sendSignalTelemetryEvent();
1796
+ }
1797
+ this._signalTracking.roundTripSignalSequenceNumber = undefined;
1798
+ }
1799
+ }
1766
1800
  processSignal(message, local) {
1767
1801
  const envelope = message.content;
1768
1802
  const transformed = {
@@ -1773,52 +1807,14 @@ export class ContainerRuntime extends TypedEventEmitter {
1773
1807
  };
1774
1808
  // Only collect signal telemetry for broadcast messages sent by the current client.
1775
1809
  if (message.clientId === this.clientId &&
1776
- this.connected &&
1777
- envelope.clientBroadcastSignalSequenceNumber !== undefined) {
1778
- if (this._signalTracking.trackingSignalSequenceNumber !== undefined &&
1779
- this._signalTracking.minimumTrackingSignalSequenceNumber !== undefined) {
1780
- if (envelope.clientBroadcastSignalSequenceNumber >=
1781
- this._signalTracking.trackingSignalSequenceNumber) {
1782
- // Calculate the number of signals lost and log the event.
1783
- const signalsLost = envelope.clientBroadcastSignalSequenceNumber -
1784
- this._signalTracking.trackingSignalSequenceNumber;
1785
- if (signalsLost > 0) {
1786
- this._signalTracking.signalsLost += signalsLost;
1787
- this.mc.logger.sendErrorEvent({
1788
- eventName: "SignalLost",
1789
- signalsLost, // Number of lost signals detected.
1790
- trackingSequenceNumber: this._signalTracking.trackingSignalSequenceNumber, // The next expected signal sequence number.
1791
- clientBroadcastSignalSequenceNumber: envelope.clientBroadcastSignalSequenceNumber, // Actual signal sequence number received.
1792
- });
1793
- }
1794
- // Update the tracking signal sequence number to the next expected signal in the sequence.
1795
- this._signalTracking.trackingSignalSequenceNumber =
1796
- envelope.clientBroadcastSignalSequenceNumber + 1;
1797
- }
1798
- else if (envelope.clientBroadcastSignalSequenceNumber >=
1799
- this._signalTracking.minimumTrackingSignalSequenceNumber) {
1800
- this._signalTracking.signalsOutOfOrder++;
1801
- this.mc.logger.sendTelemetryEvent({
1802
- eventName: "SignalOutOfOrder",
1803
- type: envelope.contents.type, // Type of signal that was received out of order.
1804
- trackingSequenceNumber: this._signalTracking.trackingSignalSequenceNumber, // The next expected signal sequence number.
1805
- clientBroadcastSignalSequenceNumber: envelope.clientBroadcastSignalSequenceNumber, // Sequence number of the out of order signal.
1806
- });
1807
- }
1808
- if (this._signalTracking.roundTripSignalSequenceNumber !== undefined &&
1809
- envelope.clientBroadcastSignalSequenceNumber >=
1810
- this._signalTracking.roundTripSignalSequenceNumber) {
1811
- if (envelope.clientBroadcastSignalSequenceNumber ===
1812
- this._signalTracking.roundTripSignalSequenceNumber) {
1813
- // Latency tracked signal has been received.
1814
- // We now log the roundtrip duration of the tracked signal.
1815
- // This telemetry event also logs metrics for signals sent, signals lost, and out of order signals received.
1816
- // These metrics are reset after logging the telemetry event.
1817
- this.sendSignalTelemetryEvent();
1818
- }
1819
- this._signalTracking.roundTripSignalSequenceNumber = undefined;
1820
- }
1821
- }
1810
+ // jason-ha: This `connected` check seems incorrect. Signals that come through
1811
+ // here must have been received while connected to service and there is no need
1812
+ // to avoid processing when connection has dropped. Because container runtime's
1813
+ // `connected` (and `_connected`) state also reflects some ops state, it may
1814
+ // easily be false when newly connected and signal tracking may very well
1815
+ // complain lost signals (that were simply skipped per this check).
1816
+ this.connected) {
1817
+ this.processSignalForTelemetry(envelope);
1822
1818
  }
1823
1819
  if (envelope.address === undefined) {
1824
1820
  // No address indicates a container signal message.
@@ -1993,16 +1989,20 @@ export class ContainerRuntime extends TypedEventEmitter {
1993
1989
  }
1994
1990
  return true;
1995
1991
  }
1996
- createNewSignalEnvelope(address, type, content, targetClientId) {
1992
+ createNewSignalEnvelope(address, type, content) {
1997
1993
  const newEnvelope = {
1998
1994
  address,
1999
1995
  contents: { type, content },
2000
1996
  };
1997
+ return newEnvelope;
1998
+ }
1999
+ submitEnvelopedSignal(envelope, targetClientId) {
2001
2000
  const isBroadcastSignal = targetClientId === undefined;
2002
2001
  if (isBroadcastSignal) {
2003
2002
  const clientBroadcastSignalSequenceNumber = ++this._signalTracking
2004
2003
  .broadcastSignalSequenceNumber;
2005
- newEnvelope.clientBroadcastSignalSequenceNumber = clientBroadcastSignalSequenceNumber;
2004
+ // Stamp with the broadcast signal sequence number.
2005
+ envelope.clientBroadcastSignalSequenceNumber = clientBroadcastSignalSequenceNumber;
2006
2006
  this._signalTracking.signalsSentSinceLastLatencyMeasurement++;
2007
2007
  if (this._signalTracking.minimumTrackingSignalSequenceNumber === undefined ||
2008
2008
  this._signalTracking.trackingSignalSequenceNumber === undefined) {
@@ -2024,7 +2024,7 @@ export class ContainerRuntime extends TypedEventEmitter {
2024
2024
  this._signalTracking.signalsSentSinceLastLatencyMeasurement = 0;
2025
2025
  }
2026
2026
  }
2027
- return newEnvelope;
2027
+ this.submitSignalFn(envelope, targetClientId);
2028
2028
  }
2029
2029
  /**
2030
2030
  * Submits the signal to be sent to other clients.
@@ -2040,8 +2040,8 @@ export class ContainerRuntime extends TypedEventEmitter {
2040
2040
  */
2041
2041
  submitSignal(type, content, targetClientId) {
2042
2042
  this.verifyNotClosed();
2043
- const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content, targetClientId);
2044
- return this.submitSignalFn(envelope, targetClientId);
2043
+ const envelope = this.createNewSignalEnvelope(undefined /* address */, type, content);
2044
+ return this.submitEnvelopedSignal(envelope, targetClientId);
2045
2045
  }
2046
2046
  setAttachState(attachState) {
2047
2047
  if (attachState === AttachState.Attaching) {
@@ -2828,26 +2828,9 @@ export class ContainerRuntime extends TypedEventEmitter {
2828
2828
  // send any ops, as some other client already changed schema.
2829
2829
  break;
2830
2830
  default: {
2831
- // This case should be very rare - it would imply an op was stashed from a
2832
- // future version of runtime code and now is being applied on an older version.
2833
- const compatBehavior = message.compatDetails?.behavior;
2834
- if (compatBehaviorAllowsMessageType(message.type, compatBehavior)) {
2835
- // We do not ultimately resubmit it, to be consistent with this version of the code.
2836
- this.logger.sendTelemetryEvent({
2837
- eventName: "resubmitUnrecognizedMessageTypeAllowed",
2838
- messageDetails: { type: message.type, compatBehavior },
2839
- });
2840
- }
2841
- else {
2842
- const error = DataProcessingError.create("Resubmitting runtime message of unexpected type", "reSubmitCore", undefined /* sequencedMessage */, {
2843
- messageDetails: JSON.stringify({
2844
- type: message.type,
2845
- compatBehavior,
2846
- }),
2847
- });
2848
- this.closeFn(error);
2849
- throw error;
2850
- }
2831
+ const error = getUnknownMessageTypeError(message.type, "reSubmitCore" /* codePath */);
2832
+ this.closeFn(error);
2833
+ throw error;
2851
2834
  }
2852
2835
  }
2853
2836
  }