@salesforce/lds-worker-api 1.454.0 → 1.456.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.
|
@@ -4282,7 +4282,7 @@
|
|
|
4282
4282
|
}
|
|
4283
4283
|
callbacks.push(callback);
|
|
4284
4284
|
}
|
|
4285
|
-
// version: 1.
|
|
4285
|
+
// version: 1.456.0-cef836b978
|
|
4286
4286
|
|
|
4287
4287
|
// TODO [TD-0081508]: once that TD is fulfilled we can probably change this file
|
|
4288
4288
|
function instrumentAdapter$1(createFunction, _metadata) {
|
|
@@ -5326,7 +5326,7 @@
|
|
|
5326
5326
|
const { apiFamily, name } = metadata;
|
|
5327
5327
|
return createGraphQLWireAdapterConstructor$1(adapter, `${apiFamily}.${name}`, luvio, astResolver);
|
|
5328
5328
|
}
|
|
5329
|
-
// version: 1.
|
|
5329
|
+
// version: 1.456.0-cef836b978
|
|
5330
5330
|
|
|
5331
5331
|
function isSupportedEntity(_objectApiName) {
|
|
5332
5332
|
return true;
|
|
@@ -5436,7 +5436,7 @@
|
|
|
5436
5436
|
|
|
5437
5437
|
const { keys: ObjectKeys$4, create: ObjectCreate$4 } = Object;
|
|
5438
5438
|
|
|
5439
|
-
const { assign: assign$7, create: create$9, freeze: freeze$6, isFrozen: isFrozen$4, keys: keys$a } = Object;
|
|
5439
|
+
const { assign: assign$7, create: create$9, freeze: freeze$6, getPrototypeOf: getPrototypeOf$3, isFrozen: isFrozen$4, keys: keys$a } = Object;
|
|
5440
5440
|
|
|
5441
5441
|
/**
|
|
5442
5442
|
* Defines configuration for the module with a default value which can be overridden by the runtime environment.
|
|
@@ -6071,7 +6071,7 @@
|
|
|
6071
6071
|
}
|
|
6072
6072
|
const keyPrefix$3 = 'UiApi';
|
|
6073
6073
|
|
|
6074
|
-
const { assign: assign$6, create: create$8, freeze: freeze$5, isFrozen: isFrozen$3, keys: keys$9 } = Object;
|
|
6074
|
+
const { assign: assign$6, create: create$8, freeze: freeze$5, getPrototypeOf: getPrototypeOf$2, isFrozen: isFrozen$3, keys: keys$9 } = Object;
|
|
6075
6075
|
const { hasOwnProperty: hasOwnProperty$5 } = Object.prototype;
|
|
6076
6076
|
const { split: split$1, endsWith: endsWith$1 } = String.prototype;
|
|
6077
6077
|
const { isArray: isArray$8 } = Array;
|
|
@@ -32553,7 +32553,7 @@
|
|
|
32553
32553
|
throttle(60, 60000, setupNotifyAllListRecordUpdateAvailable(luvio));
|
|
32554
32554
|
throttle(60, 60000, setupNotifyAllListInfoSummaryUpdateAvailable(luvio));
|
|
32555
32555
|
});
|
|
32556
|
-
// version: 1.
|
|
32556
|
+
// version: 1.456.0-6ed480b93c
|
|
32557
32557
|
|
|
32558
32558
|
var draftQueueMaxRetryAttemptsGate = {
|
|
32559
32559
|
isOpen: function (e) {
|
|
@@ -47855,16 +47855,18 @@
|
|
|
47855
47855
|
}
|
|
47856
47856
|
|
|
47857
47857
|
class AsyncWorkerPool {
|
|
47858
|
-
constructor(concurrency) {
|
|
47858
|
+
constructor(concurrency, onWorkTiming) {
|
|
47859
47859
|
this.queue = [];
|
|
47860
47860
|
this.activeWork = [];
|
|
47861
47861
|
this.concurrency = concurrency;
|
|
47862
|
+
this.onWorkTiming = onWorkTiming;
|
|
47862
47863
|
}
|
|
47863
47864
|
push(work) {
|
|
47864
47865
|
return new Promise((resolve, reject) => {
|
|
47865
47866
|
this.queue.push({
|
|
47866
47867
|
...work,
|
|
47867
47868
|
workFn: (abortController) => work.workFn(abortController).then(resolve).catch(reject),
|
|
47869
|
+
enqueuedAt: Date.now(),
|
|
47868
47870
|
});
|
|
47869
47871
|
this.doWork();
|
|
47870
47872
|
});
|
|
@@ -47907,10 +47909,30 @@
|
|
|
47907
47909
|
const abortController = new LdsAbortController();
|
|
47908
47910
|
const newWork = { ...work, abortController };
|
|
47909
47911
|
this.activeWork.push(newWork);
|
|
47910
|
-
const { workFn } = work;
|
|
47912
|
+
const { workFn, enqueuedAt } = work;
|
|
47913
|
+
const onWorkTiming = this.onWorkTiming;
|
|
47914
|
+
let startedAt = 0;
|
|
47915
|
+
let waitMs = 0;
|
|
47916
|
+
let queueDepthAtStart = 0;
|
|
47917
|
+
if (onWorkTiming !== undefined) {
|
|
47918
|
+
startedAt = Date.now();
|
|
47919
|
+
waitMs = startedAt - enqueuedAt;
|
|
47920
|
+
// depth AFTER this unit was shifted off — units still waiting behind it.
|
|
47921
|
+
queueDepthAtStart = this.queue.length;
|
|
47922
|
+
}
|
|
47911
47923
|
workFn(abortController).finally(() => {
|
|
47912
|
-
|
|
47913
|
-
|
|
47924
|
+
try {
|
|
47925
|
+
if (onWorkTiming !== undefined) {
|
|
47926
|
+
onWorkTiming(waitMs, Date.now() - startedAt, queueDepthAtStart);
|
|
47927
|
+
}
|
|
47928
|
+
}
|
|
47929
|
+
catch {
|
|
47930
|
+
// Instrumentation must not prevent the pool from releasing the worker slot.
|
|
47931
|
+
}
|
|
47932
|
+
finally {
|
|
47933
|
+
this.activeWork = this.activeWork.filter((w) => w !== newWork);
|
|
47934
|
+
this.doWork();
|
|
47935
|
+
}
|
|
47914
47936
|
});
|
|
47915
47937
|
}
|
|
47916
47938
|
}
|
|
@@ -48240,6 +48262,25 @@
|
|
|
48240
48262
|
*/
|
|
48241
48263
|
const DRAFT_ACTION_RETRY_COUNT_METADATA_KEY = 'retryCount';
|
|
48242
48264
|
class DurableDraftQueue {
|
|
48265
|
+
// Instrumentation is strictly measure-only: a broken sink must never change queue behavior.
|
|
48266
|
+
// Pass the sink into the callback so methods are invoked through their owning object and retain
|
|
48267
|
+
// their receiver (some sinks use `this` to reach their metric registry).
|
|
48268
|
+
emitInstrumentation(emit) {
|
|
48269
|
+
const { instrumentation } = this;
|
|
48270
|
+
if (instrumentation === undefined) {
|
|
48271
|
+
return;
|
|
48272
|
+
}
|
|
48273
|
+
try {
|
|
48274
|
+
emit(instrumentation);
|
|
48275
|
+
}
|
|
48276
|
+
catch {
|
|
48277
|
+
// Telemetry failures must not interrupt draft processing.
|
|
48278
|
+
}
|
|
48279
|
+
}
|
|
48280
|
+
resetDrainCycle() {
|
|
48281
|
+
this.drainCycleStart = undefined;
|
|
48282
|
+
this.drainCycleBatchCount = 0;
|
|
48283
|
+
}
|
|
48243
48284
|
getHandler(id) {
|
|
48244
48285
|
const handler = this.handlers[id];
|
|
48245
48286
|
if (handler === undefined) {
|
|
@@ -48262,9 +48303,19 @@
|
|
|
48262
48303
|
? __nimbus.plugins.JSLoggerPlugin
|
|
48263
48304
|
: undefined;
|
|
48264
48305
|
this.handlers = {};
|
|
48306
|
+
// Drain-wait attribution state. uploadStartTimes stamps when each action first began
|
|
48307
|
+
// uploading (keyed by action id) so actionCompleted/failed can emit its end-to-end drain time,
|
|
48308
|
+
// including automatic retries/backoff. actionQueueWaitEmittedIds ensures those retries do not
|
|
48309
|
+
// report the original enqueue wait more than once. drainCycleStart/BatchCount track one full
|
|
48310
|
+
// idle->empty sweep. All measure-only; when no instrumentation is injected these stay untouched.
|
|
48311
|
+
this.uploadStartTimes = new Map();
|
|
48312
|
+
this.actionQueueWaitEmittedIds = new Set();
|
|
48313
|
+
this.drainCycleBatchCount = 0;
|
|
48265
48314
|
this.draftStore = draftStore;
|
|
48266
|
-
this.workerPool = new AsyncWorkerPool(1);
|
|
48267
48315
|
this.instrumentation = instrumentation;
|
|
48316
|
+
this.workerPool = new AsyncWorkerPool(1, instrumentation?.onWorkerTiming !== undefined
|
|
48317
|
+
? (waitMs, holdMs, queueDepth) => this.emitInstrumentation((sink) => sink.onWorkerTiming?.(waitMs, holdMs, queueDepth))
|
|
48318
|
+
: undefined);
|
|
48268
48319
|
}
|
|
48269
48320
|
addHandler(handler) {
|
|
48270
48321
|
const id = handler.handlerId;
|
|
@@ -48352,6 +48403,9 @@
|
|
|
48352
48403
|
clearTimeout(this.timeoutHandler);
|
|
48353
48404
|
this.timeoutHandler = undefined;
|
|
48354
48405
|
}
|
|
48406
|
+
// A stop/user edit breaks the current sweep. A later restart starts a fresh cycle rather
|
|
48407
|
+
// than attributing stopped time to an offline drain.
|
|
48408
|
+
this.resetDrainCycle();
|
|
48355
48409
|
this.state = DraftQueueState.Stopped;
|
|
48356
48410
|
}
|
|
48357
48411
|
async getQueueActions() {
|
|
@@ -48382,7 +48436,7 @@
|
|
|
48382
48436
|
}
|
|
48383
48437
|
return aTime - bTime;
|
|
48384
48438
|
});
|
|
48385
|
-
|
|
48439
|
+
this.emitInstrumentation((sink) => sink.onGetQueueActions?.(Date.now() - start, sorted.length));
|
|
48386
48440
|
return sorted;
|
|
48387
48441
|
}
|
|
48388
48442
|
async enqueue(handlerId, data, observabilityContext) {
|
|
@@ -48426,6 +48480,13 @@
|
|
|
48426
48480
|
await handler.handleActionCompleted(action, queueOperations, values$2(this.handlers));
|
|
48427
48481
|
this.retryIntervalMilliseconds = 0;
|
|
48428
48482
|
this.uploadingActionId = undefined;
|
|
48483
|
+
// The action finished draining — emit its end-to-end drain time and
|
|
48484
|
+
// count it toward the current drain-cycle batch. Measure-only.
|
|
48485
|
+
this.emitActionDrainDuration(action.id, action.handler);
|
|
48486
|
+
this.actionQueueWaitEmittedIds.delete(action.id);
|
|
48487
|
+
if (this.drainCycleStart !== undefined) {
|
|
48488
|
+
this.drainCycleBatchCount += 1;
|
|
48489
|
+
}
|
|
48429
48490
|
await this.notifyChangedListeners({
|
|
48430
48491
|
type: DraftQueueEventType.ActionCompleted,
|
|
48431
48492
|
action,
|
|
@@ -48437,6 +48498,16 @@
|
|
|
48437
48498
|
},
|
|
48438
48499
|
});
|
|
48439
48500
|
}
|
|
48501
|
+
// Read+clear the action's upload-start stamp and emit its drain duration. Safe to
|
|
48502
|
+
// call when instrumentation is absent or the id was never stamped (no-op). Never emits the id.
|
|
48503
|
+
emitActionDrainDuration(id, handlerId) {
|
|
48504
|
+
const start = this.uploadStartTimes.get(id);
|
|
48505
|
+
if (start === undefined) {
|
|
48506
|
+
return;
|
|
48507
|
+
}
|
|
48508
|
+
this.uploadStartTimes.delete(id);
|
|
48509
|
+
this.emitInstrumentation((sink) => sink.onActionDrainDuration?.(handlerId, Date.now() - start));
|
|
48510
|
+
}
|
|
48440
48511
|
async actionFailed(action, retry, retryDelayInMs, actionDataChanged) {
|
|
48441
48512
|
if (actionDataChanged === true) {
|
|
48442
48513
|
await this.draftStore.writeAction({
|
|
@@ -48446,14 +48517,24 @@
|
|
|
48446
48517
|
}
|
|
48447
48518
|
this.uploadingActionId = undefined;
|
|
48448
48519
|
if (retry && this.state !== DraftQueueState.Stopped) {
|
|
48520
|
+
// A retry means this action is NOT done draining. Keep its first-upload stamp and the
|
|
48521
|
+
// open cycle so the eventual outcome includes network time and retry/backoff.
|
|
48449
48522
|
this.state = DraftQueueState.Waiting;
|
|
48450
48523
|
return retryDelayInMs !== undefined
|
|
48451
48524
|
? this.scheduleRetryWithSpecifiedDelay(retryDelayInMs)
|
|
48452
48525
|
: this.scheduleRetry();
|
|
48453
48526
|
}
|
|
48454
48527
|
else if (isDraftError(action)) {
|
|
48528
|
+
// Terminal failure — this action is done draining. Emit its drain time.
|
|
48529
|
+
this.emitActionDrainDuration(action.id, action.handler);
|
|
48530
|
+
// This was not a clean drain-to-empty. Discard the sweep before user intervention so a
|
|
48531
|
+
// later manual retry/removal cannot inherit its elapsed time or completed batch count.
|
|
48532
|
+
this.resetDrainCycle();
|
|
48455
48533
|
return this.handleServerError(action, action.error);
|
|
48456
48534
|
}
|
|
48535
|
+
// Any other terminal path — ensure no stale start stamp lingers.
|
|
48536
|
+
this.emitActionDrainDuration(action.id, action.handler);
|
|
48537
|
+
this.resetDrainCycle();
|
|
48457
48538
|
}
|
|
48458
48539
|
handle(action) {
|
|
48459
48540
|
const handler = this.getHandler(action.handler);
|
|
@@ -48473,12 +48554,22 @@
|
|
|
48473
48554
|
this.state = DraftQueueState.Started;
|
|
48474
48555
|
}
|
|
48475
48556
|
this.processingAction = undefined;
|
|
48557
|
+
// The queue drained empty — close the drain-cycle window if one was open.
|
|
48558
|
+
if (this.drainCycleStart !== undefined) {
|
|
48559
|
+
const durationMs = Date.now() - this.drainCycleStart;
|
|
48560
|
+
const batchSize = this.drainCycleBatchCount;
|
|
48561
|
+
this.resetDrainCycle();
|
|
48562
|
+
this.emitInstrumentation((sink) => sink.onDrainCycle?.(durationMs, batchSize));
|
|
48563
|
+
}
|
|
48476
48564
|
return ProcessActionResult.NO_ACTION_TO_PROCESS;
|
|
48477
48565
|
}
|
|
48478
48566
|
const { status, id } = action;
|
|
48479
48567
|
if (status === DraftActionStatus.Error) {
|
|
48480
48568
|
this.state = DraftQueueState.Error;
|
|
48481
48569
|
this.processingAction = undefined;
|
|
48570
|
+
// The sweep is blocked on an errored action, not a clean drain-to-empty —
|
|
48571
|
+
// discard the open drain-cycle window so it doesn't inflate a later cycle's duration.
|
|
48572
|
+
this.resetDrainCycle();
|
|
48482
48573
|
await this.notifyChangedListeners({
|
|
48483
48574
|
type: DraftQueueEventType.ActionFailed,
|
|
48484
48575
|
action: action,
|
|
@@ -48496,6 +48587,31 @@
|
|
|
48496
48587
|
if (this.state === DraftQueueState.Waiting) {
|
|
48497
48588
|
this.state = DraftQueueState.Started;
|
|
48498
48589
|
}
|
|
48590
|
+
// The action is now leaving the queue to upload. Emit head-of-line FIFO wait
|
|
48591
|
+
// (enqueue -> upload start), stamp its drain-start for end-to-end timing on completion, and
|
|
48592
|
+
// open a drain-cycle window if the queue was previously idle. All measure-only.
|
|
48593
|
+
const { instrumentation } = this;
|
|
48594
|
+
if (instrumentation !== undefined) {
|
|
48595
|
+
const now = Date.now();
|
|
48596
|
+
const { timestamp } = action;
|
|
48597
|
+
if (instrumentation.onActionQueueWait !== undefined &&
|
|
48598
|
+
!this.actionQueueWaitEmittedIds.has(id) &&
|
|
48599
|
+
typeof timestamp === 'number' &&
|
|
48600
|
+
timestamp > 0) {
|
|
48601
|
+
// Mark before invoking the sink: even a throwing callback must not make a retry
|
|
48602
|
+
// report the same action's enqueue wait again.
|
|
48603
|
+
this.actionQueueWaitEmittedIds.add(id);
|
|
48604
|
+
this.emitInstrumentation((sink) => sink.onActionQueueWait?.(action.handler, now - timestamp));
|
|
48605
|
+
}
|
|
48606
|
+
if (instrumentation.onActionDrainDuration !== undefined &&
|
|
48607
|
+
!this.uploadStartTimes.has(id)) {
|
|
48608
|
+
this.uploadStartTimes.set(id, now);
|
|
48609
|
+
}
|
|
48610
|
+
if (instrumentation.onDrainCycle !== undefined && this.drainCycleStart === undefined) {
|
|
48611
|
+
this.drainCycleStart = now;
|
|
48612
|
+
this.drainCycleBatchCount = 0;
|
|
48613
|
+
}
|
|
48614
|
+
}
|
|
48499
48615
|
await this.notifyChangedListeners({
|
|
48500
48616
|
type: DraftQueueEventType.ActionUploading,
|
|
48501
48617
|
action: { ...action, status: DraftActionStatus.Uploading },
|
|
@@ -48533,7 +48649,7 @@
|
|
|
48533
48649
|
results.push(listener(event));
|
|
48534
48650
|
}
|
|
48535
48651
|
// W-23515682: listener fan-out per event type. Measure-only.
|
|
48536
|
-
this.
|
|
48652
|
+
this.emitInstrumentation((sink) => sink.onNotifyChangedListeners?.(event.type, draftQueueLen));
|
|
48537
48653
|
await Promise.all(results);
|
|
48538
48654
|
}
|
|
48539
48655
|
/**
|
|
@@ -48562,9 +48678,17 @@
|
|
|
48562
48678
|
const shouldDeleteRelated = handler.shouldDeleteActionByTagOnRemoval(action);
|
|
48563
48679
|
if (shouldDeleteRelated) {
|
|
48564
48680
|
await this.draftStore.deleteByTag(action.tag);
|
|
48681
|
+
queue.forEach((queuedAction) => {
|
|
48682
|
+
if (queuedAction.tag === action.tag) {
|
|
48683
|
+
this.uploadStartTimes.delete(queuedAction.id);
|
|
48684
|
+
this.actionQueueWaitEmittedIds.delete(queuedAction.id);
|
|
48685
|
+
}
|
|
48686
|
+
});
|
|
48565
48687
|
}
|
|
48566
48688
|
else {
|
|
48567
48689
|
await this.draftStore.deleteDraft(action.id);
|
|
48690
|
+
this.uploadStartTimes.delete(action.id);
|
|
48691
|
+
this.actionQueueWaitEmittedIds.delete(action.id);
|
|
48568
48692
|
}
|
|
48569
48693
|
await handler.handleActionRemoved(action, queue.filter((x) => x.id !== actionId));
|
|
48570
48694
|
await this.notifyChangedListeners({
|
|
@@ -80196,6 +80320,20 @@
|
|
|
80196
80320
|
const DRAFT_QUEUE_NOTIFY_CHANGED_LISTENERS_COUNT = 'draft-queue-notify-changed-listeners-count';
|
|
80197
80321
|
const DRAFT_QUEUE_DURABLE_OP_COUNT = 'draft-queue-durable-op-count';
|
|
80198
80322
|
const DRAFT_QUEUE_DURABLE_OP_DURATION = 'draft-queue-durable-op-duration';
|
|
80323
|
+
// Drain-wait attribution telemetry: the wall-clock spine of where an offline drain actually spends
|
|
80324
|
+
// WAITING. Operational counts/durations/depths only — no draft content, field values, or server
|
|
80325
|
+
// record ids (matching the existing draft-queue privacy stance).
|
|
80326
|
+
const DRAFT_QUEUE_WORKER_WAIT_DURATION = 'draft-queue-worker-wait-duration';
|
|
80327
|
+
const DRAFT_QUEUE_WORKER_HOLD_DURATION = 'draft-queue-worker-hold-duration';
|
|
80328
|
+
const DRAFT_QUEUE_ACTION_QUEUE_WAIT_DURATION = 'draft-queue-action-queue-wait-duration';
|
|
80329
|
+
const DRAFT_QUEUE_ACTION_DRAIN_DURATION = 'draft-queue-action-drain-duration';
|
|
80330
|
+
const DRAFT_QUEUE_DRAIN_CYCLE_DURATION = 'draft-queue-drain-cycle-duration';
|
|
80331
|
+
const DRAFT_QUEUE_DRAIN_CYCLE_BATCH_SIZE = 'draft-queue-drain-cycle-batch-size';
|
|
80332
|
+
const DRAFT_QUEUE_ACTION_NETWORK_DURATION = 'draft-queue-action-network-duration';
|
|
80333
|
+
const DRAFT_QUEUE_ACTION_RETRY_ATTEMPT = 'draft-queue-action-retry-attempt';
|
|
80334
|
+
const DRAFT_QUEUE_SIDEEFFECT_OP_DURATION = 'draft-queue-sideeffect-op-duration';
|
|
80335
|
+
const DRAFT_QUEUE_SIDEEFFECT_MAP_SIZE = 'draft-queue-sideeffect-map-size';
|
|
80336
|
+
const DRAFT_QUEUE_SIDEEFFECT_REGION_DURATION = 'draft-queue-sideeffect-region-duration';
|
|
80199
80337
|
/** Content Document */
|
|
80200
80338
|
const CREATE_CONTENT_DOCUMENT_AND_VERSION_TOTAL_SYNTHESIZE_CALLS = 'content-document-version-total-synthesize-calls';
|
|
80201
80339
|
const CREATE_CONTENT_DOCUMENT_AND_VERSION_DRAFT_SYNTHESIZE_ERROR = 'create-content-document-version-draft-synthesize-error';
|
|
@@ -80315,6 +80453,134 @@
|
|
|
80315
80453
|
});
|
|
80316
80454
|
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_DURABLE_OP_DURATION, durationMs);
|
|
80317
80455
|
}
|
|
80456
|
+
const DRAIN_DURATION_BUCKETS = [50, 100, 250, 500, 1000, 2500, 5000, 10000, 30000];
|
|
80457
|
+
const WORKER_DEPTH_BUCKETS = [1, 2, 5, 10, 20, 50, 100, 250, 500];
|
|
80458
|
+
// Handler ids are extensible through DraftManager, so only retain the fixed mobile handlers in
|
|
80459
|
+
// metric tags. Everything else shares one bounded bucket rather than creating an unbounded series.
|
|
80460
|
+
function draftQueueHandlerTagOf(handlerId) {
|
|
80461
|
+
switch (handlerId) {
|
|
80462
|
+
case 'LDS_ACTION_HANDLER':
|
|
80463
|
+
case 'ContentDocumentCompositeRepresentationActionHandler':
|
|
80464
|
+
case 'QUICK_ACTION_HANDLER':
|
|
80465
|
+
case 'UPDATE_RECORD_QUICK_ACTION_HANDLER':
|
|
80466
|
+
return handlerId;
|
|
80467
|
+
default:
|
|
80468
|
+
return 'custom';
|
|
80469
|
+
}
|
|
80470
|
+
}
|
|
80471
|
+
// Coarse, bounded-cardinality label for the pool depth a unit saw when it began, so the
|
|
80472
|
+
// wait/hold durations can be sliced BY backlog size without emitting depth as a free integer tag.
|
|
80473
|
+
function workerDepthBucketOf(queueDepth) {
|
|
80474
|
+
if (queueDepth <= 0) {
|
|
80475
|
+
return '0';
|
|
80476
|
+
}
|
|
80477
|
+
if (queueDepth <= 2) {
|
|
80478
|
+
return '1-2';
|
|
80479
|
+
}
|
|
80480
|
+
if (queueDepth <= 10) {
|
|
80481
|
+
return '3-10';
|
|
80482
|
+
}
|
|
80483
|
+
if (queueDepth <= 50) {
|
|
80484
|
+
return '11-50';
|
|
80485
|
+
}
|
|
80486
|
+
if (queueDepth <= 250) {
|
|
80487
|
+
return '51-250';
|
|
80488
|
+
}
|
|
80489
|
+
return '250+';
|
|
80490
|
+
}
|
|
80491
|
+
/**
|
|
80492
|
+
* Per-unit lifecycle split for the AsyncWorkerPool(1) serial queue, emitted once when a unit settles
|
|
80493
|
+
* so the two halves are a JOINED event (rather than shipping wait and depth as unrelated aggregates).
|
|
80494
|
+
* Isolates WHERE the time goes:
|
|
80495
|
+
* waitMs — enqueue -> work began (waiting on the serial queue before any logic runs).
|
|
80496
|
+
* holdMs — work began -> work settled (the critical section's own O(N) service time).
|
|
80497
|
+
* Both are additionally tagged by a depthBucket so "does per-unit cost scale with backlog depth"
|
|
80498
|
+
* (the O(N^2) signature) survives aggregation. queueDepth itself is also tracked. Operational only.
|
|
80499
|
+
*/
|
|
80500
|
+
function reportDraftQueueWorkerTiming(waitMs, holdMs, queueDepth) {
|
|
80501
|
+
const depthBucket = workerDepthBucketOf(queueDepth);
|
|
80502
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_WORKER_WAIT_DURATION, waitMs, undefined, {
|
|
80503
|
+
depthBucket,
|
|
80504
|
+
});
|
|
80505
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_WORKER_HOLD_DURATION, holdMs, undefined, {
|
|
80506
|
+
depthBucket,
|
|
80507
|
+
});
|
|
80508
|
+
ldsMobileInstrumentation$2.bucketValue(DRAFT_QUEUE_WORKER_WAIT_DURATION + '-depth', queueDepth, WORKER_DEPTH_BUCKETS);
|
|
80509
|
+
}
|
|
80510
|
+
/**
|
|
80511
|
+
* Head-of-line FIFO wait for one draft (enqueue -> upload start), bucketed so the
|
|
80512
|
+
* "does wait grow with backlog depth" (O(N^2)) signal is visible per handler type. Custom handler
|
|
80513
|
+
* ids are normalized to one bounded tag so caller-defined values never become metric dimensions.
|
|
80514
|
+
*/
|
|
80515
|
+
function reportDraftQueueActionQueueWait(handlerId, waitMs) {
|
|
80516
|
+
ldsMobileInstrumentation$2.bucketValue(DRAFT_QUEUE_ACTION_QUEUE_WAIT_DURATION, waitMs, DRAIN_DURATION_BUCKETS, undefined, { handlerId: draftQueueHandlerTagOf(handlerId) });
|
|
80517
|
+
}
|
|
80518
|
+
/**
|
|
80519
|
+
* End-to-end drain time for one action (first upload attempt -> completed/failed), including
|
|
80520
|
+
* retry/backoff. Compare it with network-duration and retry-attempt signals to understand the
|
|
80521
|
+
* non-request portion of the drain interval.
|
|
80522
|
+
*/
|
|
80523
|
+
function reportDraftQueueActionDrainDuration(handlerId, durationMs) {
|
|
80524
|
+
ldsMobileInstrumentation$2.bucketValue(DRAFT_QUEUE_ACTION_DRAIN_DURATION, durationMs, DRAIN_DURATION_BUCKETS, undefined, { handlerId: draftQueueHandlerTagOf(handlerId) });
|
|
80525
|
+
}
|
|
80526
|
+
/**
|
|
80527
|
+
* One full drain sweep — first action starts uploading -> queue empties. Both raw values share a
|
|
80528
|
+
* bounded batch-size cohort so aggregate duration remains sliceable by the number of actions drained.
|
|
80529
|
+
*/
|
|
80530
|
+
function reportDraftQueueDrainCycle(durationMs, batchSize) {
|
|
80531
|
+
const batchSizeBucket = workerDepthBucketOf(batchSize);
|
|
80532
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_DRAIN_CYCLE_DURATION, durationMs, undefined, {
|
|
80533
|
+
batchSizeBucket,
|
|
80534
|
+
});
|
|
80535
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_DRAIN_CYCLE_BATCH_SIZE, batchSize, undefined, {
|
|
80536
|
+
batchSizeBucket,
|
|
80537
|
+
});
|
|
80538
|
+
}
|
|
80539
|
+
/**
|
|
80540
|
+
* Server round-trip duration for one upload. Isolates slow-network from CPU-bound
|
|
80541
|
+
* quadratic work — today only a THROWN error is captured, so a slow-but-successful (or slow 4xx/5xx)
|
|
80542
|
+
* response is invisible. Tags: handler type, HTTP method, and a bucketed status class ('2xx'/'4xx'/
|
|
80543
|
+
* '5xx'/'0'). No URL, body, or record id.
|
|
80544
|
+
*/
|
|
80545
|
+
function reportDraftQueueActionNetworkDuration(handlerId, method, statusBucket, durationMs) {
|
|
80546
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_ACTION_NETWORK_DURATION, durationMs, undefined, {
|
|
80547
|
+
handlerId: draftQueueHandlerTagOf(handlerId),
|
|
80548
|
+
method,
|
|
80549
|
+
statusBucket,
|
|
80550
|
+
});
|
|
80551
|
+
}
|
|
80552
|
+
/**
|
|
80553
|
+
* Retry event count. Repeated events identify actions cycling through the drain even when the retry
|
|
80554
|
+
* cap is disabled and an exact attempt number is not persisted. cappedOut marks cap exhaustion.
|
|
80555
|
+
*/
|
|
80556
|
+
function reportDraftQueueActionRetryAttempt(handlerId, cappedOut) {
|
|
80557
|
+
ldsMobileInstrumentation$2.incrementCounter(DRAFT_QUEUE_ACTION_RETRY_ATTEMPT, 1, undefined, {
|
|
80558
|
+
handlerId: draftQueueHandlerTagOf(handlerId),
|
|
80559
|
+
cappedOut: String(cappedOut),
|
|
80560
|
+
});
|
|
80561
|
+
}
|
|
80562
|
+
/**
|
|
80563
|
+
* SideEffectStore operation duration + map size. The incremental map sped up the by-KEY lookup but
|
|
80564
|
+
* getEffectsByTag still linearly scans all effects — this measures whether that residual scan is
|
|
80565
|
+
* silently quadratic during churn. op is 'add'|'remove'|'getByTag'; incremental flags the fast path;
|
|
80566
|
+
* mapSize is an integer effect count. No record keys, field names, or field values.
|
|
80567
|
+
*/
|
|
80568
|
+
function reportDraftQueueSideEffectOp(op, incremental, durationMs, mapSize) {
|
|
80569
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_SIDEEFFECT_OP_DURATION, durationMs, undefined, {
|
|
80570
|
+
op,
|
|
80571
|
+
incremental: String(incremental),
|
|
80572
|
+
});
|
|
80573
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_SIDEEFFECT_MAP_SIZE, mapSize, undefined, {
|
|
80574
|
+
op,
|
|
80575
|
+
});
|
|
80576
|
+
}
|
|
80577
|
+
/**
|
|
80578
|
+
* Broad side-effect lifecycle duration. The fixed region and lifecycle tags identify which part of
|
|
80579
|
+
* serialized draft processing is slow without emitting record keys, action ids, or field data.
|
|
80580
|
+
*/
|
|
80581
|
+
function reportDraftQueueSideEffectRegionDuration(region, lifecycle, durationMs) {
|
|
80582
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_SIDEEFFECT_REGION_DURATION, durationMs, undefined, { region, lifecycle });
|
|
80583
|
+
}
|
|
80318
80584
|
/**
|
|
80319
80585
|
* Reports an exception thrown while uploading a draft action. The thrown error is
|
|
80320
80586
|
* otherwise swallowed by the upload handler's retry path, leaving the failure
|
|
@@ -80522,8 +80788,16 @@
|
|
|
80522
80788
|
const dispatchOptions = action.observabilityContext !== undefined
|
|
80523
80789
|
? { requestCorrelator: { observabilityContext: action.observabilityContext } }
|
|
80524
80790
|
: {};
|
|
80791
|
+
const method = request?.method?.toUpperCase() ?? 'UNKNOWN';
|
|
80792
|
+
const networkStart = Date.now();
|
|
80793
|
+
let responseReceived = false;
|
|
80525
80794
|
try {
|
|
80526
80795
|
const response = await this.networkAdapter(request, dispatchOptions);
|
|
80796
|
+
responseReceived = true;
|
|
80797
|
+
// Time the round-trip regardless of outcome (ok, retryable HTTP error, or non-ok
|
|
80798
|
+
// terminal error) — today only a THROWN error is visible; a slow-but-successful or
|
|
80799
|
+
// slow 4xx/5xx response is not.
|
|
80800
|
+
this.reportNetworkDuration(method, statusBucketOf(response.status), networkStart);
|
|
80527
80801
|
if (response.ok) {
|
|
80528
80802
|
await actionCompleted({
|
|
80529
80803
|
...action,
|
|
@@ -80679,6 +80953,11 @@
|
|
|
80679
80953
|
const error = normalizeError$1(e);
|
|
80680
80954
|
const attempt = this.getUploadRetryCount(action) + 1;
|
|
80681
80955
|
reportDraftActionUploadError(error, this.handlerId, attempt);
|
|
80956
|
+
// A thrown network call still has a round-trip duration worth surfacing — a slow
|
|
80957
|
+
// FAILING call is otherwise as invisible as a slow successful one.
|
|
80958
|
+
if (!responseReceived) {
|
|
80959
|
+
this.reportNetworkDuration(method, 'error', networkStart);
|
|
80960
|
+
}
|
|
80682
80961
|
await this.retryOrCap(action, error, actionErrored);
|
|
80683
80962
|
return ProcessActionResult.NETWORK_ERROR;
|
|
80684
80963
|
}
|
|
@@ -80714,12 +80993,17 @@
|
|
|
80714
80993
|
*/
|
|
80715
80994
|
async retryOrCap(action, lastFailure, actionErrored, retryDelayInMs, actionDataChanged) {
|
|
80716
80995
|
if (!draftQueueMaxRetryAttemptsGate.isOpen({ fallback: false })) {
|
|
80717
|
-
// Gate closed: preserve the pre-existing unbounded-retry behavior exactly.
|
|
80996
|
+
// Gate closed: preserve the pre-existing unbounded-retry behavior exactly. The
|
|
80997
|
+
// metric is still emitted (measure-only) so retry attempts are visible even with
|
|
80998
|
+
// the cap gate closed — cappedOut is always false here since nothing ever caps
|
|
80999
|
+
// out on this path.
|
|
81000
|
+
this.reportRetryAttempt(false);
|
|
80718
81001
|
await actionErrored(action, true, retryDelayInMs, actionDataChanged);
|
|
80719
81002
|
return;
|
|
80720
81003
|
}
|
|
80721
81004
|
const attempt = this.getUploadRetryCount(action) + 1;
|
|
80722
81005
|
if (attempt >= MAX_RETRY_ATTEMPTS) {
|
|
81006
|
+
this.reportRetryAttempt(true);
|
|
80723
81007
|
await actionErrored({
|
|
80724
81008
|
...action,
|
|
80725
81009
|
error: buildMaxRetryError(lastFailure),
|
|
@@ -80727,6 +81011,7 @@
|
|
|
80727
81011
|
}, false);
|
|
80728
81012
|
return;
|
|
80729
81013
|
}
|
|
81014
|
+
this.reportRetryAttempt(false);
|
|
80730
81015
|
// Persist the incremented attempt count so it survives restarts. Forcing
|
|
80731
81016
|
// actionDataChanged ensures the queue writes the updated metadata before the
|
|
80732
81017
|
// action is rescheduled for retry.
|
|
@@ -80740,12 +81025,12 @@
|
|
|
80740
81025
|
await actionErrored(retryingAction, true, retryDelayInMs, true);
|
|
80741
81026
|
}
|
|
80742
81027
|
async handleActionEnqueued(action) {
|
|
80743
|
-
const impactedKeys = await this.recordService.setSideEffectsForActions([action]);
|
|
80744
|
-
await this.recordService.reapplyRecordSideEffects(impactedKeys);
|
|
81028
|
+
const impactedKeys = await this.recordService.setSideEffectsForActions([action], 'enqueued');
|
|
81029
|
+
await this.recordService.reapplyRecordSideEffects(impactedKeys, 'enqueued');
|
|
80745
81030
|
}
|
|
80746
81031
|
async handleActionRemoved(action) {
|
|
80747
81032
|
const impactedKeys = await this.recordService.removeSideEffectsForAction(action);
|
|
80748
|
-
await this.recordService.reapplyRecordSideEffects(impactedKeys);
|
|
81033
|
+
await this.recordService.reapplyRecordSideEffects(impactedKeys, 'removed');
|
|
80749
81034
|
}
|
|
80750
81035
|
async handleActionReplaced(target, source) {
|
|
80751
81036
|
// remove both the siden effects from the actions being merged before we
|
|
@@ -80753,10 +81038,10 @@
|
|
|
80753
81038
|
const impactedKeysFromRemove = await this.recordService.removeSideEffectsForAction(source);
|
|
80754
81039
|
const removedSideEffectFromSet = await this.recordService.removeSideEffectsForAction(target);
|
|
80755
81040
|
// revert the values in the DEFAULT store back to what it was before the removed side effects
|
|
80756
|
-
await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromRemove, ...removedSideEffectFromSet]));
|
|
81041
|
+
await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromRemove, ...removedSideEffectFromSet]), 'replaced-remove');
|
|
80757
81042
|
// set the new side effect values for the merged action
|
|
80758
|
-
const impactedKeysFromSet = await this.recordService.setSideEffectsForActions([target]);
|
|
80759
|
-
await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromSet]));
|
|
81043
|
+
const impactedKeysFromSet = await this.recordService.setSideEffectsForActions([target], 'replaced-set');
|
|
81044
|
+
await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromSet]), 'replaced-set');
|
|
80760
81045
|
}
|
|
80761
81046
|
async handleActionCompleted(action, queueOperations) {
|
|
80762
81047
|
const { data: request, tag } = action;
|
|
@@ -80790,8 +81075,8 @@
|
|
|
80790
81075
|
actionsNeedingReplay.push(qo.action);
|
|
80791
81076
|
}
|
|
80792
81077
|
});
|
|
80793
|
-
const impactedKeys = await this.recordService.setSideEffectsForActions(actionsNeedingReplay);
|
|
80794
|
-
await this.recordService.reapplyRecordSideEffects(impactedKeys);
|
|
81078
|
+
const impactedKeys = await this.recordService.setSideEffectsForActions(actionsNeedingReplay, 'completed-replay');
|
|
81079
|
+
await this.recordService.reapplyRecordSideEffects(impactedKeys, 'completed-replay');
|
|
80795
81080
|
}
|
|
80796
81081
|
getQueueOperationsForCompletingDrafts(queue, action) {
|
|
80797
81082
|
const queueOperations = [];
|
|
@@ -81117,6 +81402,39 @@
|
|
|
81117
81402
|
return new StoreKeyMap();
|
|
81118
81403
|
});
|
|
81119
81404
|
}
|
|
81405
|
+
reportNetworkDuration(method, statusBucket, startedAt) {
|
|
81406
|
+
try {
|
|
81407
|
+
reportDraftQueueActionNetworkDuration(this.handlerId, method, statusBucket, Date.now() - startedAt);
|
|
81408
|
+
}
|
|
81409
|
+
catch {
|
|
81410
|
+
// Telemetry must not change upload processing behavior.
|
|
81411
|
+
}
|
|
81412
|
+
}
|
|
81413
|
+
reportRetryAttempt(cappedOut) {
|
|
81414
|
+
try {
|
|
81415
|
+
reportDraftQueueActionRetryAttempt(this.handlerId, cappedOut);
|
|
81416
|
+
}
|
|
81417
|
+
catch {
|
|
81418
|
+
// Telemetry must not change retry or cap behavior.
|
|
81419
|
+
}
|
|
81420
|
+
}
|
|
81421
|
+
}
|
|
81422
|
+
// Classifies an HTTP status into a small, greppable tag set for the network-duration metric —
|
|
81423
|
+
// never the raw status, to keep the metric's tag cardinality bounded.
|
|
81424
|
+
function statusBucketOf(status) {
|
|
81425
|
+
if (status === 0) {
|
|
81426
|
+
return '0';
|
|
81427
|
+
}
|
|
81428
|
+
if (status >= 200 && status <= 299) {
|
|
81429
|
+
return '2xx';
|
|
81430
|
+
}
|
|
81431
|
+
if (status >= 400 && status <= 499) {
|
|
81432
|
+
return '4xx';
|
|
81433
|
+
}
|
|
81434
|
+
if (status >= 500) {
|
|
81435
|
+
return '5xx';
|
|
81436
|
+
}
|
|
81437
|
+
return 'other';
|
|
81120
81438
|
}
|
|
81121
81439
|
function actionsForTag(tag, queue) {
|
|
81122
81440
|
return queue.filter((action) => action.tag === tag);
|
|
@@ -81480,10 +81798,16 @@
|
|
|
81480
81798
|
}
|
|
81481
81799
|
// calculates the side effects for a given set of actions
|
|
81482
81800
|
// and returns a set of impacted record keys
|
|
81483
|
-
async setSideEffectsForActions(changedActions) {
|
|
81484
|
-
const
|
|
81485
|
-
|
|
81486
|
-
|
|
81801
|
+
async setSideEffectsForActions(changedActions, lifecycle) {
|
|
81802
|
+
const startedAt = Date.now();
|
|
81803
|
+
try {
|
|
81804
|
+
const operations = await this.recalculateForChangedActions(changedActions);
|
|
81805
|
+
await this.sideEffectStore.addEffects(operations);
|
|
81806
|
+
return new Set(operations.map((o) => o.key));
|
|
81807
|
+
}
|
|
81808
|
+
finally {
|
|
81809
|
+
this.reportSideEffectRegionDuration('set', lifecycle, startedAt);
|
|
81810
|
+
}
|
|
81487
81811
|
}
|
|
81488
81812
|
// removes the associated side effects for a given action and returns
|
|
81489
81813
|
// a set of impacted record keys
|
|
@@ -81494,31 +81818,45 @@
|
|
|
81494
81818
|
}
|
|
81495
81819
|
// reads a set of records out of the durable store, re-applies current side
|
|
81496
81820
|
// effects and persists the changed record
|
|
81497
|
-
async reapplyRecordSideEffects(recordKeys) {
|
|
81498
|
-
const
|
|
81499
|
-
|
|
81500
|
-
|
|
81501
|
-
|
|
81502
|
-
|
|
81503
|
-
|
|
81504
|
-
|
|
81505
|
-
|
|
81506
|
-
|
|
81507
|
-
|
|
81508
|
-
|
|
81509
|
-
|
|
81510
|
-
|
|
81511
|
-
|
|
81512
|
-
|
|
81513
|
-
if (recordEntry
|
|
81514
|
-
|
|
81515
|
-
metadata
|
|
81821
|
+
async reapplyRecordSideEffects(recordKeys, lifecycle) {
|
|
81822
|
+
const startedAt = Date.now();
|
|
81823
|
+
try {
|
|
81824
|
+
const luvio = this.getLuvio();
|
|
81825
|
+
const keys = Array.from(recordKeys);
|
|
81826
|
+
const recordEntries = await this.durableRecordStore.getRecordsWithMetadata(keys);
|
|
81827
|
+
keys.forEach((key) => {
|
|
81828
|
+
let record;
|
|
81829
|
+
const metadata = {
|
|
81830
|
+
namespace: 'UiApi',
|
|
81831
|
+
representationName: 'RecordRepresentation',
|
|
81832
|
+
version: VERSION$1v$1,
|
|
81833
|
+
ingestionTimestamp: Date.now(),
|
|
81834
|
+
ttl: Number.MAX_SAFE_INTEGER,
|
|
81835
|
+
};
|
|
81836
|
+
const recordEntry = recordEntries.get(key);
|
|
81837
|
+
if (recordEntry) {
|
|
81838
|
+
record = recordEntry.record;
|
|
81839
|
+
if (recordEntry.metadata) {
|
|
81840
|
+
metadata.ingestionTimestamp = recordEntry.metadata.ingestionTimestamp;
|
|
81841
|
+
metadata.ttl = TTL$z;
|
|
81842
|
+
}
|
|
81516
81843
|
}
|
|
81517
|
-
|
|
81518
|
-
|
|
81519
|
-
|
|
81520
|
-
|
|
81521
|
-
|
|
81844
|
+
luvio.storePublish(key, record);
|
|
81845
|
+
luvio.publishStoreMetadata(key, metadata);
|
|
81846
|
+
});
|
|
81847
|
+
await luvio.storeBroadcast();
|
|
81848
|
+
}
|
|
81849
|
+
finally {
|
|
81850
|
+
this.reportSideEffectRegionDuration('reapply', lifecycle, startedAt);
|
|
81851
|
+
}
|
|
81852
|
+
}
|
|
81853
|
+
reportSideEffectRegionDuration(region, lifecycle, startedAt) {
|
|
81854
|
+
try {
|
|
81855
|
+
reportDraftQueueSideEffectRegionDuration(region, lifecycle, Date.now() - startedAt);
|
|
81856
|
+
}
|
|
81857
|
+
catch {
|
|
81858
|
+
// Telemetry must not change draft processing behavior.
|
|
81859
|
+
}
|
|
81522
81860
|
}
|
|
81523
81861
|
async synthesizeId(apiName) {
|
|
81524
81862
|
const objectInfo = await this.objectInfoService.getObjectInfo(apiName);
|
|
@@ -81754,7 +82092,7 @@
|
|
|
81754
82092
|
// since we don't ingest a record from the response, we need to manually trigger a re-apply here to ensure we
|
|
81755
82093
|
// re-ingest the record without effects applied
|
|
81756
82094
|
await this.recordService.removeSideEffectsForAction(action);
|
|
81757
|
-
await this.recordService.reapplyRecordSideEffects(new Set([action.tag]));
|
|
82095
|
+
await this.recordService.reapplyRecordSideEffects(new Set([action.tag]), 'quick-action-completed');
|
|
81758
82096
|
// notify luvio that record is now changed and needs to be refreshed
|
|
81759
82097
|
await luvio.notifyStoreUpdateAvailable([action.tag]);
|
|
81760
82098
|
}
|
|
@@ -90434,6 +90772,18 @@
|
|
|
90434
90772
|
onDurableOperation(op, segment, durationMs) {
|
|
90435
90773
|
reportDraftQueueDurableOperation(op, segment, durationMs);
|
|
90436
90774
|
},
|
|
90775
|
+
onWorkerTiming(waitMs, holdMs, queueDepth) {
|
|
90776
|
+
reportDraftQueueWorkerTiming(waitMs, holdMs, queueDepth);
|
|
90777
|
+
},
|
|
90778
|
+
onActionQueueWait(handlerId, waitMs) {
|
|
90779
|
+
reportDraftQueueActionQueueWait(handlerId, waitMs);
|
|
90780
|
+
},
|
|
90781
|
+
onActionDrainDuration(handlerId, durationMs) {
|
|
90782
|
+
reportDraftQueueActionDrainDuration(handlerId, durationMs);
|
|
90783
|
+
},
|
|
90784
|
+
onDrainCycle(durationMs, batchSize) {
|
|
90785
|
+
reportDraftQueueDrainCycle(durationMs, batchSize);
|
|
90786
|
+
},
|
|
90437
90787
|
};
|
|
90438
90788
|
|
|
90439
90789
|
// so eslint doesn't complain about nimbus
|
|
@@ -93776,6 +94126,9 @@
|
|
|
93776
94126
|
this.initialize();
|
|
93777
94127
|
}
|
|
93778
94128
|
async addEffects(effects) {
|
|
94129
|
+
// Wall-clock across the whole method (including the durable write), matching
|
|
94130
|
+
// how the equivalent removeEffects/getEffectsByTag windows are measured.
|
|
94131
|
+
const startTime = Date.now();
|
|
93779
94132
|
const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
|
|
93780
94133
|
const durableEntries = {};
|
|
93781
94134
|
effects.forEach((effect) => {
|
|
@@ -93790,8 +94143,11 @@
|
|
|
93790
94143
|
this.regenerateKeyToEffectMap();
|
|
93791
94144
|
}
|
|
93792
94145
|
await this.durableStore.setEntries(durableEntries, SIDE_EFFECT_SEGMENT);
|
|
94146
|
+
this.reportOperation('add', incremental, startTime);
|
|
93793
94147
|
}
|
|
93794
94148
|
async removeEffects(effects) {
|
|
94149
|
+
// See addEffects — same wall-clock-across-the-method measurement.
|
|
94150
|
+
const startTime = Date.now();
|
|
93795
94151
|
const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
|
|
93796
94152
|
const effectKeys = effects.map((e) => e.uniqueId);
|
|
93797
94153
|
effects.forEach((effect) => {
|
|
@@ -93805,6 +94161,7 @@
|
|
|
93805
94161
|
this.regenerateKeyToEffectMap();
|
|
93806
94162
|
}
|
|
93807
94163
|
await this.durableStore.evictEntries(effectKeys, SIDE_EFFECT_SEGMENT);
|
|
94164
|
+
this.reportOperation('remove', incremental, startTime);
|
|
93808
94165
|
}
|
|
93809
94166
|
getEffects(key) {
|
|
93810
94167
|
const effects = this.keyToEffectMap.get(key);
|
|
@@ -93814,6 +94171,10 @@
|
|
|
93814
94171
|
return effects;
|
|
93815
94172
|
}
|
|
93816
94173
|
getEffectsByTag(tag) {
|
|
94174
|
+
// This scan is still O(N) over every effect regardless of the incremental-map
|
|
94175
|
+
// gate — timing it tells us whether that residual scan is the quadratic hotspot during churn.
|
|
94176
|
+
const startTime = Date.now();
|
|
94177
|
+
const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
|
|
93817
94178
|
const filteredEffects = [];
|
|
93818
94179
|
const { keyToEffectMap } = this;
|
|
93819
94180
|
// Loop through every entry in the map
|
|
@@ -93823,7 +94184,17 @@
|
|
|
93823
94184
|
// Add the matching effects to the filtered list
|
|
93824
94185
|
filteredEffects.push(...matchingEffects);
|
|
93825
94186
|
}
|
|
93826
|
-
|
|
94187
|
+
const result = filteredEffects.sort((a, b) => a.timestamp - b.timestamp);
|
|
94188
|
+
this.reportOperation('getByTag', incremental, startTime);
|
|
94189
|
+
return result;
|
|
94190
|
+
}
|
|
94191
|
+
reportOperation(op, incremental, startedAt) {
|
|
94192
|
+
try {
|
|
94193
|
+
reportDraftQueueSideEffectOp(op, incremental, Date.now() - startedAt, this.allEffects.size);
|
|
94194
|
+
}
|
|
94195
|
+
catch {
|
|
94196
|
+
// Telemetry must not change side-effect store behavior.
|
|
94197
|
+
}
|
|
93827
94198
|
}
|
|
93828
94199
|
async initialize() {
|
|
93829
94200
|
const effects = await this.durableStore.getAllEntries(SIDE_EFFECT_SEGMENT);
|
|
@@ -97020,7 +97391,7 @@
|
|
|
97020
97391
|
},
|
|
97021
97392
|
};
|
|
97022
97393
|
}
|
|
97023
|
-
// version: 1.
|
|
97394
|
+
// version: 1.456.0-cef836b978
|
|
97024
97395
|
|
|
97025
97396
|
/**
|
|
97026
97397
|
* Copyright (c) 2022, Salesforce, Inc.,
|
|
@@ -97046,7 +97417,7 @@
|
|
|
97046
97417
|
},
|
|
97047
97418
|
};
|
|
97048
97419
|
}
|
|
97049
|
-
// version: 1.
|
|
97420
|
+
// version: 1.456.0-cef836b978
|
|
97050
97421
|
|
|
97051
97422
|
function findExecutableOperation$1(input) {
|
|
97052
97423
|
const operations = input.query.definitions.filter(
|
|
@@ -99755,7 +100126,7 @@
|
|
|
99755
100126
|
id: '@salesforce/lds-network-adapter',
|
|
99756
100127
|
instrument: instrument$2,
|
|
99757
100128
|
});
|
|
99758
|
-
// version: 1.
|
|
100129
|
+
// version: 1.456.0-cef836b978
|
|
99759
100130
|
|
|
99760
100131
|
const { create: create$2, keys: keys$2 } = Object;
|
|
99761
100132
|
const { stringify, parse } = JSON;
|
|
@@ -100219,10 +100590,11 @@
|
|
|
100219
100590
|
}
|
|
100220
100591
|
]);
|
|
100221
100592
|
}
|
|
100593
|
+
const existingArrayData = input.existingNormalizedData?.data;
|
|
100222
100594
|
const arrayNormalizationErrors = [];
|
|
100223
100595
|
const normalizedArray = [];
|
|
100224
100596
|
input.data.forEach((item, index) => {
|
|
100225
|
-
const existingItemData =
|
|
100597
|
+
const existingItemData = existingArrayData?.[index];
|
|
100226
100598
|
const normalizedItemResult = this.items.write(cache, {
|
|
100227
100599
|
...input,
|
|
100228
100600
|
data: item,
|
|
@@ -107290,7 +107662,7 @@
|
|
|
107290
107662
|
cb(graphql_v1_import, graphql_imperative$1, graphql_imperative_legacy_v1_import, graphql_state_manager, useOneStoreGraphQL);
|
|
107291
107663
|
}
|
|
107292
107664
|
}
|
|
107293
|
-
// version: 1.
|
|
107665
|
+
// version: 1.456.0-6ed480b93c
|
|
107294
107666
|
|
|
107295
107667
|
function createFragmentMap(documentNode) {
|
|
107296
107668
|
const fragments = {};
|
|
@@ -124019,7 +124391,7 @@
|
|
|
124019
124391
|
return keyBuilder$z(luvio, keyParams);
|
|
124020
124392
|
}
|
|
124021
124393
|
|
|
124022
|
-
const { assign: assign$1, create: create$1, freeze: freeze$1, isFrozen: isFrozen$1, keys: keys$1 } = Object;
|
|
124394
|
+
const { assign: assign$1, create: create$1, freeze: freeze$1, getPrototypeOf: getPrototypeOf$1, isFrozen: isFrozen$1, keys: keys$1 } = Object;
|
|
124023
124395
|
const { isArray: isArray$2 } = Array;
|
|
124024
124396
|
const { concat: concat$1, filter: filter$1, includes: includes$1, push: push$1, reduce: reduce$1 } = Array.prototype;
|
|
124025
124397
|
|
|
@@ -136533,7 +136905,7 @@
|
|
|
136533
136905
|
configuration: { ...configurationForGraphQLAdapters$1 },
|
|
136534
136906
|
instrument: instrument$1,
|
|
136535
136907
|
});
|
|
136536
|
-
// version: 1.
|
|
136908
|
+
// version: 1.456.0-6ed480b93c
|
|
136537
136909
|
|
|
136538
136910
|
// On core the unstable adapters are re-exported with different names,
|
|
136539
136911
|
// we want to match them here.
|
|
@@ -136685,7 +137057,7 @@
|
|
|
136685
137057
|
unstable_graphQL_imperative = createImperativeAdapter(luvio, createInstrumentedAdapter(ldsAdapter, adapterMetadata), adapterMetadata);
|
|
136686
137058
|
graphQLImperative = ldsAdapter;
|
|
136687
137059
|
});
|
|
136688
|
-
// version: 1.
|
|
137060
|
+
// version: 1.456.0-6ed480b93c
|
|
136689
137061
|
|
|
136690
137062
|
var gqlApi = /*#__PURE__*/Object.freeze({
|
|
136691
137063
|
__proto__: null,
|
|
@@ -137484,7 +137856,7 @@
|
|
|
137484
137856
|
function register(r) {
|
|
137485
137857
|
callbacks$1.forEach((callback) => callback(r));
|
|
137486
137858
|
}
|
|
137487
|
-
// version: 1.
|
|
137859
|
+
// version: 1.456.0-cef836b978
|
|
137488
137860
|
|
|
137489
137861
|
/**
|
|
137490
137862
|
* Copyright (c) 2022, Salesforce, Inc.,
|
|
@@ -137770,7 +138142,7 @@
|
|
|
137770
138142
|
}
|
|
137771
138143
|
const keyPrefix = 'UiApi';
|
|
137772
138144
|
|
|
137773
|
-
const { assign, create, freeze, isFrozen, keys } = Object;
|
|
138145
|
+
const { assign, create, freeze, getPrototypeOf, isFrozen, keys } = Object;
|
|
137774
138146
|
const { isArray } = Array;
|
|
137775
138147
|
const { concat, filter, includes, push, reduce } = Array.prototype;
|
|
137776
138148
|
|
|
@@ -138794,4 +139166,4 @@
|
|
|
138794
139166
|
exports.subscribeToAdapter = subscribeToAdapter;
|
|
138795
139167
|
|
|
138796
139168
|
}));
|
|
138797
|
-
// version: 1.
|
|
139169
|
+
// version: 1.456.0-cef836b978
|