@fluidframework/container-runtime 0.59.4002 → 1.0.2
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/.eslintrc.js +1 -1
- package/dist/blobManager.d.ts +2 -2
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +12 -11
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.js +3 -3
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +125 -29
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +242 -110
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStoreContext.d.ts +4 -2
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +16 -5
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +4 -3
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +9 -3
- package/dist/dataStores.js.map +1 -1
- package/dist/garbageCollection.d.ts +3 -3
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +10 -8
- package/dist/garbageCollection.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/orderedClientElection.js +0 -4
- package/dist/orderedClientElection.js.map +1 -1
- 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/pendingStateManager.d.ts +30 -29
- package/dist/pendingStateManager.d.ts.map +1 -1
- package/dist/pendingStateManager.js +72 -109
- package/dist/pendingStateManager.js.map +1 -1
- package/dist/runningSummarizer.d.ts +4 -3
- package/dist/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +11 -6
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/serializedSnapshotStorage.d.ts +58 -0
- package/dist/serializedSnapshotStorage.d.ts.map +1 -0
- package/dist/serializedSnapshotStorage.js +108 -0
- package/dist/serializedSnapshotStorage.js.map +1 -0
- package/dist/summarizer.d.ts +11 -4
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +18 -9
- package/dist/summarizer.js.map +1 -1
- package/dist/summarizerHeuristics.d.ts +5 -3
- package/dist/summarizerHeuristics.d.ts.map +1 -1
- package/dist/summarizerHeuristics.js +10 -3
- package/dist/summarizerHeuristics.js.map +1 -1
- package/dist/summarizerTypes.d.ts +4 -2
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryManager.d.ts +3 -3
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +7 -7
- package/dist/summaryManager.js.map +1 -1
- package/garbageCollection.md +9 -1
- package/lib/blobManager.d.ts +2 -2
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +12 -11
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.js +3 -3
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +125 -29
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +243 -111
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStoreContext.d.ts +4 -2
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +16 -5
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +4 -3
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +9 -3
- package/lib/dataStores.js.map +1 -1
- package/lib/garbageCollection.d.ts +3 -3
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +10 -8
- package/lib/garbageCollection.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/orderedClientElection.js +0 -4
- package/lib/orderedClientElection.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/pendingStateManager.d.ts +30 -29
- package/lib/pendingStateManager.d.ts.map +1 -1
- package/lib/pendingStateManager.js +72 -109
- package/lib/pendingStateManager.js.map +1 -1
- package/lib/runningSummarizer.d.ts +4 -3
- package/lib/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +11 -6
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/serializedSnapshotStorage.d.ts +58 -0
- package/lib/serializedSnapshotStorage.d.ts.map +1 -0
- package/lib/serializedSnapshotStorage.js +104 -0
- package/lib/serializedSnapshotStorage.js.map +1 -0
- package/lib/summarizer.d.ts +11 -4
- package/lib/summarizer.d.ts.map +1 -1
- package/lib/summarizer.js +18 -9
- package/lib/summarizer.js.map +1 -1
- package/lib/summarizerHeuristics.d.ts +5 -3
- package/lib/summarizerHeuristics.d.ts.map +1 -1
- package/lib/summarizerHeuristics.js +10 -3
- package/lib/summarizerHeuristics.js.map +1 -1
- package/lib/summarizerTypes.d.ts +4 -2
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryManager.d.ts +3 -3
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +7 -7
- package/lib/summaryManager.js.map +1 -1
- package/package.json +46 -31
- package/src/blobManager.ts +29 -15
- package/src/connectionTelemetry.ts +3 -3
- package/src/containerRuntime.ts +388 -135
- package/src/dataStoreContext.ts +27 -5
- package/src/dataStores.ts +15 -3
- package/src/garbageCollection.ts +21 -14
- package/src/index.ts +7 -1
- package/src/orderedClientElection.ts +1 -1
- package/src/packageVersion.ts +1 -1
- package/src/pendingStateManager.ts +104 -123
- package/src/runningSummarizer.ts +20 -10
- package/src/serializedSnapshotStorage.ts +146 -0
- package/src/summarizer.ts +20 -16
- package/src/summarizerHeuristics.ts +21 -5
- package/src/summarizerTypes.ts +4 -2
- package/src/summaryManager.ts +5 -6
package/src/runningSummarizer.ts
CHANGED
|
@@ -8,17 +8,18 @@ import { assert, delay, Deferred, PromiseTimer } from "@fluidframework/common-ut
|
|
|
8
8
|
import { UsageError } from "@fluidframework/container-utils";
|
|
9
9
|
import {
|
|
10
10
|
ISequencedDocumentMessage,
|
|
11
|
-
ISummaryConfiguration,
|
|
12
11
|
MessageType,
|
|
13
12
|
} from "@fluidframework/protocol-definitions";
|
|
14
13
|
import { ChildLogger } from "@fluidframework/telemetry-utils";
|
|
14
|
+
import {
|
|
15
|
+
ISummaryConfiguration,
|
|
16
|
+
} from "./containerRuntime";
|
|
15
17
|
import { SummarizeHeuristicRunner } from "./summarizerHeuristics";
|
|
16
18
|
import {
|
|
17
19
|
IEnqueueSummarizeOptions,
|
|
18
20
|
ISummarizeOptions,
|
|
19
21
|
ISummarizeHeuristicData,
|
|
20
22
|
ISummarizeHeuristicRunner,
|
|
21
|
-
ISummarizerOptions,
|
|
22
23
|
IOnDemandSummarizeOptions,
|
|
23
24
|
EnqueueSummarizeResult,
|
|
24
25
|
SummarizerStopReason,
|
|
@@ -57,7 +58,6 @@ export class RunningSummarizer implements IDisposable {
|
|
|
57
58
|
summaryCollection: SummaryCollection,
|
|
58
59
|
cancellationToken: ISummaryCancellationToken,
|
|
59
60
|
stopSummarizerCallback: (reason: SummarizerStopReason) => void,
|
|
60
|
-
options?: Readonly<Partial<ISummarizerOptions>>,
|
|
61
61
|
): Promise<RunningSummarizer> {
|
|
62
62
|
const summarizer = new RunningSummarizer(
|
|
63
63
|
logger,
|
|
@@ -68,8 +68,7 @@ export class RunningSummarizer implements IDisposable {
|
|
|
68
68
|
raiseSummarizingError,
|
|
69
69
|
summaryCollection,
|
|
70
70
|
cancellationToken,
|
|
71
|
-
stopSummarizerCallback
|
|
72
|
-
options);
|
|
71
|
+
stopSummarizerCallback);
|
|
73
72
|
|
|
74
73
|
await summarizer.waitStart();
|
|
75
74
|
|
|
@@ -107,7 +106,6 @@ export class RunningSummarizer implements IDisposable {
|
|
|
107
106
|
private readonly summaryCollection: SummaryCollection,
|
|
108
107
|
private readonly cancellationToken: ISummaryCancellationToken,
|
|
109
108
|
private readonly stopSummarizerCallback: (reason: SummarizerStopReason) => void,
|
|
110
|
-
{ disableHeuristics = false }: Readonly<Partial<ISummarizerOptions>> = {},
|
|
111
109
|
) {
|
|
112
110
|
const telemetryProps: ISummarizeRunnerTelemetry = {
|
|
113
111
|
summarizeCount: () => this.summarizeCount,
|
|
@@ -121,15 +119,23 @@ export class RunningSummarizer implements IDisposable {
|
|
|
121
119
|
},
|
|
122
120
|
);
|
|
123
121
|
|
|
124
|
-
if (
|
|
122
|
+
if (configuration.state !== "disableHeuristics") {
|
|
123
|
+
assert(this.configuration.state === "enabled", 0x2ea /* "Configuration state should be enabled" */);
|
|
125
124
|
this.heuristicRunner = new SummarizeHeuristicRunner(
|
|
126
125
|
heuristicData,
|
|
127
|
-
configuration,
|
|
128
|
-
(reason) => this.trySummarize(reason)
|
|
126
|
+
this.configuration,
|
|
127
|
+
(reason) => this.trySummarize(reason),
|
|
128
|
+
this.logger);
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
assert(
|
|
132
|
+
this.configuration.state !== "disabled",
|
|
133
|
+
0x2eb /* "Summary not supported with configuration disabled" */,
|
|
134
|
+
);
|
|
135
|
+
|
|
131
136
|
// Cap the maximum amount of time client will wait for a summarize op ack to maxSummarizeAckWaitTime
|
|
132
137
|
// configuration.maxAckWaitTime is composed from defaults, server values, and runtime overrides
|
|
138
|
+
|
|
133
139
|
const maxAckWaitTime = Math.min(this.configuration.maxAckWaitTime, maxSummarizeAckWaitTime);
|
|
134
140
|
|
|
135
141
|
this.pendingAckTimer = new PromiseTimer(
|
|
@@ -360,7 +366,11 @@ export class RunningSummarizer implements IDisposable {
|
|
|
360
366
|
return;
|
|
361
367
|
}
|
|
362
368
|
|
|
363
|
-
|
|
369
|
+
// We only want to attempt 1 summary when reason is "lastSummary"
|
|
370
|
+
if (++summaryAttempts > 1 && reason === "lastSummary") {
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
364
374
|
summaryAttemptsPerPhase++;
|
|
365
375
|
|
|
366
376
|
const { delaySeconds: regularDelaySeconds = 0, ...options } = attempts[summaryAttemptPhase];
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) Microsoft Corporation and contributors. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { assert, bufferToString, stringToBuffer } from "@fluidframework/common-utils";
|
|
7
|
+
import { IDocumentStorageService, ISummaryContext } from "@fluidframework/driver-definitions";
|
|
8
|
+
import {
|
|
9
|
+
ICreateBlobResponse,
|
|
10
|
+
ISnapshotTree,
|
|
11
|
+
ISummaryHandle,
|
|
12
|
+
ISummaryTree,
|
|
13
|
+
IVersion,
|
|
14
|
+
} from "@fluidframework/protocol-definitions";
|
|
15
|
+
import { ISnapshotTreeWithBlobContents } from "@fluidframework/container-definitions";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Serialized blobs from a snapshot. Used to load offline.
|
|
19
|
+
*/
|
|
20
|
+
export interface ISerializedBaseSnapshotBlobs {
|
|
21
|
+
[id: string]: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A storage wrapper that can serialize blobs from a snapshot tree and then use them to rehydrate.
|
|
26
|
+
* Used in offline load/attached dehydration to save snapshot blobs that are still needed but may have been deleted.
|
|
27
|
+
*/
|
|
28
|
+
export class SerializedSnapshotStorage implements IDocumentStorageService {
|
|
29
|
+
constructor(
|
|
30
|
+
private readonly storageGetter: () => IDocumentStorageService,
|
|
31
|
+
private readonly blobs: ISerializedBaseSnapshotBlobs,
|
|
32
|
+
) { }
|
|
33
|
+
|
|
34
|
+
public static async serializeTree(
|
|
35
|
+
snapshot: ISnapshotTree,
|
|
36
|
+
storage: IDocumentStorageService,
|
|
37
|
+
): Promise<ISerializedBaseSnapshotBlobs> {
|
|
38
|
+
const blobs = {};
|
|
39
|
+
await this.serializeTreeCore(snapshot, blobs, storage);
|
|
40
|
+
return blobs;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private static async serializeTreeCore(
|
|
44
|
+
tree: ISnapshotTree,
|
|
45
|
+
blobs: ISerializedBaseSnapshotBlobs,
|
|
46
|
+
storage: IDocumentStorageService,
|
|
47
|
+
) {
|
|
48
|
+
const treePs: Promise<any>[] = [];
|
|
49
|
+
for (const subTree of Object.values(tree.trees)) {
|
|
50
|
+
treePs.push(this.serializeTreeCore(subTree, blobs, storage));
|
|
51
|
+
}
|
|
52
|
+
for (const id of Object.values(tree.blobs)) {
|
|
53
|
+
const blob = await storage.readBlob(id);
|
|
54
|
+
// ArrayBufferLike will not survive JSON.stringify()
|
|
55
|
+
blobs[id] = bufferToString(blob, "utf8");
|
|
56
|
+
}
|
|
57
|
+
return Promise.all(treePs);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public static serializeTreeWithBlobContents(
|
|
61
|
+
snapshot: ISnapshotTreeWithBlobContents,
|
|
62
|
+
): ISerializedBaseSnapshotBlobs {
|
|
63
|
+
const blobs = {};
|
|
64
|
+
this.serializeTreeWithBlobContentsCore(snapshot, blobs);
|
|
65
|
+
return blobs;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private static serializeTreeWithBlobContentsCore(
|
|
69
|
+
tree: ISnapshotTreeWithBlobContents,
|
|
70
|
+
blobs: ISerializedBaseSnapshotBlobs,
|
|
71
|
+
) {
|
|
72
|
+
for (const subTree of Object.values(tree.trees)) {
|
|
73
|
+
this.serializeTreeWithBlobContentsCore(subTree, blobs);
|
|
74
|
+
}
|
|
75
|
+
for (const id of Object.values(tree.blobs)) {
|
|
76
|
+
const blob = tree.blobsContents[id];
|
|
77
|
+
assert(!!blob, 0x2ec /* "Blob must be present in blobsContents" */);
|
|
78
|
+
// ArrayBufferLike will not survive JSON.stringify()
|
|
79
|
+
blobs[id] = bufferToString(blob, "utf8");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private _storage?: IDocumentStorageService;
|
|
84
|
+
private get storage(): IDocumentStorageService {
|
|
85
|
+
// avoid calling it until we need it since it will be undefined if we're not connected
|
|
86
|
+
// and we shouldn't need it in this case anyway
|
|
87
|
+
if (this._storage) {
|
|
88
|
+
return this._storage;
|
|
89
|
+
}
|
|
90
|
+
this._storage = this.storageGetter();
|
|
91
|
+
return this._storage;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public get repositoryUrl(): string { return this.storage.repositoryUrl; }
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Reads the object with the given ID, returns content in arrayBufferLike
|
|
98
|
+
*/
|
|
99
|
+
public async readBlob(id: string): Promise<ArrayBufferLike> {
|
|
100
|
+
if (this.blobs[id] !== undefined) {
|
|
101
|
+
return stringToBuffer(this.blobs[id], "utf8");
|
|
102
|
+
}
|
|
103
|
+
return this.storage.readBlob(id);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Returns the snapshot tree.
|
|
108
|
+
*/
|
|
109
|
+
// eslint-disable-next-line @rushstack/no-new-null
|
|
110
|
+
public async getSnapshotTree(version?: IVersion): Promise<ISnapshotTree | null> {
|
|
111
|
+
return this.storage.getSnapshotTree(version);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Retrieves all versions of the document starting at the specified versionId - or null if from the head
|
|
116
|
+
*/
|
|
117
|
+
// eslint-disable-next-line @rushstack/no-new-null
|
|
118
|
+
public async getVersions(versionId: string | null, count: number): Promise<IVersion[]> {
|
|
119
|
+
return this.storage.getVersions(versionId, count);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Creates a blob out of the given buffer
|
|
124
|
+
*/
|
|
125
|
+
public async createBlob(file: ArrayBufferLike): Promise<ICreateBlobResponse> {
|
|
126
|
+
return this.storage.createBlob(file);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Uploads a summary tree to storage using the given context for reference of previous summary handle.
|
|
131
|
+
* The ISummaryHandles in the uploaded tree should have paths to indicate which summary object they are
|
|
132
|
+
* referencing from the previously acked summary.
|
|
133
|
+
* Returns the uploaded summary handle.
|
|
134
|
+
*/
|
|
135
|
+
public async uploadSummaryWithContext(summary: ISummaryTree, context: ISummaryContext): Promise<string> {
|
|
136
|
+
return this.storage.uploadSummaryWithContext(summary, context);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Retrieves the commit that matches the packfile handle. If the packfile has already been committed and the
|
|
141
|
+
* server has deleted it this call may result in a broken promise.
|
|
142
|
+
*/
|
|
143
|
+
public async downloadSummary(handle: ISummaryHandle): Promise<ISummaryTree> {
|
|
144
|
+
return this.storage.downloadSummary(handle);
|
|
145
|
+
}
|
|
146
|
+
}
|
package/src/summarizer.ts
CHANGED
|
@@ -19,8 +19,8 @@ import {
|
|
|
19
19
|
} from "@fluidframework/core-interfaces";
|
|
20
20
|
import {
|
|
21
21
|
ISequencedDocumentMessage,
|
|
22
|
-
ISummaryConfiguration,
|
|
23
22
|
} from "@fluidframework/protocol-definitions";
|
|
23
|
+
import { ISummaryConfiguration } from "./containerRuntime";
|
|
24
24
|
import { ICancellableSummarizerController } from "./runWhileConnectedCoordinator";
|
|
25
25
|
import { summarizerClientType } from "./summarizerClientElection";
|
|
26
26
|
import { SummaryCollection } from "./summaryCollection";
|
|
@@ -29,7 +29,6 @@ import { RunningSummarizer } from "./runningSummarizer";
|
|
|
29
29
|
import {
|
|
30
30
|
ISummarizer,
|
|
31
31
|
ISummarizerInternalsProvider,
|
|
32
|
-
ISummarizerOptions,
|
|
33
32
|
ISummarizerRuntime,
|
|
34
33
|
ISummarizingWarning,
|
|
35
34
|
SummarizerStopReason,
|
|
@@ -136,11 +135,9 @@ export class Summarizer extends EventEmitter implements ISummarizer {
|
|
|
136
135
|
return fluidObject.ISummarizer;
|
|
137
136
|
}
|
|
138
137
|
|
|
139
|
-
public async run(
|
|
140
|
-
onBehalfOf: string,
|
|
141
|
-
options?: Readonly<Partial<ISummarizerOptions>>): Promise<SummarizerStopReason> {
|
|
138
|
+
public async run(onBehalfOf: string): Promise<SummarizerStopReason> {
|
|
142
139
|
try {
|
|
143
|
-
return await this.runCore(onBehalfOf
|
|
140
|
+
return await this.runCore(onBehalfOf);
|
|
144
141
|
} catch (error) {
|
|
145
142
|
this.stop("summarizerException");
|
|
146
143
|
throw SummarizingWarning.wrap(error, false /* logged */, this.logger);
|
|
@@ -165,9 +162,7 @@ export class Summarizer extends EventEmitter implements ISummarizer {
|
|
|
165
162
|
this.runtime.closeFn();
|
|
166
163
|
}
|
|
167
164
|
|
|
168
|
-
private async runCore(
|
|
169
|
-
onBehalfOf: string,
|
|
170
|
-
options?: Readonly<Partial<ISummarizerOptions>>): Promise<SummarizerStopReason> {
|
|
165
|
+
private async runCore(onBehalfOf: string): Promise<SummarizerStopReason> {
|
|
171
166
|
const runCoordinator: ICancellableSummarizerController = await this.runCoordinatorCreateFn(this.runtime);
|
|
172
167
|
|
|
173
168
|
// Wait for either external signal to cancel, or loss of connectivity.
|
|
@@ -184,7 +179,7 @@ export class Summarizer extends EventEmitter implements ISummarizer {
|
|
|
184
179
|
return runCoordinator.waitCancelled;
|
|
185
180
|
}
|
|
186
181
|
|
|
187
|
-
const runningSummarizer = await this.start(onBehalfOf, runCoordinator
|
|
182
|
+
const runningSummarizer = await this.start(onBehalfOf, runCoordinator);
|
|
188
183
|
|
|
189
184
|
// Wait for either external signal to cancel, or loss of connectivity.
|
|
190
185
|
const stopReason = await stopP;
|
|
@@ -206,7 +201,8 @@ export class Summarizer extends EventEmitter implements ISummarizer {
|
|
|
206
201
|
// cons of #2 substantially.
|
|
207
202
|
|
|
208
203
|
// Cleanup after running
|
|
209
|
-
await runningSummarizer.waitStop(
|
|
204
|
+
await runningSummarizer.waitStop(
|
|
205
|
+
!runCoordinator.cancelled && Summarizer.stopReasonCanRunLastSummary(stopReason));
|
|
210
206
|
|
|
211
207
|
// Propagate reason and ensure that if someone is waiting for cancellation token, they are moving to exit
|
|
212
208
|
runCoordinator.stop(stopReason);
|
|
@@ -214,19 +210,28 @@ export class Summarizer extends EventEmitter implements ISummarizer {
|
|
|
214
210
|
return stopReason;
|
|
215
211
|
}
|
|
216
212
|
|
|
213
|
+
/**
|
|
214
|
+
* Should we try to run a last summary for the given stop reason?
|
|
215
|
+
* Currently only allows "parentNotConnected"
|
|
216
|
+
* @param stopReason - SummarizerStopReason
|
|
217
|
+
* @returns - true if the stop reason can run a last summary
|
|
218
|
+
*/
|
|
219
|
+
public static stopReasonCanRunLastSummary(stopReason: SummarizerStopReason): boolean {
|
|
220
|
+
return stopReason === "parentNotConnected";
|
|
221
|
+
}
|
|
222
|
+
|
|
217
223
|
/**
|
|
218
224
|
* Put the summarizer in a started state, including creating and initializing the RunningSummarizer.
|
|
219
225
|
* The start request can come either from the SummaryManager (in the auto-summarize case) or from the user
|
|
220
226
|
* (in the on-demand case).
|
|
221
227
|
* @param onBehalfOf - ID of the client that requested that the summarizer start
|
|
222
228
|
* @param runCoordinator - cancellation token
|
|
223
|
-
* @param
|
|
229
|
+
* @param newConfig - Summary configuration to override the existing config when invoking the RunningSummarizer.
|
|
224
230
|
* @returns - Promise that is fulfilled when the RunningSummarizer is ready
|
|
225
231
|
*/
|
|
226
232
|
private async start(
|
|
227
233
|
onBehalfOf: string,
|
|
228
|
-
runCoordinator: ICancellableSummarizerController
|
|
229
|
-
options?: Readonly<Partial<ISummarizerOptions>>): Promise<RunningSummarizer> {
|
|
234
|
+
runCoordinator: ICancellableSummarizerController): Promise<RunningSummarizer> {
|
|
230
235
|
if (this.runningSummarizer) {
|
|
231
236
|
if (this.runningSummarizer.disposed) {
|
|
232
237
|
throw new UsageError("Starting a disposed summarizer");
|
|
@@ -272,7 +277,6 @@ export class Summarizer extends EventEmitter implements ISummarizer {
|
|
|
272
277
|
this.summaryCollection,
|
|
273
278
|
runCoordinator /* cancellationToken */,
|
|
274
279
|
(reason) => runCoordinator.stop(reason), /* stopSummarizerCallback */
|
|
275
|
-
options,
|
|
276
280
|
);
|
|
277
281
|
this.runningSummarizer = runningSummarizer;
|
|
278
282
|
this.starting = false;
|
|
@@ -343,7 +347,7 @@ export class Summarizer extends EventEmitter implements ISummarizer {
|
|
|
343
347
|
coordinatorCreateP.then((runCoordinator) => {
|
|
344
348
|
// Successully created the cancellation token. Start the summarizer.
|
|
345
349
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
346
|
-
const startP = this.start(this.runtime.clientId!, runCoordinator
|
|
350
|
+
const startP = this.start(this.runtime.clientId!, runCoordinator);
|
|
347
351
|
startP.then(async (runningSummarizer) => {
|
|
348
352
|
// Successfully started the summarizer. Run it.
|
|
349
353
|
runningSummarizer.summarizeOnDemand(builder, ...args);
|
|
@@ -3,9 +3,15 @@
|
|
|
3
3
|
* Licensed under the MIT License.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
6
7
|
import { Timer } from "@fluidframework/common-utils";
|
|
7
|
-
import {
|
|
8
|
-
|
|
8
|
+
import { ISummaryConfigurationHeuristics } from "./containerRuntime";
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
ISummarizeHeuristicData,
|
|
12
|
+
ISummarizeHeuristicRunner,
|
|
13
|
+
ISummarizeAttempt,
|
|
14
|
+
} from "./summarizerTypes";
|
|
9
15
|
import { SummarizeReason } from "./summaryGenerator";
|
|
10
16
|
|
|
11
17
|
/** Simple implementation of class for tracking summarize heuristic data. */
|
|
@@ -51,16 +57,18 @@ export class SummarizeHeuristicData implements ISummarizeHeuristicData {
|
|
|
51
57
|
*/
|
|
52
58
|
export class SummarizeHeuristicRunner implements ISummarizeHeuristicRunner {
|
|
53
59
|
private readonly idleTimer: Timer;
|
|
60
|
+
private readonly minOpsForLastSummaryAttempt: number;
|
|
54
61
|
|
|
55
62
|
public constructor(
|
|
56
63
|
private readonly heuristicData: ISummarizeHeuristicData,
|
|
57
|
-
private readonly configuration:
|
|
64
|
+
private readonly configuration: ISummaryConfigurationHeuristics,
|
|
58
65
|
private readonly trySummarize: (reason: SummarizeReason) => void,
|
|
59
|
-
private readonly
|
|
66
|
+
private readonly logger: ITelemetryLogger,
|
|
60
67
|
) {
|
|
61
68
|
this.idleTimer = new Timer(
|
|
62
69
|
this.configuration.idleTime,
|
|
63
70
|
() => this.trySummarize("idle"));
|
|
71
|
+
this.minOpsForLastSummaryAttempt = this.configuration.minOpsForLastSummaryAttempt;
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
public get opsSinceLastAck(): number {
|
|
@@ -83,7 +91,15 @@ export class SummarizeHeuristicRunner implements ISummarizeHeuristicRunner {
|
|
|
83
91
|
|
|
84
92
|
public shouldRunLastSummary(): boolean {
|
|
85
93
|
const opsSinceLastAck = this.opsSinceLastAck;
|
|
86
|
-
|
|
94
|
+
const minOpsForLastSummaryAttempt = this.minOpsForLastSummaryAttempt;
|
|
95
|
+
|
|
96
|
+
this.logger.sendTelemetryEvent({
|
|
97
|
+
eventName: "ShouldRunLastSummary",
|
|
98
|
+
opsSinceLastAck,
|
|
99
|
+
minOpsForLastSummaryAttempt,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
return opsSinceLastAck >= minOpsForLastSummaryAttempt;
|
|
87
103
|
}
|
|
88
104
|
|
|
89
105
|
public dispose() {
|
package/src/summarizerTypes.ts
CHANGED
|
@@ -67,7 +67,9 @@ export interface ISummarizerInternalsProvider {
|
|
|
67
67
|
): Promise<void>;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
/**
|
|
70
|
+
/**
|
|
71
|
+
* @deprecated Options that control the behavior of a running summarizer.
|
|
72
|
+
* */
|
|
71
73
|
export interface ISummarizerOptions {
|
|
72
74
|
/**
|
|
73
75
|
* Set to true to disable the default heuristics from running; false by default.
|
|
@@ -309,7 +311,7 @@ export interface ISummarizer extends
|
|
|
309
311
|
/* Closes summarizer. Any pending processes (summary in flight) are abandoned. */
|
|
310
312
|
close(): void;
|
|
311
313
|
|
|
312
|
-
run(onBehalfOf: string,
|
|
314
|
+
run(onBehalfOf: string, disableHeuristics?: boolean): Promise<SummarizerStopReason>;
|
|
313
315
|
|
|
314
316
|
/**
|
|
315
317
|
* Attempts to generate a summary on demand. If already running, takes no action.
|
package/src/summaryManager.ts
CHANGED
|
@@ -11,7 +11,6 @@ import { ISummarizerClientElection } from "./summarizerClientElection";
|
|
|
11
11
|
import { IThrottler } from "./throttler";
|
|
12
12
|
import {
|
|
13
13
|
ISummarizer,
|
|
14
|
-
ISummarizerOptions,
|
|
15
14
|
SummarizerStopReason,
|
|
16
15
|
} from "./summarizerTypes";
|
|
17
16
|
import { SummaryCollection } from "./summaryCollection";
|
|
@@ -97,7 +96,7 @@ export class SummaryManager implements IDisposable {
|
|
|
97
96
|
initialDelayMs = defaultInitialDelayMs,
|
|
98
97
|
opsToBypassInitialDelay = defaultOpsToBypassInitialDelay,
|
|
99
98
|
}: Readonly<Partial<ISummaryManagerConfig>> = {},
|
|
100
|
-
private readonly
|
|
99
|
+
private readonly disableHeuristics?: boolean,
|
|
101
100
|
) {
|
|
102
101
|
this.logger = ChildLogger.create(
|
|
103
102
|
parentLogger,
|
|
@@ -141,12 +140,12 @@ export class SummaryManager implements IDisposable {
|
|
|
141
140
|
// enforce connectedState.clientId === clientElection.electedClientId. But once we're Running, we should
|
|
142
141
|
// only transition to Stopping when the electedParentId changes. Stopping the summarizer without
|
|
143
142
|
// changing the electedParent will just cause us to transition to Starting again.
|
|
144
|
-
if (
|
|
145
|
-
return { shouldSummarize: false, stopReason: "parentNotConnected" };
|
|
146
|
-
} else if (this.connectedState.clientId !== this.clientElection.electedParentId ||
|
|
143
|
+
if (this.connectedState.clientId !== this.clientElection.electedParentId ||
|
|
147
144
|
(this.state !== SummaryManagerState.Running &&
|
|
148
145
|
this.connectedState.clientId !== this.clientElection.electedClientId)) {
|
|
149
146
|
return { shouldSummarize: false, stopReason: "parentShouldNotSummarize" };
|
|
147
|
+
} else if (!this.connectedState.connected) {
|
|
148
|
+
return { shouldSummarize: false, stopReason: "parentNotConnected" };
|
|
150
149
|
} else if (this.disposed) {
|
|
151
150
|
assert(false, 0x260 /* "Disposed should mean disconnected!" */);
|
|
152
151
|
} else {
|
|
@@ -227,7 +226,7 @@ export class SummaryManager implements IDisposable {
|
|
|
227
226
|
return PerformanceEvent.timedExecAsync(
|
|
228
227
|
this.logger,
|
|
229
228
|
{ eventName: "RunningSummarizer", attempt: this.startThrottler.numAttempts },
|
|
230
|
-
async () => summarizer.run(clientId, this.
|
|
229
|
+
async () => summarizer.run(clientId, this.disableHeuristics),
|
|
231
230
|
);
|
|
232
231
|
}).then((reason: string) => {
|
|
233
232
|
this.logger.sendTelemetryEvent({
|