@fluidframework/container-runtime 0.48.5 → 0.49.1
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/dist/containerRuntime.d.ts +1 -7
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +3 -13
- package/dist/containerRuntime.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/runningSummarizer.d.ts.map +1 -1
- package/dist/runningSummarizer.js +8 -3
- package/dist/runningSummarizer.js.map +1 -1
- package/dist/summarizer.d.ts.map +1 -1
- package/dist/summarizer.js +1 -1
- package/dist/summarizer.js.map +1 -1
- package/dist/summarizerTypes.d.ts +11 -7
- package/dist/summarizerTypes.d.ts.map +1 -1
- package/dist/summarizerTypes.js.map +1 -1
- package/dist/summaryCollection.d.ts +2 -0
- package/dist/summaryCollection.d.ts.map +1 -1
- package/dist/summaryCollection.js +6 -0
- package/dist/summaryCollection.js.map +1 -1
- package/dist/summaryGenerator.d.ts +5 -5
- package/dist/summaryGenerator.d.ts.map +1 -1
- package/dist/summaryGenerator.js +5 -6
- package/dist/summaryGenerator.js.map +1 -1
- package/dist/summaryManager.d.ts +1 -1
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +23 -12
- package/dist/summaryManager.js.map +1 -1
- package/lib/containerRuntime.d.ts +1 -7
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +3 -13
- package/lib/containerRuntime.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/runningSummarizer.d.ts.map +1 -1
- package/lib/runningSummarizer.js +8 -3
- package/lib/runningSummarizer.js.map +1 -1
- package/lib/summarizer.d.ts.map +1 -1
- package/lib/summarizer.js +1 -1
- package/lib/summarizer.js.map +1 -1
- package/lib/summarizerTypes.d.ts +11 -7
- package/lib/summarizerTypes.d.ts.map +1 -1
- package/lib/summarizerTypes.js.map +1 -1
- package/lib/summaryCollection.d.ts +2 -0
- package/lib/summaryCollection.d.ts.map +1 -1
- package/lib/summaryCollection.js +6 -0
- package/lib/summaryCollection.js.map +1 -1
- package/lib/summaryGenerator.d.ts +5 -5
- package/lib/summaryGenerator.d.ts.map +1 -1
- package/lib/summaryGenerator.js +6 -7
- package/lib/summaryGenerator.js.map +1 -1
- package/lib/summaryManager.d.ts +1 -1
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +24 -13
- package/lib/summaryManager.js.map +1 -1
- package/package.json +15 -15
- package/src/containerRuntime.ts +3 -12
- package/src/packageVersion.ts +1 -1
- package/src/runningSummarizer.ts +11 -3
- package/src/summarizer.ts +1 -0
- package/src/summarizerTypes.ts +12 -6
- package/src/summaryCollection.ts +8 -0
- package/src/summaryGenerator.ts +18 -11
- package/src/summaryManager.ts +25 -13
package/src/containerRuntime.ts
CHANGED
|
@@ -1571,15 +1571,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1571
1571
|
this.context.raiseContainerWarning(warning);
|
|
1572
1572
|
};
|
|
1573
1573
|
|
|
1574
|
-
/**
|
|
1575
|
-
* @deprecated - // back-compat: marked deprecated in 0.35
|
|
1576
|
-
* Returns true of document is dirty, i.e. there are some pending local changes that
|
|
1577
|
-
* either were not sent out to delta stream or were not yet acknowledged.
|
|
1578
|
-
*/
|
|
1579
|
-
public isDocumentDirty(): boolean {
|
|
1580
|
-
return this.dirtyContainer;
|
|
1581
|
-
}
|
|
1582
|
-
|
|
1583
1574
|
/**
|
|
1584
1575
|
* Returns true of container is dirty, i.e. there are some pending local changes that
|
|
1585
1576
|
* either were not sent out to delta stream or were not yet acknowledged.
|
|
@@ -1998,9 +1989,6 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
1998
1989
|
|
|
1999
1990
|
this.dirtyContainer = dirty;
|
|
2000
1991
|
if (this.emitDirtyDocumentEvent) {
|
|
2001
|
-
// back-compat: dirtyDocument & savedDocument deprecated in 0.35.
|
|
2002
|
-
this.emit(dirty ? "dirtyDocument" : "savedDocument");
|
|
2003
|
-
|
|
2004
1992
|
this.emit(dirty ? "dirty" : "saved");
|
|
2005
1993
|
// back-compat: Loader API added in 0.35 only
|
|
2006
1994
|
if (this.context.updateDirtyContainerState !== undefined) {
|
|
@@ -2194,11 +2182,13 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2194
2182
|
public async refreshLatestSummaryAck(
|
|
2195
2183
|
proposalHandle: string | undefined,
|
|
2196
2184
|
ackHandle: string,
|
|
2185
|
+
summaryRefSeq: number,
|
|
2197
2186
|
summaryLogger: ITelemetryLogger,
|
|
2198
2187
|
) {
|
|
2199
2188
|
const readAndParseBlob = async <T>(id: string) => readAndParse<T>(this.storage, id);
|
|
2200
2189
|
const result = await this.summarizerNode.refreshLatestSummary(
|
|
2201
2190
|
proposalHandle,
|
|
2191
|
+
summaryRefSeq,
|
|
2202
2192
|
async () => this.fetchSnapshotFromStorage(ackHandle, summaryLogger, {
|
|
2203
2193
|
eventName: "RefreshLatestSummaryGetSnapshot",
|
|
2204
2194
|
fetchLatest: false,
|
|
@@ -2238,6 +2228,7 @@ export class ContainerRuntime extends TypedEventEmitter<IContainerRuntimeEvents>
|
|
|
2238
2228
|
|
|
2239
2229
|
const result = await this.summarizerNode.refreshLatestSummary(
|
|
2240
2230
|
undefined,
|
|
2231
|
+
snapshotRefSeq,
|
|
2241
2232
|
async () => snapshot,
|
|
2242
2233
|
readAndParseBlob,
|
|
2243
2234
|
summaryLogger,
|
package/src/packageVersion.ts
CHANGED
package/src/runningSummarizer.ts
CHANGED
|
@@ -346,6 +346,8 @@ export class RunningSummarizer implements IDisposable {
|
|
|
346
346
|
let totalAttempts = 0;
|
|
347
347
|
let attemptPerPhase = 0;
|
|
348
348
|
|
|
349
|
+
let lastResult: { message: string; error: any; } | undefined;
|
|
350
|
+
|
|
349
351
|
for (let attemptPhase = 0; attemptPhase < attempts.length;) {
|
|
350
352
|
if (this.cancellationToken.cancelled) {
|
|
351
353
|
return;
|
|
@@ -378,7 +380,6 @@ export class RunningSummarizer implements IDisposable {
|
|
|
378
380
|
const result = await resultSummarize.receivedSummaryAckOrNack;
|
|
379
381
|
|
|
380
382
|
if (result.success) {
|
|
381
|
-
assert(result.data.summaryAckNackOp.type === MessageType.SummaryAck, 0x25c /* "not nack" */);
|
|
382
383
|
return;
|
|
383
384
|
}
|
|
384
385
|
// Check for retryDelay that can come from summaryNack or upload summary flow.
|
|
@@ -388,9 +389,16 @@ export class RunningSummarizer implements IDisposable {
|
|
|
388
389
|
attemptPhase++;
|
|
389
390
|
attemptPerPhase = 0;
|
|
390
391
|
}
|
|
392
|
+
lastResult = result;
|
|
391
393
|
}
|
|
392
|
-
|
|
393
|
-
|
|
394
|
+
|
|
395
|
+
// If all attempts failed, log error (with last attempt info) and close the summarizer container
|
|
396
|
+
this.logger.sendErrorEvent({
|
|
397
|
+
eventName: "FailToSummarize",
|
|
398
|
+
summarizeReason,
|
|
399
|
+
message: lastResult?.message,
|
|
400
|
+
}, lastResult?.error);
|
|
401
|
+
|
|
394
402
|
this.stopSummarizerCallback("failToSummarize");
|
|
395
403
|
}).catch((error) => {
|
|
396
404
|
this.logger.sendErrorEvent({ eventName: "UnexpectedSummarizeError" }, error);
|
package/src/summarizer.ts
CHANGED
|
@@ -277,6 +277,7 @@ export class Summarizer extends EventEmitter implements ISummarizer {
|
|
|
277
277
|
await this.internalsProvider.refreshLatestSummaryAck(
|
|
278
278
|
ack.summaryOp.contents.handle,
|
|
279
279
|
ack.summaryAck.contents.handle,
|
|
280
|
+
refSequenceNumber,
|
|
280
281
|
summaryLogger,
|
|
281
282
|
);
|
|
282
283
|
} catch (error) {
|
package/src/summarizerTypes.ts
CHANGED
|
@@ -57,6 +57,7 @@ export interface ISummarizerInternalsProvider {
|
|
|
57
57
|
refreshLatestSummaryAck(
|
|
58
58
|
proposalHandle: string,
|
|
59
59
|
ackHandle: string,
|
|
60
|
+
summaryRefSeq: number,
|
|
60
61
|
summaryLogger: ITelemetryLogger,
|
|
61
62
|
): Promise<void>;
|
|
62
63
|
}
|
|
@@ -196,17 +197,22 @@ export interface IBroadcastSummaryResult {
|
|
|
196
197
|
readonly broadcastDuration: number;
|
|
197
198
|
}
|
|
198
199
|
|
|
199
|
-
export interface
|
|
200
|
-
readonly
|
|
200
|
+
export interface IAckSummaryResult {
|
|
201
|
+
readonly summaryAckOp: ISummaryAckMessage;
|
|
201
202
|
readonly ackNackDuration: number;
|
|
202
203
|
}
|
|
203
204
|
|
|
204
|
-
export
|
|
205
|
+
export interface INackSummaryResult {
|
|
206
|
+
readonly summaryNackOp: ISummaryNackMessage;
|
|
207
|
+
readonly ackNackDuration: number;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export type SummarizeResultPart<TSuccess, TFailure = undefined> = {
|
|
205
211
|
success: true;
|
|
206
|
-
data:
|
|
212
|
+
data: TSuccess;
|
|
207
213
|
} | {
|
|
208
214
|
success: false;
|
|
209
|
-
data:
|
|
215
|
+
data: TFailure | undefined;
|
|
210
216
|
message: string;
|
|
211
217
|
error: any;
|
|
212
218
|
retryAfterSeconds?: number;
|
|
@@ -218,7 +224,7 @@ export interface ISummarizeResults {
|
|
|
218
224
|
/** Resolves when we observe our summarize op broadcast. */
|
|
219
225
|
readonly summaryOpBroadcasted: Promise<SummarizeResultPart<IBroadcastSummaryResult>>;
|
|
220
226
|
/** Resolves when we receive a summaryAck or summaryNack. */
|
|
221
|
-
readonly receivedSummaryAckOrNack: Promise<SummarizeResultPart<
|
|
227
|
+
readonly receivedSummaryAckOrNack: Promise<SummarizeResultPart<IAckSummaryResult, INackSummaryResult>>;
|
|
222
228
|
}
|
|
223
229
|
|
|
224
230
|
export type OnDemandSummarizeResult = (ISummarizeResults & {
|
package/src/summaryCollection.ts
CHANGED
|
@@ -226,6 +226,14 @@ export class SummaryCollection extends TypedEventEmitter<ISummaryCollectionOpEve
|
|
|
226
226
|
(this.lastAck?.summaryAck.sequenceNumber ?? this.deltaManager.initialSequenceNumber);
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
+
public addOpListener(listener: () => void) {
|
|
230
|
+
this.deltaManager.on("op", listener);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
public removeOpListener(listener: () => void) {
|
|
234
|
+
this.deltaManager.off("op", listener);
|
|
235
|
+
}
|
|
236
|
+
|
|
229
237
|
public constructor(
|
|
230
238
|
private readonly deltaManager: IDeltaManager<ISequencedDocumentMessage, IDocumentMessage>,
|
|
231
239
|
private readonly logger: ITelemetryLogger,
|
package/src/summaryGenerator.ts
CHANGED
|
@@ -4,12 +4,19 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { ITelemetryLogger, ITelemetryProperties } from "@fluidframework/common-definitions";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
assert,
|
|
9
|
+
Deferred,
|
|
10
|
+
IPromiseTimer,
|
|
11
|
+
IPromiseTimerResult,
|
|
12
|
+
Timer,
|
|
13
|
+
} from "@fluidframework/common-utils";
|
|
8
14
|
import { MessageType } from "@fluidframework/protocol-definitions";
|
|
9
15
|
import { PerformanceEvent, LoggingError, ChildLogger } from "@fluidframework/telemetry-utils";
|
|
10
16
|
import { getRetryDelaySecondsFromError } from "@fluidframework/driver-utils";
|
|
11
17
|
import {
|
|
12
|
-
|
|
18
|
+
IAckSummaryResult,
|
|
19
|
+
INackSummaryResult,
|
|
13
20
|
ISummarizeOptions,
|
|
14
21
|
IBroadcastSummaryResult,
|
|
15
22
|
ISummarizeResults,
|
|
@@ -118,9 +125,10 @@ const summarizeErrors = {
|
|
|
118
125
|
export class SummarizeResultBuilder {
|
|
119
126
|
public readonly summarySubmitted = new Deferred<SummarizeResultPart<SubmitSummaryResult>>();
|
|
120
127
|
public readonly summaryOpBroadcasted = new Deferred<SummarizeResultPart<IBroadcastSummaryResult>>();
|
|
121
|
-
public readonly receivedSummaryAckOrNack =
|
|
128
|
+
public readonly receivedSummaryAckOrNack =
|
|
129
|
+
new Deferred<SummarizeResultPart<IAckSummaryResult, INackSummaryResult>>();
|
|
122
130
|
|
|
123
|
-
public fail(message: string, error: any, nackSummaryResult?:
|
|
131
|
+
public fail(message: string, error: any, nackSummaryResult?: INackSummaryResult, retryAfterSeconds?: number) {
|
|
124
132
|
assert(!this.receivedSummaryAckOrNack.isCompleted,
|
|
125
133
|
0x25e /* "no reason to call fail if all promises have been completed" */);
|
|
126
134
|
|
|
@@ -203,7 +211,7 @@ export class SummaryGenerator {
|
|
|
203
211
|
errorCode: keyof typeof summarizeErrors,
|
|
204
212
|
error?: any,
|
|
205
213
|
properties?: ITelemetryProperties,
|
|
206
|
-
nackSummaryResult?:
|
|
214
|
+
nackSummaryResult?: INackSummaryResult,
|
|
207
215
|
) => {
|
|
208
216
|
this.raiseSummarizingError(summarizeErrors[errorCode]);
|
|
209
217
|
// UploadSummary may fail with 429 and retryAfter - respect that
|
|
@@ -327,16 +335,15 @@ export class SummaryGenerator {
|
|
|
327
335
|
this.heuristicData.markLastAttemptAsSuccessful();
|
|
328
336
|
summarizeEvent.end({ ...telemetryProps, handle: ackNackOp.contents.handle, message: "summaryAck" });
|
|
329
337
|
resultsBuilder.receivedSummaryAckOrNack.resolve({ success: true, data: {
|
|
330
|
-
|
|
338
|
+
summaryAckOp: ackNackOp,
|
|
331
339
|
ackNackDuration,
|
|
332
340
|
}});
|
|
333
341
|
} else {
|
|
334
342
|
// Check for retryDelay in summaryNack response.
|
|
335
343
|
// back-compat: cast needed until dep on protocol-definitions version bump
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
const message = (ackNackOp.contents as { message?: string }).message ?? ackNackOp.contents.errorMessage;
|
|
344
|
+
assert(ackNackOp.type === MessageType.SummaryNack, 0x274 /* "type check" */);
|
|
345
|
+
const summaryNack = ackNackOp.contents as { message?: string; retryAfter?: number; };
|
|
346
|
+
const message = summaryNack.message ?? ackNackOp.contents.errorMessage;
|
|
340
347
|
const retryAfterSeconds = summaryNack?.retryAfter;
|
|
341
348
|
|
|
342
349
|
const error = new LoggingError(`summaryNack: ${message}`, { retryAfterSeconds });
|
|
@@ -348,7 +355,7 @@ export class SummaryGenerator {
|
|
|
348
355
|
"summaryNack",
|
|
349
356
|
error,
|
|
350
357
|
{ ...telemetryProps, nackRetryAfter: retryAfterSeconds },
|
|
351
|
-
{
|
|
358
|
+
{ summaryNackOp: ackNackOp, ackNackDuration },
|
|
352
359
|
);
|
|
353
360
|
}
|
|
354
361
|
} finally {
|
package/src/summaryManager.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { IDisposable, IEvent, IEventProvider, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
7
|
-
import {
|
|
7
|
+
import { TypedEventEmitter, assert } from "@fluidframework/common-utils";
|
|
8
8
|
import { ChildLogger, PerformanceEvent } from "@fluidframework/telemetry-utils";
|
|
9
9
|
import { IFluidRouter, IRequest } from "@fluidframework/core-interfaces";
|
|
10
10
|
import { IDeltaManager, LoaderHeader } from "@fluidframework/container-definitions";
|
|
@@ -90,7 +90,8 @@ export class SummaryManager extends TypedEventEmitter<ISummaryManagerEvents> imp
|
|
|
90
90
|
constructor(
|
|
91
91
|
private readonly clientElection: ISummarizerClientElection,
|
|
92
92
|
private readonly connectedState: IConnectedState,
|
|
93
|
-
private readonly summaryCollection:
|
|
93
|
+
private readonly summaryCollection:
|
|
94
|
+
Pick<SummaryCollection, "opsSinceLastAck" | "addOpListener" | "removeOpListener">,
|
|
94
95
|
parentLogger: ITelemetryLogger,
|
|
95
96
|
/** Creates summarizer by asking interactive container to spawn summarizing container and
|
|
96
97
|
* get back its Summarizer instance. */
|
|
@@ -265,15 +266,9 @@ export class SummaryManager extends TypedEventEmitter<ISummaryManagerEvents> imp
|
|
|
265
266
|
0x265 /* "Expected: Starting or Running" */);
|
|
266
267
|
this.state = SummaryManagerState.Stopping;
|
|
267
268
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
this.summarizer.stop(reason);
|
|
272
|
-
} else {
|
|
273
|
-
// Should not be possible to hit this case
|
|
274
|
-
this.logger.sendErrorEvent({ eventName: "StopCalledWithoutRunningSummarizer", reason });
|
|
275
|
-
this.state = SummaryManagerState.Off;
|
|
276
|
-
}
|
|
269
|
+
// Stopping the running summarizer client should trigger a change
|
|
270
|
+
// in states when the running summarizer closes
|
|
271
|
+
this.summarizer?.stop(reason);
|
|
277
272
|
}
|
|
278
273
|
|
|
279
274
|
/**
|
|
@@ -284,7 +279,7 @@ export class SummaryManager extends TypedEventEmitter<ISummaryManagerEvents> imp
|
|
|
284
279
|
private async delayBeforeCreatingSummarizer(): Promise<boolean> {
|
|
285
280
|
// throttle creation of new summarizer containers to prevent spamming the server with websocket connections
|
|
286
281
|
let delayMs = this.startThrottler.getDelay();
|
|
287
|
-
if (delayMs > 0 && delayMs
|
|
282
|
+
if (delayMs > 0 && delayMs > this.startThrottler.maxDelayMs) {
|
|
288
283
|
this.emit(
|
|
289
284
|
"summarizerWarning",
|
|
290
285
|
createSummarizingWarning("summaryManagerCreateSummarizerMaxThrottleDelay", false),
|
|
@@ -317,7 +312,24 @@ export class SummaryManager extends TypedEventEmitter<ISummaryManagerEvents> imp
|
|
|
317
312
|
}
|
|
318
313
|
|
|
319
314
|
if (delayMs > 0) {
|
|
320
|
-
|
|
315
|
+
let timer;
|
|
316
|
+
let resolveOpPromiseFn;
|
|
317
|
+
// Create a listener that will break the delay if we've exceeded the initial delay ops count.
|
|
318
|
+
const opsListenerFn = () => {
|
|
319
|
+
if (this.summaryCollection.opsSinceLastAck >= this.opsToBypassInitialDelay) {
|
|
320
|
+
clearTimeout(timer);
|
|
321
|
+
resolveOpPromiseFn();
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
// Create a Promise that will resolve when the delay expires.
|
|
325
|
+
const delayPromise = new Promise<void>((resolve) => {
|
|
326
|
+
timer = setTimeout(() => resolve(), delayMs);
|
|
327
|
+
});
|
|
328
|
+
// Create a Promise that will resolve if the ops count passes the threshold.
|
|
329
|
+
const opPromise = new Promise<void>((resolve) => { resolveOpPromiseFn = resolve; });
|
|
330
|
+
this.summaryCollection.addOpListener(opsListenerFn);
|
|
331
|
+
await Promise.race([ delayPromise, opPromise ]);
|
|
332
|
+
this.summaryCollection.removeOpListener(opsListenerFn);
|
|
321
333
|
}
|
|
322
334
|
return startWithInitialDelay;
|
|
323
335
|
}
|