@fluidframework/container-runtime 0.58.3000-61081 → 0.59.1001-62246
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/blobManager.d.ts +13 -1
- package/dist/blobManager.d.ts.map +1 -1
- package/dist/blobManager.js +52 -0
- package/dist/blobManager.js.map +1 -1
- package/dist/connectionTelemetry.js +7 -7
- package/dist/connectionTelemetry.js.map +1 -1
- package/dist/containerRuntime.d.ts +27 -3
- package/dist/containerRuntime.d.ts.map +1 -1
- package/dist/containerRuntime.js +100 -14
- package/dist/containerRuntime.js.map +1 -1
- package/dist/dataStore.js +8 -1
- package/dist/dataStore.js.map +1 -1
- package/dist/dataStoreContext.d.ts +9 -3
- package/dist/dataStoreContext.d.ts.map +1 -1
- package/dist/dataStoreContext.js +22 -6
- package/dist/dataStoreContext.js.map +1 -1
- package/dist/dataStores.d.ts +13 -5
- package/dist/dataStores.d.ts.map +1 -1
- package/dist/dataStores.js +39 -18
- package/dist/dataStores.js.map +1 -1
- package/dist/deltaScheduler.d.ts +4 -5
- package/dist/deltaScheduler.d.ts.map +1 -1
- package/dist/deltaScheduler.js +54 -35
- package/dist/deltaScheduler.js.map +1 -1
- package/dist/garbageCollection.d.ts +31 -27
- package/dist/garbageCollection.d.ts.map +1 -1
- package/dist/garbageCollection.js +76 -75
- package/dist/garbageCollection.js.map +1 -1
- package/dist/orderedClientElection.d.ts +6 -57
- package/dist/orderedClientElection.d.ts.map +1 -1
- package/dist/orderedClientElection.js +25 -140
- package/dist/orderedClientElection.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/summarizerClientElection.d.ts +0 -2
- package/dist/summarizerClientElection.d.ts.map +1 -1
- package/dist/summarizerClientElection.js +2 -7
- package/dist/summarizerClientElection.js.map +1 -1
- package/dist/summaryManager.d.ts.map +1 -1
- package/dist/summaryManager.js +3 -14
- package/dist/summaryManager.js.map +1 -1
- package/lib/blobManager.d.ts +13 -1
- package/lib/blobManager.d.ts.map +1 -1
- package/lib/blobManager.js +52 -0
- package/lib/blobManager.js.map +1 -1
- package/lib/connectionTelemetry.js +7 -7
- package/lib/connectionTelemetry.js.map +1 -1
- package/lib/containerRuntime.d.ts +27 -3
- package/lib/containerRuntime.d.ts.map +1 -1
- package/lib/containerRuntime.js +101 -15
- package/lib/containerRuntime.js.map +1 -1
- package/lib/dataStore.js +8 -1
- package/lib/dataStore.js.map +1 -1
- package/lib/dataStoreContext.d.ts +9 -3
- package/lib/dataStoreContext.d.ts.map +1 -1
- package/lib/dataStoreContext.js +22 -6
- package/lib/dataStoreContext.js.map +1 -1
- package/lib/dataStores.d.ts +13 -5
- package/lib/dataStores.d.ts.map +1 -1
- package/lib/dataStores.js +39 -18
- package/lib/dataStores.js.map +1 -1
- package/lib/deltaScheduler.d.ts +4 -5
- package/lib/deltaScheduler.d.ts.map +1 -1
- package/lib/deltaScheduler.js +54 -35
- package/lib/deltaScheduler.js.map +1 -1
- package/lib/garbageCollection.d.ts +31 -27
- package/lib/garbageCollection.d.ts.map +1 -1
- package/lib/garbageCollection.js +75 -74
- package/lib/garbageCollection.js.map +1 -1
- package/lib/orderedClientElection.d.ts +6 -57
- package/lib/orderedClientElection.d.ts.map +1 -1
- package/lib/orderedClientElection.js +25 -140
- package/lib/orderedClientElection.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/summarizerClientElection.d.ts +0 -2
- package/lib/summarizerClientElection.d.ts.map +1 -1
- package/lib/summarizerClientElection.js +2 -7
- package/lib/summarizerClientElection.js.map +1 -1
- package/lib/summaryManager.d.ts.map +1 -1
- package/lib/summaryManager.js +3 -14
- package/lib/summaryManager.js.map +1 -1
- package/package.json +33 -21
- package/src/blobManager.ts +60 -1
- package/src/connectionTelemetry.ts +7 -7
- package/src/containerRuntime.ts +106 -17
- package/src/dataStore.ts +7 -1
- package/src/dataStoreContext.ts +22 -7
- package/src/dataStores.ts +40 -19
- package/src/deltaScheduler.ts +65 -39
- package/src/garbageCollection.ts +92 -78
- package/src/orderedClientElection.ts +25 -154
- package/src/packageVersion.ts +1 -1
- package/src/summarizerClientElection.ts +2 -7
- package/src/summaryManager.ts +4 -15
|
@@ -6,10 +6,8 @@
|
|
|
6
6
|
import { IEvent, IEventProvider, ITelemetryLogger } from "@fluidframework/common-definitions";
|
|
7
7
|
import { assert, TypedEventEmitter } from "@fluidframework/common-utils";
|
|
8
8
|
import { IDeltaManager } from "@fluidframework/container-definitions";
|
|
9
|
-
import { UsageError } from "@fluidframework/container-utils";
|
|
10
9
|
import { IClient, IQuorumClients, ISequencedClient } from "@fluidframework/protocol-definitions";
|
|
11
10
|
import { ChildLogger } from "@fluidframework/telemetry-utils";
|
|
12
|
-
import { summarizerClientType } from "./summarizerClientElection";
|
|
13
11
|
|
|
14
12
|
// helper types for recursive readonly.
|
|
15
13
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
@@ -208,26 +206,16 @@ export interface IOrderedClientElectionEvents extends IEvent {
|
|
|
208
206
|
export interface ISerializedElection {
|
|
209
207
|
/** Sequence number at the time of the latest election. */
|
|
210
208
|
readonly electionSequenceNumber: number;
|
|
211
|
-
/** Most recently elected client id.
|
|
212
|
-
* 1. the interactive elected parent client, in which case electedClientId === electedParentId,
|
|
213
|
-
* and the SummaryManager on the elected client will spawn a summarizer client, or
|
|
214
|
-
* 2. the non-interactive summarizer client itself. */
|
|
209
|
+
/** Most recently elected client id. */
|
|
215
210
|
readonly electedClientId: string | undefined;
|
|
216
|
-
/** Most recently elected parent client id. This is always an interactive client. */
|
|
217
|
-
readonly electedParentId: string | undefined;
|
|
218
211
|
}
|
|
219
212
|
|
|
220
213
|
/** Contract for maintaining a deterministic client election based on eligibility. */
|
|
221
214
|
export interface IOrderedClientElection extends IEventProvider<IOrderedClientElectionEvents> {
|
|
222
215
|
/** Count of eligible clients in the collection. */
|
|
223
216
|
readonly eligibleCount: number;
|
|
224
|
-
/** Currently elected client.
|
|
225
|
-
* 1. the interactive elected parent client, in which case electedClientId === electedParentId,
|
|
226
|
-
* and the SummaryManager on the elected client will spawn a summarizer client, or
|
|
227
|
-
* 2. the non-interactive summarizer client itself. */
|
|
217
|
+
/** Currently elected client. */
|
|
228
218
|
readonly electedClient: ITrackedClient | undefined;
|
|
229
|
-
/** Currently elected parent client. This is always an interactive client. */
|
|
230
|
-
readonly electedParent: ITrackedClient | undefined;
|
|
231
219
|
/** Sequence number of most recent election. */
|
|
232
220
|
readonly electionSequenceNumber: number;
|
|
233
221
|
/** Marks the currently elected client as invalid, and elects the next eligible client. */
|
|
@@ -253,50 +241,16 @@ export class OrderedClientElection
|
|
|
253
241
|
implements IOrderedClientElection {
|
|
254
242
|
private _eligibleCount: number = 0;
|
|
255
243
|
private _electedClient: ILinkedClient | undefined;
|
|
256
|
-
private _electedParent: ILinkedClient | undefined;
|
|
257
244
|
private _electionSequenceNumber: number;
|
|
258
245
|
|
|
259
246
|
public get eligibleCount() {
|
|
260
247
|
return this._eligibleCount;
|
|
261
248
|
}
|
|
262
|
-
public get electionSequenceNumber() {
|
|
263
|
-
return this._electionSequenceNumber;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
* OrderedClientCollection tracks electedClient and electedParent separately. This allows us to handle the case
|
|
268
|
-
* where a new interactive parent client has been elected, but the summarizer is still doing work, so
|
|
269
|
-
* a new summarizer should not yet be spawned. In this case, changing electedParent will cause SummaryManager
|
|
270
|
-
* to stop the current summarizer, but a new summarizer will not be spawned until the old summarizer client has
|
|
271
|
-
* left the quorum.
|
|
272
|
-
*
|
|
273
|
-
* Details:
|
|
274
|
-
*
|
|
275
|
-
* electedParent is the interactive client that has been elected to spawn a summarizer. It is typically the oldest
|
|
276
|
-
* eligible interactive client in the quorum. Only the electedParent is permitted to spawn a summarizer.
|
|
277
|
-
* Once elected, this client will remain the electedParent until it leaves the quorum or the summarizer that
|
|
278
|
-
* it spawned stops producing summaries, at which point a new electedParent will be chosen.
|
|
279
|
-
*
|
|
280
|
-
* electedClient is the non-interactive summarizer client if one exists. If not, then electedClient is equal to
|
|
281
|
-
* electedParent. If electedParent === electedClient, this is the signal for electedParent to spawn a new
|
|
282
|
-
* electedClient. Once a summarizer client becomes electedClient, a new summarizer will not be spawned until
|
|
283
|
-
* electedClient leaves the quorum.
|
|
284
|
-
*
|
|
285
|
-
* A typical sequence looks like this:
|
|
286
|
-
* i. Begin by electing A. electedParent === A, electedClient === A.
|
|
287
|
-
* ii. SummaryManager running on A spawns a summarizer client, A'. electedParent === A, electedClient === A'
|
|
288
|
-
* iii. A' stops producing summaries. A new parent client, B, is elected. electedParent === B, electedClient === A'
|
|
289
|
-
* iv. SummaryManager running on A detects the change to electedParent and tells the summarizer to stop, but A'
|
|
290
|
-
* is in mid-summarization. No new summarizer is spawned, as electedParent !== electedClient.
|
|
291
|
-
* v. A' completes its summary, and the summarizer and backing client are torn down.
|
|
292
|
-
* vi. A' leaves the quorum, and B takes its place as electedClient. electedParent === B, electedClient === B
|
|
293
|
-
* vii. SummaryManager running on B spawns a summarizer client, B'. electedParent === B, electedClient === B'
|
|
294
|
-
*/
|
|
295
249
|
public get electedClient() {
|
|
296
250
|
return this._electedClient;
|
|
297
251
|
}
|
|
298
|
-
public get
|
|
299
|
-
return this.
|
|
252
|
+
public get electionSequenceNumber() {
|
|
253
|
+
return this._electionSequenceNumber;
|
|
300
254
|
}
|
|
301
255
|
|
|
302
256
|
constructor(
|
|
@@ -308,20 +262,11 @@ export class OrderedClientElection
|
|
|
308
262
|
) {
|
|
309
263
|
super();
|
|
310
264
|
let initialClient: ILinkedClient | undefined;
|
|
311
|
-
let initialParent: ILinkedClient | undefined;
|
|
312
265
|
for (const client of orderedClientCollection.getAllClients()) {
|
|
313
266
|
this.addClient(client, 0);
|
|
314
267
|
if (typeof initialState !== "number") {
|
|
315
268
|
if (client.clientId === initialState.electedClientId) {
|
|
316
269
|
initialClient = client;
|
|
317
|
-
if (initialState.electedParentId === undefined &&
|
|
318
|
-
client.client.details.type !== summarizerClientType) {
|
|
319
|
-
// If there was no elected parent in the serialized data, use this one.
|
|
320
|
-
initialParent = client;
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
if (client.clientId === initialState.electedParentId) {
|
|
324
|
-
initialParent = client;
|
|
325
270
|
}
|
|
326
271
|
}
|
|
327
272
|
}
|
|
@@ -343,7 +288,7 @@ export class OrderedClientElection
|
|
|
343
288
|
});
|
|
344
289
|
} else if (initialClient !== undefined && !isEligibleFn(initialClient)) {
|
|
345
290
|
// Initially elected client is ineligible, so elect next eligible client.
|
|
346
|
-
initialClient =
|
|
291
|
+
initialClient = this.findFirstEligibleClient(initialClient);
|
|
347
292
|
logger.sendErrorEvent({
|
|
348
293
|
eventName: "InitialElectedClientIneligible",
|
|
349
294
|
electionSequenceNumber: initialState.electionSequenceNumber,
|
|
@@ -351,53 +296,31 @@ export class OrderedClientElection
|
|
|
351
296
|
electedClientId: initialClient?.clientId,
|
|
352
297
|
});
|
|
353
298
|
}
|
|
354
|
-
this._electedParent = initialParent;
|
|
355
299
|
this._electedClient = initialClient;
|
|
356
300
|
this._electionSequenceNumber = initialState.electionSequenceNumber;
|
|
357
301
|
}
|
|
358
302
|
}
|
|
359
303
|
|
|
360
|
-
/** Tries changing the elected client, raising an event if it is different.
|
|
361
|
-
* Note that this function does no eligibility or suitability checks. If we get here, then
|
|
362
|
-
* we will set _electedClient, and we will set _electedParent if this is an interactive client.
|
|
363
|
-
*/
|
|
304
|
+
/** Tries changing the elected client, raising an event if it is different. */
|
|
364
305
|
private tryElectingClient(client: ILinkedClient | undefined, sequenceNumber: number): void {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if (this._electedClient !== client) {
|
|
369
|
-
// Changing the elected client. Record the sequence number and note that we have to fire an event.
|
|
370
|
-
this._electionSequenceNumber = sequenceNumber;
|
|
371
|
-
this._electedClient = client;
|
|
372
|
-
change = true;
|
|
373
|
-
}
|
|
374
|
-
if (this._electedParent !== client && !isSummarizerClient) {
|
|
375
|
-
// Changing the elected parent as well.
|
|
376
|
-
this._electedParent = client;
|
|
377
|
-
change = true;
|
|
378
|
-
}
|
|
379
|
-
if (change) {
|
|
380
|
-
this.emit("election", client, sequenceNumber, prevClient);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
private tryElectingParent(client: ILinkedClient | undefined, sequenceNumber: number): void {
|
|
385
|
-
if (this._electedParent !== client) {
|
|
386
|
-
this._electedParent = client;
|
|
387
|
-
this.emit("election", this._electedClient, sequenceNumber, this._electedClient);
|
|
306
|
+
this._electionSequenceNumber = sequenceNumber;
|
|
307
|
+
if (this._electedClient === client) {
|
|
308
|
+
return;
|
|
388
309
|
}
|
|
310
|
+
const prevClient = this._electedClient;
|
|
311
|
+
this._electedClient = client;
|
|
312
|
+
this.emit("election", client, sequenceNumber, prevClient);
|
|
389
313
|
}
|
|
390
314
|
|
|
391
315
|
/**
|
|
392
|
-
* Helper function to find the first eligible
|
|
316
|
+
* Helper function to find the first eligible client starting with the passed in client,
|
|
393
317
|
* or undefined if none are eligible.
|
|
394
318
|
* @param client - client to start checking
|
|
395
319
|
* @returns oldest eligible client starting with passed in client or undefined if none.
|
|
396
320
|
*/
|
|
397
|
-
private
|
|
321
|
+
private findFirstEligibleClient(client: ILinkedClient | undefined): ILinkedClient | undefined {
|
|
398
322
|
let candidateClient = client;
|
|
399
|
-
while (candidateClient !== undefined &&
|
|
400
|
-
(!this.isEligibleFn(candidateClient) || candidateClient.client.details.type === summarizerClientType)) {
|
|
323
|
+
while (candidateClient !== undefined && !this.isEligibleFn(candidateClient)) {
|
|
401
324
|
candidateClient = candidateClient.youngerClient;
|
|
402
325
|
}
|
|
403
326
|
return candidateClient;
|
|
@@ -412,16 +335,10 @@ export class OrderedClientElection
|
|
|
412
335
|
private addClient(client: ILinkedClient, sequenceNumber: number): void {
|
|
413
336
|
if (this.isEligibleFn(client)) {
|
|
414
337
|
this._eligibleCount++;
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
// Note that we allow a summarizer client to supercede an interactive client as elected client.
|
|
418
|
-
if (this._electedClient === undefined || (!electedClientIsSummarizer && newClientIsSummarizer)) {
|
|
338
|
+
if (this._electedClient === undefined) {
|
|
339
|
+
// Automatically elect latest client
|
|
419
340
|
this.tryElectingClient(client, sequenceNumber);
|
|
420
341
|
}
|
|
421
|
-
else if (this._electedParent === undefined && !newClientIsSummarizer) {
|
|
422
|
-
// This is an odd case. If the _electedClient is set, the _electedParent should be as well.
|
|
423
|
-
this.tryElectingParent(client, sequenceNumber);
|
|
424
|
-
}
|
|
425
342
|
}
|
|
426
343
|
}
|
|
427
344
|
|
|
@@ -435,33 +352,9 @@ export class OrderedClientElection
|
|
|
435
352
|
if (this.isEligibleFn(client)) {
|
|
436
353
|
this._eligibleCount--;
|
|
437
354
|
if (this._electedClient === client) {
|
|
438
|
-
//
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
// Let the _electedParent become the _electedClient so that it can start its own summarizer.
|
|
442
|
-
if (this._electedClient.client.details.type !== summarizerClientType) {
|
|
443
|
-
throw new UsageError("Elected client should be a summarizer client 1");
|
|
444
|
-
}
|
|
445
|
-
this.tryElectingClient(this._electedParent, sequenceNumber);
|
|
446
|
-
}
|
|
447
|
-
else {
|
|
448
|
-
// 2. The _electedClient is an interactive client that has left the quorum.
|
|
449
|
-
// Automatically shift to next oldest client.
|
|
450
|
-
const nextClient = this.findFirstEligibleParent(this._electedParent?.youngerClient) ??
|
|
451
|
-
this.findFirstEligibleParent(this.orderedClientCollection.oldestClient);
|
|
452
|
-
this.tryElectingClient(nextClient, sequenceNumber);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
else if (this._electedParent === client) {
|
|
456
|
-
// Removing the _electedParent (but not _electedClient).
|
|
457
|
-
// Shift to the next oldest parent, but do not replace the _electedClient,
|
|
458
|
-
// which is a summarizer that is still doing work.
|
|
459
|
-
if (this._electedClient?.client.details.type !== summarizerClientType) {
|
|
460
|
-
throw new UsageError("Elected client should be a summarizer client 2");
|
|
461
|
-
}
|
|
462
|
-
const nextParent = this.findFirstEligibleParent(this._electedParent?.youngerClient) ??
|
|
463
|
-
this.findFirstEligibleParent(this.orderedClientCollection.oldestClient);
|
|
464
|
-
this.tryElectingParent(nextParent, sequenceNumber);
|
|
355
|
+
// Automatically shift to next oldest client
|
|
356
|
+
const nextClient = this.findFirstEligibleClient(this._electedClient.youngerClient);
|
|
357
|
+
this.tryElectingClient(nextClient, sequenceNumber);
|
|
465
358
|
}
|
|
466
359
|
}
|
|
467
360
|
}
|
|
@@ -470,46 +363,24 @@ export class OrderedClientElection
|
|
|
470
363
|
return this.orderedClientCollection.getAllClients().filter(this.isEligibleFn);
|
|
471
364
|
}
|
|
472
365
|
|
|
473
|
-
/** Advance election to the next-oldest client. This is called if the current parent is leaving the quorum,
|
|
474
|
-
* or if the current summarizer is not responsive and we want to stop it and spawn a new one.
|
|
475
|
-
*/
|
|
476
366
|
public incrementElectedClient(sequenceNumber: number): void {
|
|
477
|
-
const nextClient = this.
|
|
478
|
-
|
|
479
|
-
if (this._electedClient === undefined || this._electedClient === this._electedParent) {
|
|
480
|
-
this.tryElectingClient(nextClient, sequenceNumber);
|
|
481
|
-
}
|
|
482
|
-
else {
|
|
483
|
-
// The _electedClient is a summarizer and should not be replaced until it leaves the quorum.
|
|
484
|
-
// Changing the _electedParent will stop the summarizer.
|
|
485
|
-
this.tryElectingParent(nextClient, sequenceNumber);
|
|
486
|
-
}
|
|
367
|
+
const nextClient = this.findFirstEligibleClient(this._electedClient?.youngerClient);
|
|
368
|
+
this.tryElectingClient(nextClient, sequenceNumber);
|
|
487
369
|
}
|
|
488
370
|
|
|
489
|
-
/** (Re-)start election with the oldest client in the quorum. This is called if we need to summarize
|
|
490
|
-
* and no client has been elected.
|
|
491
|
-
*/
|
|
492
371
|
public resetElectedClient(sequenceNumber: number): void {
|
|
493
|
-
const firstClient = this.
|
|
494
|
-
|
|
495
|
-
this.tryElectingClient(firstClient, sequenceNumber);
|
|
496
|
-
}
|
|
497
|
-
else {
|
|
498
|
-
// The _electedClient is a summarizer and should not be replaced until it leaves the quorum.
|
|
499
|
-
// Changing the _electedParent will stop the summarizer.
|
|
500
|
-
this.tryElectingParent(firstClient, sequenceNumber);
|
|
501
|
-
}
|
|
372
|
+
const firstClient = this.findFirstEligibleClient(this.orderedClientCollection.oldestClient);
|
|
373
|
+
this.tryElectingClient(firstClient, sequenceNumber);
|
|
502
374
|
}
|
|
503
375
|
|
|
504
376
|
public peekNextElectedClient(): ITrackedClient | undefined {
|
|
505
|
-
return this.
|
|
377
|
+
return this.findFirstEligibleClient(this._electedClient?.youngerClient);
|
|
506
378
|
}
|
|
507
379
|
|
|
508
380
|
public serialize(): ISerializedElection {
|
|
509
381
|
return {
|
|
510
382
|
electionSequenceNumber: this.electionSequenceNumber,
|
|
511
383
|
electedClientId: this.electedClient?.clientId,
|
|
512
|
-
electedParentId: this.electedParent?.clientId,
|
|
513
384
|
};
|
|
514
385
|
}
|
|
515
386
|
}
|
package/src/packageVersion.ts
CHANGED
|
@@ -17,7 +17,6 @@ export interface ISummarizerClientElectionEvents extends IEvent {
|
|
|
17
17
|
|
|
18
18
|
export interface ISummarizerClientElection extends IEventProvider<ISummarizerClientElectionEvents> {
|
|
19
19
|
readonly electedClientId: string | undefined;
|
|
20
|
-
readonly electedParentId: string | undefined;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
/**
|
|
@@ -45,9 +44,6 @@ export class SummarizerClientElection
|
|
|
45
44
|
public get electedClientId() {
|
|
46
45
|
return this.clientElection.electedClient?.clientId;
|
|
47
46
|
}
|
|
48
|
-
public get electedParentId() {
|
|
49
|
-
return this.clientElection.electedParent?.clientId;
|
|
50
|
-
}
|
|
51
47
|
|
|
52
48
|
constructor(
|
|
53
49
|
private readonly logger: ITelemetryLogger,
|
|
@@ -131,10 +127,9 @@ export class SummarizerClientElection
|
|
|
131
127
|
}
|
|
132
128
|
|
|
133
129
|
public serialize(): ISerializedElection {
|
|
134
|
-
const { electedClientId,
|
|
130
|
+
const { electedClientId, electionSequenceNumber } = this.clientElection.serialize();
|
|
135
131
|
return {
|
|
136
132
|
electedClientId,
|
|
137
|
-
electedParentId,
|
|
138
133
|
electionSequenceNumber: this.lastSummaryAckSeqForClient ?? electionSequenceNumber,
|
|
139
134
|
};
|
|
140
135
|
}
|
|
@@ -149,5 +144,5 @@ export class SummarizerClientElection
|
|
|
149
144
|
}
|
|
150
145
|
|
|
151
146
|
public static readonly clientDetailsPermitElection = (details: IClientDetails): boolean =>
|
|
152
|
-
details.capabilities.interactive
|
|
147
|
+
details.capabilities.interactive && details.type !== summarizerClientType;
|
|
153
148
|
}
|
package/src/summaryManager.ts
CHANGED
|
@@ -137,15 +137,9 @@ export class SummaryManager implements IDisposable {
|
|
|
137
137
|
state === SummaryManagerState.Starting || state === SummaryManagerState.Running;
|
|
138
138
|
|
|
139
139
|
private getShouldSummarizeState(): ShouldSummarizeState {
|
|
140
|
-
// Note that if we're in the Running state, the electedClient may be a summarizer client, so we can't
|
|
141
|
-
// enforce connectedState.clientId === clientElection.electedClientId. But once we're Running, we should
|
|
142
|
-
// only transition to Stopping when the electedParentId changes. Stopping the summarizer without
|
|
143
|
-
// changing the electedParent will just cause us to transition to Starting again.
|
|
144
140
|
if (!this.connectedState.connected) {
|
|
145
141
|
return { shouldSummarize: false, stopReason: "parentNotConnected" };
|
|
146
|
-
} else if (this.connectedState.clientId !== this.clientElection.
|
|
147
|
-
(this.state !== SummaryManagerState.Running &&
|
|
148
|
-
this.connectedState.clientId !== this.clientElection.electedClientId)) {
|
|
142
|
+
} else if (this.connectedState.clientId !== this.clientElection.electedClientId) {
|
|
149
143
|
return { shouldSummarize: false, stopReason: "parentShouldNotSummarize" };
|
|
150
144
|
} else if (this.disposed) {
|
|
151
145
|
assert(false, 0x260 /* "Disposed should mean disconnected!" */);
|
|
@@ -205,23 +199,18 @@ export class SummaryManager implements IDisposable {
|
|
|
205
199
|
return;
|
|
206
200
|
}
|
|
207
201
|
|
|
208
|
-
// We transition to Running before requesting the summarizer, because after requesting we can't predict
|
|
209
|
-
// when the electedClient will be replaced with the new summarizer client.
|
|
210
|
-
// The alternative would be to let connectedState.clientId !== clientElection.electedClientId when
|
|
211
|
-
// state === Starting || state === Running.
|
|
212
|
-
assert(this.state === SummaryManagerState.Starting, 0x263 /* "Expected: starting" */);
|
|
213
|
-
this.state = SummaryManagerState.Running;
|
|
214
|
-
|
|
215
202
|
const summarizer = await this.requestSummarizerFn();
|
|
216
203
|
|
|
217
204
|
// Re-validate that it need to be running. Due to asynchrony, it may be not the case anymore
|
|
218
205
|
const shouldSummarizeState = this.getShouldSummarizeState();
|
|
219
206
|
if (shouldSummarizeState.shouldSummarize === false) {
|
|
220
|
-
this.state = SummaryManagerState.Starting;
|
|
221
207
|
summarizer.stop(shouldSummarizeState.stopReason);
|
|
222
208
|
return;
|
|
223
209
|
}
|
|
224
210
|
|
|
211
|
+
assert(this.state === SummaryManagerState.Starting, 0x263 /* "Expected: starting" */);
|
|
212
|
+
this.state = SummaryManagerState.Running;
|
|
213
|
+
|
|
225
214
|
this.summarizer = summarizer;
|
|
226
215
|
|
|
227
216
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|