@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.
|
@@ -4276,7 +4276,7 @@ function withDefaultLuvio(callback) {
|
|
|
4276
4276
|
}
|
|
4277
4277
|
callbacks.push(callback);
|
|
4278
4278
|
}
|
|
4279
|
-
// version: 1.
|
|
4279
|
+
// version: 1.456.0-cef836b978
|
|
4280
4280
|
|
|
4281
4281
|
// TODO [TD-0081508]: once that TD is fulfilled we can probably change this file
|
|
4282
4282
|
function instrumentAdapter$1(createFunction, _metadata) {
|
|
@@ -5320,7 +5320,7 @@ function createGraphQLWireAdapterConstructor(luvio, adapter, metadata, astResolv
|
|
|
5320
5320
|
const { apiFamily, name } = metadata;
|
|
5321
5321
|
return createGraphQLWireAdapterConstructor$1(adapter, `${apiFamily}.${name}`, luvio, astResolver);
|
|
5322
5322
|
}
|
|
5323
|
-
// version: 1.
|
|
5323
|
+
// version: 1.456.0-cef836b978
|
|
5324
5324
|
|
|
5325
5325
|
function isSupportedEntity(_objectApiName) {
|
|
5326
5326
|
return true;
|
|
@@ -5430,7 +5430,7 @@ var TypeCheckShapes;
|
|
|
5430
5430
|
|
|
5431
5431
|
const { keys: ObjectKeys$4, create: ObjectCreate$4 } = Object;
|
|
5432
5432
|
|
|
5433
|
-
const { assign: assign$7, create: create$9, freeze: freeze$6, isFrozen: isFrozen$4, keys: keys$a } = Object;
|
|
5433
|
+
const { assign: assign$7, create: create$9, freeze: freeze$6, getPrototypeOf: getPrototypeOf$3, isFrozen: isFrozen$4, keys: keys$a } = Object;
|
|
5434
5434
|
|
|
5435
5435
|
/**
|
|
5436
5436
|
* Defines configuration for the module with a default value which can be overridden by the runtime environment.
|
|
@@ -6065,7 +6065,7 @@ function buildAdapterValidationConfig$3(displayName, paramsMeta) {
|
|
|
6065
6065
|
}
|
|
6066
6066
|
const keyPrefix$3 = 'UiApi';
|
|
6067
6067
|
|
|
6068
|
-
const { assign: assign$6, create: create$8, freeze: freeze$5, isFrozen: isFrozen$3, keys: keys$9 } = Object;
|
|
6068
|
+
const { assign: assign$6, create: create$8, freeze: freeze$5, getPrototypeOf: getPrototypeOf$2, isFrozen: isFrozen$3, keys: keys$9 } = Object;
|
|
6069
6069
|
const { hasOwnProperty: hasOwnProperty$5 } = Object.prototype;
|
|
6070
6070
|
const { split: split$1, endsWith: endsWith$1 } = String.prototype;
|
|
6071
6071
|
const { isArray: isArray$8 } = Array;
|
|
@@ -32547,7 +32547,7 @@ withDefaultLuvio((luvio) => {
|
|
|
32547
32547
|
throttle(60, 60000, setupNotifyAllListRecordUpdateAvailable(luvio));
|
|
32548
32548
|
throttle(60, 60000, setupNotifyAllListInfoSummaryUpdateAvailable(luvio));
|
|
32549
32549
|
});
|
|
32550
|
-
// version: 1.
|
|
32550
|
+
// version: 1.456.0-6ed480b93c
|
|
32551
32551
|
|
|
32552
32552
|
var draftQueueMaxRetryAttemptsGate = {
|
|
32553
32553
|
isOpen: function (e) {
|
|
@@ -47849,16 +47849,18 @@ class LdsAbortController {
|
|
|
47849
47849
|
}
|
|
47850
47850
|
|
|
47851
47851
|
class AsyncWorkerPool {
|
|
47852
|
-
constructor(concurrency) {
|
|
47852
|
+
constructor(concurrency, onWorkTiming) {
|
|
47853
47853
|
this.queue = [];
|
|
47854
47854
|
this.activeWork = [];
|
|
47855
47855
|
this.concurrency = concurrency;
|
|
47856
|
+
this.onWorkTiming = onWorkTiming;
|
|
47856
47857
|
}
|
|
47857
47858
|
push(work) {
|
|
47858
47859
|
return new Promise((resolve, reject) => {
|
|
47859
47860
|
this.queue.push({
|
|
47860
47861
|
...work,
|
|
47861
47862
|
workFn: (abortController) => work.workFn(abortController).then(resolve).catch(reject),
|
|
47863
|
+
enqueuedAt: Date.now(),
|
|
47862
47864
|
});
|
|
47863
47865
|
this.doWork();
|
|
47864
47866
|
});
|
|
@@ -47901,10 +47903,30 @@ class AsyncWorkerPool {
|
|
|
47901
47903
|
const abortController = new LdsAbortController();
|
|
47902
47904
|
const newWork = { ...work, abortController };
|
|
47903
47905
|
this.activeWork.push(newWork);
|
|
47904
|
-
const { workFn } = work;
|
|
47906
|
+
const { workFn, enqueuedAt } = work;
|
|
47907
|
+
const onWorkTiming = this.onWorkTiming;
|
|
47908
|
+
let startedAt = 0;
|
|
47909
|
+
let waitMs = 0;
|
|
47910
|
+
let queueDepthAtStart = 0;
|
|
47911
|
+
if (onWorkTiming !== undefined) {
|
|
47912
|
+
startedAt = Date.now();
|
|
47913
|
+
waitMs = startedAt - enqueuedAt;
|
|
47914
|
+
// depth AFTER this unit was shifted off — units still waiting behind it.
|
|
47915
|
+
queueDepthAtStart = this.queue.length;
|
|
47916
|
+
}
|
|
47905
47917
|
workFn(abortController).finally(() => {
|
|
47906
|
-
|
|
47907
|
-
|
|
47918
|
+
try {
|
|
47919
|
+
if (onWorkTiming !== undefined) {
|
|
47920
|
+
onWorkTiming(waitMs, Date.now() - startedAt, queueDepthAtStart);
|
|
47921
|
+
}
|
|
47922
|
+
}
|
|
47923
|
+
catch {
|
|
47924
|
+
// Instrumentation must not prevent the pool from releasing the worker slot.
|
|
47925
|
+
}
|
|
47926
|
+
finally {
|
|
47927
|
+
this.activeWork = this.activeWork.filter((w) => w !== newWork);
|
|
47928
|
+
this.doWork();
|
|
47929
|
+
}
|
|
47908
47930
|
});
|
|
47909
47931
|
}
|
|
47910
47932
|
}
|
|
@@ -48234,6 +48256,25 @@ const DRAFT_SEGMENT = 'DRAFT';
|
|
|
48234
48256
|
*/
|
|
48235
48257
|
const DRAFT_ACTION_RETRY_COUNT_METADATA_KEY = 'retryCount';
|
|
48236
48258
|
class DurableDraftQueue {
|
|
48259
|
+
// Instrumentation is strictly measure-only: a broken sink must never change queue behavior.
|
|
48260
|
+
// Pass the sink into the callback so methods are invoked through their owning object and retain
|
|
48261
|
+
// their receiver (some sinks use `this` to reach their metric registry).
|
|
48262
|
+
emitInstrumentation(emit) {
|
|
48263
|
+
const { instrumentation } = this;
|
|
48264
|
+
if (instrumentation === undefined) {
|
|
48265
|
+
return;
|
|
48266
|
+
}
|
|
48267
|
+
try {
|
|
48268
|
+
emit(instrumentation);
|
|
48269
|
+
}
|
|
48270
|
+
catch {
|
|
48271
|
+
// Telemetry failures must not interrupt draft processing.
|
|
48272
|
+
}
|
|
48273
|
+
}
|
|
48274
|
+
resetDrainCycle() {
|
|
48275
|
+
this.drainCycleStart = undefined;
|
|
48276
|
+
this.drainCycleBatchCount = 0;
|
|
48277
|
+
}
|
|
48237
48278
|
getHandler(id) {
|
|
48238
48279
|
const handler = this.handlers[id];
|
|
48239
48280
|
if (handler === undefined) {
|
|
@@ -48256,9 +48297,19 @@ class DurableDraftQueue {
|
|
|
48256
48297
|
? __nimbus.plugins.JSLoggerPlugin
|
|
48257
48298
|
: undefined;
|
|
48258
48299
|
this.handlers = {};
|
|
48300
|
+
// Drain-wait attribution state. uploadStartTimes stamps when each action first began
|
|
48301
|
+
// uploading (keyed by action id) so actionCompleted/failed can emit its end-to-end drain time,
|
|
48302
|
+
// including automatic retries/backoff. actionQueueWaitEmittedIds ensures those retries do not
|
|
48303
|
+
// report the original enqueue wait more than once. drainCycleStart/BatchCount track one full
|
|
48304
|
+
// idle->empty sweep. All measure-only; when no instrumentation is injected these stay untouched.
|
|
48305
|
+
this.uploadStartTimes = new Map();
|
|
48306
|
+
this.actionQueueWaitEmittedIds = new Set();
|
|
48307
|
+
this.drainCycleBatchCount = 0;
|
|
48259
48308
|
this.draftStore = draftStore;
|
|
48260
|
-
this.workerPool = new AsyncWorkerPool(1);
|
|
48261
48309
|
this.instrumentation = instrumentation;
|
|
48310
|
+
this.workerPool = new AsyncWorkerPool(1, instrumentation?.onWorkerTiming !== undefined
|
|
48311
|
+
? (waitMs, holdMs, queueDepth) => this.emitInstrumentation((sink) => sink.onWorkerTiming?.(waitMs, holdMs, queueDepth))
|
|
48312
|
+
: undefined);
|
|
48262
48313
|
}
|
|
48263
48314
|
addHandler(handler) {
|
|
48264
48315
|
const id = handler.handlerId;
|
|
@@ -48346,6 +48397,9 @@ class DurableDraftQueue {
|
|
|
48346
48397
|
clearTimeout(this.timeoutHandler);
|
|
48347
48398
|
this.timeoutHandler = undefined;
|
|
48348
48399
|
}
|
|
48400
|
+
// A stop/user edit breaks the current sweep. A later restart starts a fresh cycle rather
|
|
48401
|
+
// than attributing stopped time to an offline drain.
|
|
48402
|
+
this.resetDrainCycle();
|
|
48349
48403
|
this.state = DraftQueueState.Stopped;
|
|
48350
48404
|
}
|
|
48351
48405
|
async getQueueActions() {
|
|
@@ -48376,7 +48430,7 @@ class DurableDraftQueue {
|
|
|
48376
48430
|
}
|
|
48377
48431
|
return aTime - bTime;
|
|
48378
48432
|
});
|
|
48379
|
-
|
|
48433
|
+
this.emitInstrumentation((sink) => sink.onGetQueueActions?.(Date.now() - start, sorted.length));
|
|
48380
48434
|
return sorted;
|
|
48381
48435
|
}
|
|
48382
48436
|
async enqueue(handlerId, data, observabilityContext) {
|
|
@@ -48420,6 +48474,13 @@ class DurableDraftQueue {
|
|
|
48420
48474
|
await handler.handleActionCompleted(action, queueOperations, values$2(this.handlers));
|
|
48421
48475
|
this.retryIntervalMilliseconds = 0;
|
|
48422
48476
|
this.uploadingActionId = undefined;
|
|
48477
|
+
// The action finished draining — emit its end-to-end drain time and
|
|
48478
|
+
// count it toward the current drain-cycle batch. Measure-only.
|
|
48479
|
+
this.emitActionDrainDuration(action.id, action.handler);
|
|
48480
|
+
this.actionQueueWaitEmittedIds.delete(action.id);
|
|
48481
|
+
if (this.drainCycleStart !== undefined) {
|
|
48482
|
+
this.drainCycleBatchCount += 1;
|
|
48483
|
+
}
|
|
48423
48484
|
await this.notifyChangedListeners({
|
|
48424
48485
|
type: DraftQueueEventType.ActionCompleted,
|
|
48425
48486
|
action,
|
|
@@ -48431,6 +48492,16 @@ class DurableDraftQueue {
|
|
|
48431
48492
|
},
|
|
48432
48493
|
});
|
|
48433
48494
|
}
|
|
48495
|
+
// Read+clear the action's upload-start stamp and emit its drain duration. Safe to
|
|
48496
|
+
// call when instrumentation is absent or the id was never stamped (no-op). Never emits the id.
|
|
48497
|
+
emitActionDrainDuration(id, handlerId) {
|
|
48498
|
+
const start = this.uploadStartTimes.get(id);
|
|
48499
|
+
if (start === undefined) {
|
|
48500
|
+
return;
|
|
48501
|
+
}
|
|
48502
|
+
this.uploadStartTimes.delete(id);
|
|
48503
|
+
this.emitInstrumentation((sink) => sink.onActionDrainDuration?.(handlerId, Date.now() - start));
|
|
48504
|
+
}
|
|
48434
48505
|
async actionFailed(action, retry, retryDelayInMs, actionDataChanged) {
|
|
48435
48506
|
if (actionDataChanged === true) {
|
|
48436
48507
|
await this.draftStore.writeAction({
|
|
@@ -48440,14 +48511,24 @@ class DurableDraftQueue {
|
|
|
48440
48511
|
}
|
|
48441
48512
|
this.uploadingActionId = undefined;
|
|
48442
48513
|
if (retry && this.state !== DraftQueueState.Stopped) {
|
|
48514
|
+
// A retry means this action is NOT done draining. Keep its first-upload stamp and the
|
|
48515
|
+
// open cycle so the eventual outcome includes network time and retry/backoff.
|
|
48443
48516
|
this.state = DraftQueueState.Waiting;
|
|
48444
48517
|
return retryDelayInMs !== undefined
|
|
48445
48518
|
? this.scheduleRetryWithSpecifiedDelay(retryDelayInMs)
|
|
48446
48519
|
: this.scheduleRetry();
|
|
48447
48520
|
}
|
|
48448
48521
|
else if (isDraftError(action)) {
|
|
48522
|
+
// Terminal failure — this action is done draining. Emit its drain time.
|
|
48523
|
+
this.emitActionDrainDuration(action.id, action.handler);
|
|
48524
|
+
// This was not a clean drain-to-empty. Discard the sweep before user intervention so a
|
|
48525
|
+
// later manual retry/removal cannot inherit its elapsed time or completed batch count.
|
|
48526
|
+
this.resetDrainCycle();
|
|
48449
48527
|
return this.handleServerError(action, action.error);
|
|
48450
48528
|
}
|
|
48529
|
+
// Any other terminal path — ensure no stale start stamp lingers.
|
|
48530
|
+
this.emitActionDrainDuration(action.id, action.handler);
|
|
48531
|
+
this.resetDrainCycle();
|
|
48451
48532
|
}
|
|
48452
48533
|
handle(action) {
|
|
48453
48534
|
const handler = this.getHandler(action.handler);
|
|
@@ -48467,12 +48548,22 @@ class DurableDraftQueue {
|
|
|
48467
48548
|
this.state = DraftQueueState.Started;
|
|
48468
48549
|
}
|
|
48469
48550
|
this.processingAction = undefined;
|
|
48551
|
+
// The queue drained empty — close the drain-cycle window if one was open.
|
|
48552
|
+
if (this.drainCycleStart !== undefined) {
|
|
48553
|
+
const durationMs = Date.now() - this.drainCycleStart;
|
|
48554
|
+
const batchSize = this.drainCycleBatchCount;
|
|
48555
|
+
this.resetDrainCycle();
|
|
48556
|
+
this.emitInstrumentation((sink) => sink.onDrainCycle?.(durationMs, batchSize));
|
|
48557
|
+
}
|
|
48470
48558
|
return ProcessActionResult.NO_ACTION_TO_PROCESS;
|
|
48471
48559
|
}
|
|
48472
48560
|
const { status, id } = action;
|
|
48473
48561
|
if (status === DraftActionStatus.Error) {
|
|
48474
48562
|
this.state = DraftQueueState.Error;
|
|
48475
48563
|
this.processingAction = undefined;
|
|
48564
|
+
// The sweep is blocked on an errored action, not a clean drain-to-empty —
|
|
48565
|
+
// discard the open drain-cycle window so it doesn't inflate a later cycle's duration.
|
|
48566
|
+
this.resetDrainCycle();
|
|
48476
48567
|
await this.notifyChangedListeners({
|
|
48477
48568
|
type: DraftQueueEventType.ActionFailed,
|
|
48478
48569
|
action: action,
|
|
@@ -48490,6 +48581,31 @@ class DurableDraftQueue {
|
|
|
48490
48581
|
if (this.state === DraftQueueState.Waiting) {
|
|
48491
48582
|
this.state = DraftQueueState.Started;
|
|
48492
48583
|
}
|
|
48584
|
+
// The action is now leaving the queue to upload. Emit head-of-line FIFO wait
|
|
48585
|
+
// (enqueue -> upload start), stamp its drain-start for end-to-end timing on completion, and
|
|
48586
|
+
// open a drain-cycle window if the queue was previously idle. All measure-only.
|
|
48587
|
+
const { instrumentation } = this;
|
|
48588
|
+
if (instrumentation !== undefined) {
|
|
48589
|
+
const now = Date.now();
|
|
48590
|
+
const { timestamp } = action;
|
|
48591
|
+
if (instrumentation.onActionQueueWait !== undefined &&
|
|
48592
|
+
!this.actionQueueWaitEmittedIds.has(id) &&
|
|
48593
|
+
typeof timestamp === 'number' &&
|
|
48594
|
+
timestamp > 0) {
|
|
48595
|
+
// Mark before invoking the sink: even a throwing callback must not make a retry
|
|
48596
|
+
// report the same action's enqueue wait again.
|
|
48597
|
+
this.actionQueueWaitEmittedIds.add(id);
|
|
48598
|
+
this.emitInstrumentation((sink) => sink.onActionQueueWait?.(action.handler, now - timestamp));
|
|
48599
|
+
}
|
|
48600
|
+
if (instrumentation.onActionDrainDuration !== undefined &&
|
|
48601
|
+
!this.uploadStartTimes.has(id)) {
|
|
48602
|
+
this.uploadStartTimes.set(id, now);
|
|
48603
|
+
}
|
|
48604
|
+
if (instrumentation.onDrainCycle !== undefined && this.drainCycleStart === undefined) {
|
|
48605
|
+
this.drainCycleStart = now;
|
|
48606
|
+
this.drainCycleBatchCount = 0;
|
|
48607
|
+
}
|
|
48608
|
+
}
|
|
48493
48609
|
await this.notifyChangedListeners({
|
|
48494
48610
|
type: DraftQueueEventType.ActionUploading,
|
|
48495
48611
|
action: { ...action, status: DraftActionStatus.Uploading },
|
|
@@ -48527,7 +48643,7 @@ class DurableDraftQueue {
|
|
|
48527
48643
|
results.push(listener(event));
|
|
48528
48644
|
}
|
|
48529
48645
|
// W-23515682: listener fan-out per event type. Measure-only.
|
|
48530
|
-
this.
|
|
48646
|
+
this.emitInstrumentation((sink) => sink.onNotifyChangedListeners?.(event.type, draftQueueLen));
|
|
48531
48647
|
await Promise.all(results);
|
|
48532
48648
|
}
|
|
48533
48649
|
/**
|
|
@@ -48556,9 +48672,17 @@ class DurableDraftQueue {
|
|
|
48556
48672
|
const shouldDeleteRelated = handler.shouldDeleteActionByTagOnRemoval(action);
|
|
48557
48673
|
if (shouldDeleteRelated) {
|
|
48558
48674
|
await this.draftStore.deleteByTag(action.tag);
|
|
48675
|
+
queue.forEach((queuedAction) => {
|
|
48676
|
+
if (queuedAction.tag === action.tag) {
|
|
48677
|
+
this.uploadStartTimes.delete(queuedAction.id);
|
|
48678
|
+
this.actionQueueWaitEmittedIds.delete(queuedAction.id);
|
|
48679
|
+
}
|
|
48680
|
+
});
|
|
48559
48681
|
}
|
|
48560
48682
|
else {
|
|
48561
48683
|
await this.draftStore.deleteDraft(action.id);
|
|
48684
|
+
this.uploadStartTimes.delete(action.id);
|
|
48685
|
+
this.actionQueueWaitEmittedIds.delete(action.id);
|
|
48562
48686
|
}
|
|
48563
48687
|
await handler.handleActionRemoved(action, queue.filter((x) => x.id !== actionId));
|
|
48564
48688
|
await this.notifyChangedListeners({
|
|
@@ -80190,6 +80314,20 @@ const DRAFT_QUEUE_GET_QUEUE_ACTIONS_DURATION = 'draft-queue-get-queue-actions-du
|
|
|
80190
80314
|
const DRAFT_QUEUE_NOTIFY_CHANGED_LISTENERS_COUNT = 'draft-queue-notify-changed-listeners-count';
|
|
80191
80315
|
const DRAFT_QUEUE_DURABLE_OP_COUNT = 'draft-queue-durable-op-count';
|
|
80192
80316
|
const DRAFT_QUEUE_DURABLE_OP_DURATION = 'draft-queue-durable-op-duration';
|
|
80317
|
+
// Drain-wait attribution telemetry: the wall-clock spine of where an offline drain actually spends
|
|
80318
|
+
// WAITING. Operational counts/durations/depths only — no draft content, field values, or server
|
|
80319
|
+
// record ids (matching the existing draft-queue privacy stance).
|
|
80320
|
+
const DRAFT_QUEUE_WORKER_WAIT_DURATION = 'draft-queue-worker-wait-duration';
|
|
80321
|
+
const DRAFT_QUEUE_WORKER_HOLD_DURATION = 'draft-queue-worker-hold-duration';
|
|
80322
|
+
const DRAFT_QUEUE_ACTION_QUEUE_WAIT_DURATION = 'draft-queue-action-queue-wait-duration';
|
|
80323
|
+
const DRAFT_QUEUE_ACTION_DRAIN_DURATION = 'draft-queue-action-drain-duration';
|
|
80324
|
+
const DRAFT_QUEUE_DRAIN_CYCLE_DURATION = 'draft-queue-drain-cycle-duration';
|
|
80325
|
+
const DRAFT_QUEUE_DRAIN_CYCLE_BATCH_SIZE = 'draft-queue-drain-cycle-batch-size';
|
|
80326
|
+
const DRAFT_QUEUE_ACTION_NETWORK_DURATION = 'draft-queue-action-network-duration';
|
|
80327
|
+
const DRAFT_QUEUE_ACTION_RETRY_ATTEMPT = 'draft-queue-action-retry-attempt';
|
|
80328
|
+
const DRAFT_QUEUE_SIDEEFFECT_OP_DURATION = 'draft-queue-sideeffect-op-duration';
|
|
80329
|
+
const DRAFT_QUEUE_SIDEEFFECT_MAP_SIZE = 'draft-queue-sideeffect-map-size';
|
|
80330
|
+
const DRAFT_QUEUE_SIDEEFFECT_REGION_DURATION = 'draft-queue-sideeffect-region-duration';
|
|
80193
80331
|
/** Content Document */
|
|
80194
80332
|
const CREATE_CONTENT_DOCUMENT_AND_VERSION_TOTAL_SYNTHESIZE_CALLS = 'content-document-version-total-synthesize-calls';
|
|
80195
80333
|
const CREATE_CONTENT_DOCUMENT_AND_VERSION_DRAFT_SYNTHESIZE_ERROR = 'create-content-document-version-draft-synthesize-error';
|
|
@@ -80309,6 +80447,134 @@ function reportDraftQueueDurableOperation(op, segment, durationMs) {
|
|
|
80309
80447
|
});
|
|
80310
80448
|
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_DURABLE_OP_DURATION, durationMs);
|
|
80311
80449
|
}
|
|
80450
|
+
const DRAIN_DURATION_BUCKETS = [50, 100, 250, 500, 1000, 2500, 5000, 10000, 30000];
|
|
80451
|
+
const WORKER_DEPTH_BUCKETS = [1, 2, 5, 10, 20, 50, 100, 250, 500];
|
|
80452
|
+
// Handler ids are extensible through DraftManager, so only retain the fixed mobile handlers in
|
|
80453
|
+
// metric tags. Everything else shares one bounded bucket rather than creating an unbounded series.
|
|
80454
|
+
function draftQueueHandlerTagOf(handlerId) {
|
|
80455
|
+
switch (handlerId) {
|
|
80456
|
+
case 'LDS_ACTION_HANDLER':
|
|
80457
|
+
case 'ContentDocumentCompositeRepresentationActionHandler':
|
|
80458
|
+
case 'QUICK_ACTION_HANDLER':
|
|
80459
|
+
case 'UPDATE_RECORD_QUICK_ACTION_HANDLER':
|
|
80460
|
+
return handlerId;
|
|
80461
|
+
default:
|
|
80462
|
+
return 'custom';
|
|
80463
|
+
}
|
|
80464
|
+
}
|
|
80465
|
+
// Coarse, bounded-cardinality label for the pool depth a unit saw when it began, so the
|
|
80466
|
+
// wait/hold durations can be sliced BY backlog size without emitting depth as a free integer tag.
|
|
80467
|
+
function workerDepthBucketOf(queueDepth) {
|
|
80468
|
+
if (queueDepth <= 0) {
|
|
80469
|
+
return '0';
|
|
80470
|
+
}
|
|
80471
|
+
if (queueDepth <= 2) {
|
|
80472
|
+
return '1-2';
|
|
80473
|
+
}
|
|
80474
|
+
if (queueDepth <= 10) {
|
|
80475
|
+
return '3-10';
|
|
80476
|
+
}
|
|
80477
|
+
if (queueDepth <= 50) {
|
|
80478
|
+
return '11-50';
|
|
80479
|
+
}
|
|
80480
|
+
if (queueDepth <= 250) {
|
|
80481
|
+
return '51-250';
|
|
80482
|
+
}
|
|
80483
|
+
return '250+';
|
|
80484
|
+
}
|
|
80485
|
+
/**
|
|
80486
|
+
* Per-unit lifecycle split for the AsyncWorkerPool(1) serial queue, emitted once when a unit settles
|
|
80487
|
+
* so the two halves are a JOINED event (rather than shipping wait and depth as unrelated aggregates).
|
|
80488
|
+
* Isolates WHERE the time goes:
|
|
80489
|
+
* waitMs — enqueue -> work began (waiting on the serial queue before any logic runs).
|
|
80490
|
+
* holdMs — work began -> work settled (the critical section's own O(N) service time).
|
|
80491
|
+
* Both are additionally tagged by a depthBucket so "does per-unit cost scale with backlog depth"
|
|
80492
|
+
* (the O(N^2) signature) survives aggregation. queueDepth itself is also tracked. Operational only.
|
|
80493
|
+
*/
|
|
80494
|
+
function reportDraftQueueWorkerTiming(waitMs, holdMs, queueDepth) {
|
|
80495
|
+
const depthBucket = workerDepthBucketOf(queueDepth);
|
|
80496
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_WORKER_WAIT_DURATION, waitMs, undefined, {
|
|
80497
|
+
depthBucket,
|
|
80498
|
+
});
|
|
80499
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_WORKER_HOLD_DURATION, holdMs, undefined, {
|
|
80500
|
+
depthBucket,
|
|
80501
|
+
});
|
|
80502
|
+
ldsMobileInstrumentation$2.bucketValue(DRAFT_QUEUE_WORKER_WAIT_DURATION + '-depth', queueDepth, WORKER_DEPTH_BUCKETS);
|
|
80503
|
+
}
|
|
80504
|
+
/**
|
|
80505
|
+
* Head-of-line FIFO wait for one draft (enqueue -> upload start), bucketed so the
|
|
80506
|
+
* "does wait grow with backlog depth" (O(N^2)) signal is visible per handler type. Custom handler
|
|
80507
|
+
* ids are normalized to one bounded tag so caller-defined values never become metric dimensions.
|
|
80508
|
+
*/
|
|
80509
|
+
function reportDraftQueueActionQueueWait(handlerId, waitMs) {
|
|
80510
|
+
ldsMobileInstrumentation$2.bucketValue(DRAFT_QUEUE_ACTION_QUEUE_WAIT_DURATION, waitMs, DRAIN_DURATION_BUCKETS, undefined, { handlerId: draftQueueHandlerTagOf(handlerId) });
|
|
80511
|
+
}
|
|
80512
|
+
/**
|
|
80513
|
+
* End-to-end drain time for one action (first upload attempt -> completed/failed), including
|
|
80514
|
+
* retry/backoff. Compare it with network-duration and retry-attempt signals to understand the
|
|
80515
|
+
* non-request portion of the drain interval.
|
|
80516
|
+
*/
|
|
80517
|
+
function reportDraftQueueActionDrainDuration(handlerId, durationMs) {
|
|
80518
|
+
ldsMobileInstrumentation$2.bucketValue(DRAFT_QUEUE_ACTION_DRAIN_DURATION, durationMs, DRAIN_DURATION_BUCKETS, undefined, { handlerId: draftQueueHandlerTagOf(handlerId) });
|
|
80519
|
+
}
|
|
80520
|
+
/**
|
|
80521
|
+
* One full drain sweep — first action starts uploading -> queue empties. Both raw values share a
|
|
80522
|
+
* bounded batch-size cohort so aggregate duration remains sliceable by the number of actions drained.
|
|
80523
|
+
*/
|
|
80524
|
+
function reportDraftQueueDrainCycle(durationMs, batchSize) {
|
|
80525
|
+
const batchSizeBucket = workerDepthBucketOf(batchSize);
|
|
80526
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_DRAIN_CYCLE_DURATION, durationMs, undefined, {
|
|
80527
|
+
batchSizeBucket,
|
|
80528
|
+
});
|
|
80529
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_DRAIN_CYCLE_BATCH_SIZE, batchSize, undefined, {
|
|
80530
|
+
batchSizeBucket,
|
|
80531
|
+
});
|
|
80532
|
+
}
|
|
80533
|
+
/**
|
|
80534
|
+
* Server round-trip duration for one upload. Isolates slow-network from CPU-bound
|
|
80535
|
+
* quadratic work — today only a THROWN error is captured, so a slow-but-successful (or slow 4xx/5xx)
|
|
80536
|
+
* response is invisible. Tags: handler type, HTTP method, and a bucketed status class ('2xx'/'4xx'/
|
|
80537
|
+
* '5xx'/'0'). No URL, body, or record id.
|
|
80538
|
+
*/
|
|
80539
|
+
function reportDraftQueueActionNetworkDuration(handlerId, method, statusBucket, durationMs) {
|
|
80540
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_ACTION_NETWORK_DURATION, durationMs, undefined, {
|
|
80541
|
+
handlerId: draftQueueHandlerTagOf(handlerId),
|
|
80542
|
+
method,
|
|
80543
|
+
statusBucket,
|
|
80544
|
+
});
|
|
80545
|
+
}
|
|
80546
|
+
/**
|
|
80547
|
+
* Retry event count. Repeated events identify actions cycling through the drain even when the retry
|
|
80548
|
+
* cap is disabled and an exact attempt number is not persisted. cappedOut marks cap exhaustion.
|
|
80549
|
+
*/
|
|
80550
|
+
function reportDraftQueueActionRetryAttempt(handlerId, cappedOut) {
|
|
80551
|
+
ldsMobileInstrumentation$2.incrementCounter(DRAFT_QUEUE_ACTION_RETRY_ATTEMPT, 1, undefined, {
|
|
80552
|
+
handlerId: draftQueueHandlerTagOf(handlerId),
|
|
80553
|
+
cappedOut: String(cappedOut),
|
|
80554
|
+
});
|
|
80555
|
+
}
|
|
80556
|
+
/**
|
|
80557
|
+
* SideEffectStore operation duration + map size. The incremental map sped up the by-KEY lookup but
|
|
80558
|
+
* getEffectsByTag still linearly scans all effects — this measures whether that residual scan is
|
|
80559
|
+
* silently quadratic during churn. op is 'add'|'remove'|'getByTag'; incremental flags the fast path;
|
|
80560
|
+
* mapSize is an integer effect count. No record keys, field names, or field values.
|
|
80561
|
+
*/
|
|
80562
|
+
function reportDraftQueueSideEffectOp(op, incremental, durationMs, mapSize) {
|
|
80563
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_SIDEEFFECT_OP_DURATION, durationMs, undefined, {
|
|
80564
|
+
op,
|
|
80565
|
+
incremental: String(incremental),
|
|
80566
|
+
});
|
|
80567
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_SIDEEFFECT_MAP_SIZE, mapSize, undefined, {
|
|
80568
|
+
op,
|
|
80569
|
+
});
|
|
80570
|
+
}
|
|
80571
|
+
/**
|
|
80572
|
+
* Broad side-effect lifecycle duration. The fixed region and lifecycle tags identify which part of
|
|
80573
|
+
* serialized draft processing is slow without emitting record keys, action ids, or field data.
|
|
80574
|
+
*/
|
|
80575
|
+
function reportDraftQueueSideEffectRegionDuration(region, lifecycle, durationMs) {
|
|
80576
|
+
ldsMobileInstrumentation$2.trackValue(DRAFT_QUEUE_SIDEEFFECT_REGION_DURATION, durationMs, undefined, { region, lifecycle });
|
|
80577
|
+
}
|
|
80312
80578
|
/**
|
|
80313
80579
|
* Reports an exception thrown while uploading a draft action. The thrown error is
|
|
80314
80580
|
* otherwise swallowed by the upload handler's retry path, leaving the failure
|
|
@@ -80516,8 +80782,16 @@ class AbstractResourceRequestActionHandler {
|
|
|
80516
80782
|
const dispatchOptions = action.observabilityContext !== undefined
|
|
80517
80783
|
? { requestCorrelator: { observabilityContext: action.observabilityContext } }
|
|
80518
80784
|
: {};
|
|
80785
|
+
const method = request?.method?.toUpperCase() ?? 'UNKNOWN';
|
|
80786
|
+
const networkStart = Date.now();
|
|
80787
|
+
let responseReceived = false;
|
|
80519
80788
|
try {
|
|
80520
80789
|
const response = await this.networkAdapter(request, dispatchOptions);
|
|
80790
|
+
responseReceived = true;
|
|
80791
|
+
// Time the round-trip regardless of outcome (ok, retryable HTTP error, or non-ok
|
|
80792
|
+
// terminal error) — today only a THROWN error is visible; a slow-but-successful or
|
|
80793
|
+
// slow 4xx/5xx response is not.
|
|
80794
|
+
this.reportNetworkDuration(method, statusBucketOf(response.status), networkStart);
|
|
80521
80795
|
if (response.ok) {
|
|
80522
80796
|
await actionCompleted({
|
|
80523
80797
|
...action,
|
|
@@ -80673,6 +80947,11 @@ class AbstractResourceRequestActionHandler {
|
|
|
80673
80947
|
const error = normalizeError$1(e);
|
|
80674
80948
|
const attempt = this.getUploadRetryCount(action) + 1;
|
|
80675
80949
|
reportDraftActionUploadError(error, this.handlerId, attempt);
|
|
80950
|
+
// A thrown network call still has a round-trip duration worth surfacing — a slow
|
|
80951
|
+
// FAILING call is otherwise as invisible as a slow successful one.
|
|
80952
|
+
if (!responseReceived) {
|
|
80953
|
+
this.reportNetworkDuration(method, 'error', networkStart);
|
|
80954
|
+
}
|
|
80676
80955
|
await this.retryOrCap(action, error, actionErrored);
|
|
80677
80956
|
return ProcessActionResult.NETWORK_ERROR;
|
|
80678
80957
|
}
|
|
@@ -80708,12 +80987,17 @@ class AbstractResourceRequestActionHandler {
|
|
|
80708
80987
|
*/
|
|
80709
80988
|
async retryOrCap(action, lastFailure, actionErrored, retryDelayInMs, actionDataChanged) {
|
|
80710
80989
|
if (!draftQueueMaxRetryAttemptsGate.isOpen({ fallback: false })) {
|
|
80711
|
-
// Gate closed: preserve the pre-existing unbounded-retry behavior exactly.
|
|
80990
|
+
// Gate closed: preserve the pre-existing unbounded-retry behavior exactly. The
|
|
80991
|
+
// metric is still emitted (measure-only) so retry attempts are visible even with
|
|
80992
|
+
// the cap gate closed — cappedOut is always false here since nothing ever caps
|
|
80993
|
+
// out on this path.
|
|
80994
|
+
this.reportRetryAttempt(false);
|
|
80712
80995
|
await actionErrored(action, true, retryDelayInMs, actionDataChanged);
|
|
80713
80996
|
return;
|
|
80714
80997
|
}
|
|
80715
80998
|
const attempt = this.getUploadRetryCount(action) + 1;
|
|
80716
80999
|
if (attempt >= MAX_RETRY_ATTEMPTS) {
|
|
81000
|
+
this.reportRetryAttempt(true);
|
|
80717
81001
|
await actionErrored({
|
|
80718
81002
|
...action,
|
|
80719
81003
|
error: buildMaxRetryError(lastFailure),
|
|
@@ -80721,6 +81005,7 @@ class AbstractResourceRequestActionHandler {
|
|
|
80721
81005
|
}, false);
|
|
80722
81006
|
return;
|
|
80723
81007
|
}
|
|
81008
|
+
this.reportRetryAttempt(false);
|
|
80724
81009
|
// Persist the incremented attempt count so it survives restarts. Forcing
|
|
80725
81010
|
// actionDataChanged ensures the queue writes the updated metadata before the
|
|
80726
81011
|
// action is rescheduled for retry.
|
|
@@ -80734,12 +81019,12 @@ class AbstractResourceRequestActionHandler {
|
|
|
80734
81019
|
await actionErrored(retryingAction, true, retryDelayInMs, true);
|
|
80735
81020
|
}
|
|
80736
81021
|
async handleActionEnqueued(action) {
|
|
80737
|
-
const impactedKeys = await this.recordService.setSideEffectsForActions([action]);
|
|
80738
|
-
await this.recordService.reapplyRecordSideEffects(impactedKeys);
|
|
81022
|
+
const impactedKeys = await this.recordService.setSideEffectsForActions([action], 'enqueued');
|
|
81023
|
+
await this.recordService.reapplyRecordSideEffects(impactedKeys, 'enqueued');
|
|
80739
81024
|
}
|
|
80740
81025
|
async handleActionRemoved(action) {
|
|
80741
81026
|
const impactedKeys = await this.recordService.removeSideEffectsForAction(action);
|
|
80742
|
-
await this.recordService.reapplyRecordSideEffects(impactedKeys);
|
|
81027
|
+
await this.recordService.reapplyRecordSideEffects(impactedKeys, 'removed');
|
|
80743
81028
|
}
|
|
80744
81029
|
async handleActionReplaced(target, source) {
|
|
80745
81030
|
// remove both the siden effects from the actions being merged before we
|
|
@@ -80747,10 +81032,10 @@ class AbstractResourceRequestActionHandler {
|
|
|
80747
81032
|
const impactedKeysFromRemove = await this.recordService.removeSideEffectsForAction(source);
|
|
80748
81033
|
const removedSideEffectFromSet = await this.recordService.removeSideEffectsForAction(target);
|
|
80749
81034
|
// revert the values in the DEFAULT store back to what it was before the removed side effects
|
|
80750
|
-
await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromRemove, ...removedSideEffectFromSet]));
|
|
81035
|
+
await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromRemove, ...removedSideEffectFromSet]), 'replaced-remove');
|
|
80751
81036
|
// set the new side effect values for the merged action
|
|
80752
|
-
const impactedKeysFromSet = await this.recordService.setSideEffectsForActions([target]);
|
|
80753
|
-
await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromSet]));
|
|
81037
|
+
const impactedKeysFromSet = await this.recordService.setSideEffectsForActions([target], 'replaced-set');
|
|
81038
|
+
await this.recordService.reapplyRecordSideEffects(new Set([...impactedKeysFromSet]), 'replaced-set');
|
|
80754
81039
|
}
|
|
80755
81040
|
async handleActionCompleted(action, queueOperations) {
|
|
80756
81041
|
const { data: request, tag } = action;
|
|
@@ -80784,8 +81069,8 @@ class AbstractResourceRequestActionHandler {
|
|
|
80784
81069
|
actionsNeedingReplay.push(qo.action);
|
|
80785
81070
|
}
|
|
80786
81071
|
});
|
|
80787
|
-
const impactedKeys = await this.recordService.setSideEffectsForActions(actionsNeedingReplay);
|
|
80788
|
-
await this.recordService.reapplyRecordSideEffects(impactedKeys);
|
|
81072
|
+
const impactedKeys = await this.recordService.setSideEffectsForActions(actionsNeedingReplay, 'completed-replay');
|
|
81073
|
+
await this.recordService.reapplyRecordSideEffects(impactedKeys, 'completed-replay');
|
|
80789
81074
|
}
|
|
80790
81075
|
getQueueOperationsForCompletingDrafts(queue, action) {
|
|
80791
81076
|
const queueOperations = [];
|
|
@@ -81111,6 +81396,39 @@ class AbstractResourceRequestActionHandler {
|
|
|
81111
81396
|
return new StoreKeyMap();
|
|
81112
81397
|
});
|
|
81113
81398
|
}
|
|
81399
|
+
reportNetworkDuration(method, statusBucket, startedAt) {
|
|
81400
|
+
try {
|
|
81401
|
+
reportDraftQueueActionNetworkDuration(this.handlerId, method, statusBucket, Date.now() - startedAt);
|
|
81402
|
+
}
|
|
81403
|
+
catch {
|
|
81404
|
+
// Telemetry must not change upload processing behavior.
|
|
81405
|
+
}
|
|
81406
|
+
}
|
|
81407
|
+
reportRetryAttempt(cappedOut) {
|
|
81408
|
+
try {
|
|
81409
|
+
reportDraftQueueActionRetryAttempt(this.handlerId, cappedOut);
|
|
81410
|
+
}
|
|
81411
|
+
catch {
|
|
81412
|
+
// Telemetry must not change retry or cap behavior.
|
|
81413
|
+
}
|
|
81414
|
+
}
|
|
81415
|
+
}
|
|
81416
|
+
// Classifies an HTTP status into a small, greppable tag set for the network-duration metric —
|
|
81417
|
+
// never the raw status, to keep the metric's tag cardinality bounded.
|
|
81418
|
+
function statusBucketOf(status) {
|
|
81419
|
+
if (status === 0) {
|
|
81420
|
+
return '0';
|
|
81421
|
+
}
|
|
81422
|
+
if (status >= 200 && status <= 299) {
|
|
81423
|
+
return '2xx';
|
|
81424
|
+
}
|
|
81425
|
+
if (status >= 400 && status <= 499) {
|
|
81426
|
+
return '4xx';
|
|
81427
|
+
}
|
|
81428
|
+
if (status >= 500) {
|
|
81429
|
+
return '5xx';
|
|
81430
|
+
}
|
|
81431
|
+
return 'other';
|
|
81114
81432
|
}
|
|
81115
81433
|
function actionsForTag(tag, queue) {
|
|
81116
81434
|
return queue.filter((action) => action.tag === tag);
|
|
@@ -81474,10 +81792,16 @@ class UiApiDraftRecordService {
|
|
|
81474
81792
|
}
|
|
81475
81793
|
// calculates the side effects for a given set of actions
|
|
81476
81794
|
// and returns a set of impacted record keys
|
|
81477
|
-
async setSideEffectsForActions(changedActions) {
|
|
81478
|
-
const
|
|
81479
|
-
|
|
81480
|
-
|
|
81795
|
+
async setSideEffectsForActions(changedActions, lifecycle) {
|
|
81796
|
+
const startedAt = Date.now();
|
|
81797
|
+
try {
|
|
81798
|
+
const operations = await this.recalculateForChangedActions(changedActions);
|
|
81799
|
+
await this.sideEffectStore.addEffects(operations);
|
|
81800
|
+
return new Set(operations.map((o) => o.key));
|
|
81801
|
+
}
|
|
81802
|
+
finally {
|
|
81803
|
+
this.reportSideEffectRegionDuration('set', lifecycle, startedAt);
|
|
81804
|
+
}
|
|
81481
81805
|
}
|
|
81482
81806
|
// removes the associated side effects for a given action and returns
|
|
81483
81807
|
// a set of impacted record keys
|
|
@@ -81488,31 +81812,45 @@ class UiApiDraftRecordService {
|
|
|
81488
81812
|
}
|
|
81489
81813
|
// reads a set of records out of the durable store, re-applies current side
|
|
81490
81814
|
// effects and persists the changed record
|
|
81491
|
-
async reapplyRecordSideEffects(recordKeys) {
|
|
81492
|
-
const
|
|
81493
|
-
|
|
81494
|
-
|
|
81495
|
-
|
|
81496
|
-
|
|
81497
|
-
|
|
81498
|
-
|
|
81499
|
-
|
|
81500
|
-
|
|
81501
|
-
|
|
81502
|
-
|
|
81503
|
-
|
|
81504
|
-
|
|
81505
|
-
|
|
81506
|
-
|
|
81507
|
-
if (recordEntry
|
|
81508
|
-
|
|
81509
|
-
metadata
|
|
81815
|
+
async reapplyRecordSideEffects(recordKeys, lifecycle) {
|
|
81816
|
+
const startedAt = Date.now();
|
|
81817
|
+
try {
|
|
81818
|
+
const luvio = this.getLuvio();
|
|
81819
|
+
const keys = Array.from(recordKeys);
|
|
81820
|
+
const recordEntries = await this.durableRecordStore.getRecordsWithMetadata(keys);
|
|
81821
|
+
keys.forEach((key) => {
|
|
81822
|
+
let record;
|
|
81823
|
+
const metadata = {
|
|
81824
|
+
namespace: 'UiApi',
|
|
81825
|
+
representationName: 'RecordRepresentation',
|
|
81826
|
+
version: VERSION$1v$1,
|
|
81827
|
+
ingestionTimestamp: Date.now(),
|
|
81828
|
+
ttl: Number.MAX_SAFE_INTEGER,
|
|
81829
|
+
};
|
|
81830
|
+
const recordEntry = recordEntries.get(key);
|
|
81831
|
+
if (recordEntry) {
|
|
81832
|
+
record = recordEntry.record;
|
|
81833
|
+
if (recordEntry.metadata) {
|
|
81834
|
+
metadata.ingestionTimestamp = recordEntry.metadata.ingestionTimestamp;
|
|
81835
|
+
metadata.ttl = TTL$z;
|
|
81836
|
+
}
|
|
81510
81837
|
}
|
|
81511
|
-
|
|
81512
|
-
|
|
81513
|
-
|
|
81514
|
-
|
|
81515
|
-
|
|
81838
|
+
luvio.storePublish(key, record);
|
|
81839
|
+
luvio.publishStoreMetadata(key, metadata);
|
|
81840
|
+
});
|
|
81841
|
+
await luvio.storeBroadcast();
|
|
81842
|
+
}
|
|
81843
|
+
finally {
|
|
81844
|
+
this.reportSideEffectRegionDuration('reapply', lifecycle, startedAt);
|
|
81845
|
+
}
|
|
81846
|
+
}
|
|
81847
|
+
reportSideEffectRegionDuration(region, lifecycle, startedAt) {
|
|
81848
|
+
try {
|
|
81849
|
+
reportDraftQueueSideEffectRegionDuration(region, lifecycle, Date.now() - startedAt);
|
|
81850
|
+
}
|
|
81851
|
+
catch {
|
|
81852
|
+
// Telemetry must not change draft processing behavior.
|
|
81853
|
+
}
|
|
81516
81854
|
}
|
|
81517
81855
|
async synthesizeId(apiName) {
|
|
81518
81856
|
const objectInfo = await this.objectInfoService.getObjectInfo(apiName);
|
|
@@ -81748,7 +82086,7 @@ class UpdateRecordQuickActionExecutionRepresentationHandler extends AbstractQuic
|
|
|
81748
82086
|
// since we don't ingest a record from the response, we need to manually trigger a re-apply here to ensure we
|
|
81749
82087
|
// re-ingest the record without effects applied
|
|
81750
82088
|
await this.recordService.removeSideEffectsForAction(action);
|
|
81751
|
-
await this.recordService.reapplyRecordSideEffects(new Set([action.tag]));
|
|
82089
|
+
await this.recordService.reapplyRecordSideEffects(new Set([action.tag]), 'quick-action-completed');
|
|
81752
82090
|
// notify luvio that record is now changed and needs to be refreshed
|
|
81753
82091
|
await luvio.notifyStoreUpdateAvailable([action.tag]);
|
|
81754
82092
|
}
|
|
@@ -90428,6 +90766,18 @@ const draftQueueInstrumentation = {
|
|
|
90428
90766
|
onDurableOperation(op, segment, durationMs) {
|
|
90429
90767
|
reportDraftQueueDurableOperation(op, segment, durationMs);
|
|
90430
90768
|
},
|
|
90769
|
+
onWorkerTiming(waitMs, holdMs, queueDepth) {
|
|
90770
|
+
reportDraftQueueWorkerTiming(waitMs, holdMs, queueDepth);
|
|
90771
|
+
},
|
|
90772
|
+
onActionQueueWait(handlerId, waitMs) {
|
|
90773
|
+
reportDraftQueueActionQueueWait(handlerId, waitMs);
|
|
90774
|
+
},
|
|
90775
|
+
onActionDrainDuration(handlerId, durationMs) {
|
|
90776
|
+
reportDraftQueueActionDrainDuration(handlerId, durationMs);
|
|
90777
|
+
},
|
|
90778
|
+
onDrainCycle(durationMs, batchSize) {
|
|
90779
|
+
reportDraftQueueDrainCycle(durationMs, batchSize);
|
|
90780
|
+
},
|
|
90431
90781
|
};
|
|
90432
90782
|
|
|
90433
90783
|
// so eslint doesn't complain about nimbus
|
|
@@ -93770,6 +94120,9 @@ class SideEffectStore {
|
|
|
93770
94120
|
this.initialize();
|
|
93771
94121
|
}
|
|
93772
94122
|
async addEffects(effects) {
|
|
94123
|
+
// Wall-clock across the whole method (including the durable write), matching
|
|
94124
|
+
// how the equivalent removeEffects/getEffectsByTag windows are measured.
|
|
94125
|
+
const startTime = Date.now();
|
|
93773
94126
|
const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
|
|
93774
94127
|
const durableEntries = {};
|
|
93775
94128
|
effects.forEach((effect) => {
|
|
@@ -93784,8 +94137,11 @@ class SideEffectStore {
|
|
|
93784
94137
|
this.regenerateKeyToEffectMap();
|
|
93785
94138
|
}
|
|
93786
94139
|
await this.durableStore.setEntries(durableEntries, SIDE_EFFECT_SEGMENT);
|
|
94140
|
+
this.reportOperation('add', incremental, startTime);
|
|
93787
94141
|
}
|
|
93788
94142
|
async removeEffects(effects) {
|
|
94143
|
+
// See addEffects — same wall-clock-across-the-method measurement.
|
|
94144
|
+
const startTime = Date.now();
|
|
93789
94145
|
const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
|
|
93790
94146
|
const effectKeys = effects.map((e) => e.uniqueId);
|
|
93791
94147
|
effects.forEach((effect) => {
|
|
@@ -93799,6 +94155,7 @@ class SideEffectStore {
|
|
|
93799
94155
|
this.regenerateKeyToEffectMap();
|
|
93800
94156
|
}
|
|
93801
94157
|
await this.durableStore.evictEntries(effectKeys, SIDE_EFFECT_SEGMENT);
|
|
94158
|
+
this.reportOperation('remove', incremental, startTime);
|
|
93802
94159
|
}
|
|
93803
94160
|
getEffects(key) {
|
|
93804
94161
|
const effects = this.keyToEffectMap.get(key);
|
|
@@ -93808,6 +94165,10 @@ class SideEffectStore {
|
|
|
93808
94165
|
return effects;
|
|
93809
94166
|
}
|
|
93810
94167
|
getEffectsByTag(tag) {
|
|
94168
|
+
// This scan is still O(N) over every effect regardless of the incremental-map
|
|
94169
|
+
// gate — timing it tells us whether that residual scan is the quadratic hotspot during churn.
|
|
94170
|
+
const startTime = Date.now();
|
|
94171
|
+
const incremental = draftQueueSideEffectMapGate.isOpen({ fallback: true });
|
|
93811
94172
|
const filteredEffects = [];
|
|
93812
94173
|
const { keyToEffectMap } = this;
|
|
93813
94174
|
// Loop through every entry in the map
|
|
@@ -93817,7 +94178,17 @@ class SideEffectStore {
|
|
|
93817
94178
|
// Add the matching effects to the filtered list
|
|
93818
94179
|
filteredEffects.push(...matchingEffects);
|
|
93819
94180
|
}
|
|
93820
|
-
|
|
94181
|
+
const result = filteredEffects.sort((a, b) => a.timestamp - b.timestamp);
|
|
94182
|
+
this.reportOperation('getByTag', incremental, startTime);
|
|
94183
|
+
return result;
|
|
94184
|
+
}
|
|
94185
|
+
reportOperation(op, incremental, startedAt) {
|
|
94186
|
+
try {
|
|
94187
|
+
reportDraftQueueSideEffectOp(op, incremental, Date.now() - startedAt, this.allEffects.size);
|
|
94188
|
+
}
|
|
94189
|
+
catch {
|
|
94190
|
+
// Telemetry must not change side-effect store behavior.
|
|
94191
|
+
}
|
|
93821
94192
|
}
|
|
93822
94193
|
async initialize() {
|
|
93823
94194
|
const effects = await this.durableStore.getAllEntries(SIDE_EFFECT_SEGMENT);
|
|
@@ -97014,7 +97385,7 @@ function buildServiceDescriptor$b(luvio) {
|
|
|
97014
97385
|
},
|
|
97015
97386
|
};
|
|
97016
97387
|
}
|
|
97017
|
-
// version: 1.
|
|
97388
|
+
// version: 1.456.0-cef836b978
|
|
97018
97389
|
|
|
97019
97390
|
/**
|
|
97020
97391
|
* Copyright (c) 2022, Salesforce, Inc.,
|
|
@@ -97040,7 +97411,7 @@ function buildServiceDescriptor$a(notifyRecordUpdateAvailable, getNormalizedLuvi
|
|
|
97040
97411
|
},
|
|
97041
97412
|
};
|
|
97042
97413
|
}
|
|
97043
|
-
// version: 1.
|
|
97414
|
+
// version: 1.456.0-cef836b978
|
|
97044
97415
|
|
|
97045
97416
|
function findExecutableOperation$1(input) {
|
|
97046
97417
|
const operations = input.query.definitions.filter(
|
|
@@ -99749,7 +100120,7 @@ register$1({
|
|
|
99749
100120
|
id: '@salesforce/lds-network-adapter',
|
|
99750
100121
|
instrument: instrument$2,
|
|
99751
100122
|
});
|
|
99752
|
-
// version: 1.
|
|
100123
|
+
// version: 1.456.0-cef836b978
|
|
99753
100124
|
|
|
99754
100125
|
const { create: create$2, keys: keys$2 } = Object;
|
|
99755
100126
|
const { stringify, parse } = JSON;
|
|
@@ -100213,10 +100584,11 @@ class BaseArrayFieldDef {
|
|
|
100213
100584
|
}
|
|
100214
100585
|
]);
|
|
100215
100586
|
}
|
|
100587
|
+
const existingArrayData = input.existingNormalizedData?.data;
|
|
100216
100588
|
const arrayNormalizationErrors = [];
|
|
100217
100589
|
const normalizedArray = [];
|
|
100218
100590
|
input.data.forEach((item, index) => {
|
|
100219
|
-
const existingItemData =
|
|
100591
|
+
const existingItemData = existingArrayData?.[index];
|
|
100220
100592
|
const normalizedItemResult = this.items.write(cache, {
|
|
100221
100593
|
...input,
|
|
100222
100594
|
data: item,
|
|
@@ -107284,7 +107656,7 @@ function registerCallback(cb) {
|
|
|
107284
107656
|
cb(graphql_v1_import, graphql_imperative$1, graphql_imperative_legacy_v1_import, graphql_state_manager, useOneStoreGraphQL);
|
|
107285
107657
|
}
|
|
107286
107658
|
}
|
|
107287
|
-
// version: 1.
|
|
107659
|
+
// version: 1.456.0-6ed480b93c
|
|
107288
107660
|
|
|
107289
107661
|
function createFragmentMap(documentNode) {
|
|
107290
107662
|
const fragments = {};
|
|
@@ -124013,7 +124385,7 @@ function keyBuilderFromType(luvio, object) {
|
|
|
124013
124385
|
return keyBuilder$z(luvio, keyParams);
|
|
124014
124386
|
}
|
|
124015
124387
|
|
|
124016
|
-
const { assign: assign$1, create: create$1, freeze: freeze$1, isFrozen: isFrozen$1, keys: keys$1 } = Object;
|
|
124388
|
+
const { assign: assign$1, create: create$1, freeze: freeze$1, getPrototypeOf: getPrototypeOf$1, isFrozen: isFrozen$1, keys: keys$1 } = Object;
|
|
124017
124389
|
const { isArray: isArray$2 } = Array;
|
|
124018
124390
|
const { concat: concat$1, filter: filter$1, includes: includes$1, push: push$1, reduce: reduce$1 } = Array.prototype;
|
|
124019
124391
|
|
|
@@ -136527,7 +136899,7 @@ register$1({
|
|
|
136527
136899
|
configuration: { ...configurationForGraphQLAdapters$1 },
|
|
136528
136900
|
instrument: instrument$1,
|
|
136529
136901
|
});
|
|
136530
|
-
// version: 1.
|
|
136902
|
+
// version: 1.456.0-6ed480b93c
|
|
136531
136903
|
|
|
136532
136904
|
// On core the unstable adapters are re-exported with different names,
|
|
136533
136905
|
// we want to match them here.
|
|
@@ -136679,7 +137051,7 @@ withDefaultLuvio((luvio) => {
|
|
|
136679
137051
|
unstable_graphQL_imperative = createImperativeAdapter(luvio, createInstrumentedAdapter(ldsAdapter, adapterMetadata), adapterMetadata);
|
|
136680
137052
|
graphQLImperative = ldsAdapter;
|
|
136681
137053
|
});
|
|
136682
|
-
// version: 1.
|
|
137054
|
+
// version: 1.456.0-6ed480b93c
|
|
136683
137055
|
|
|
136684
137056
|
var gqlApi = /*#__PURE__*/Object.freeze({
|
|
136685
137057
|
__proto__: null,
|
|
@@ -137478,7 +137850,7 @@ const callbacks$1 = [];
|
|
|
137478
137850
|
function register(r) {
|
|
137479
137851
|
callbacks$1.forEach((callback) => callback(r));
|
|
137480
137852
|
}
|
|
137481
|
-
// version: 1.
|
|
137853
|
+
// version: 1.456.0-cef836b978
|
|
137482
137854
|
|
|
137483
137855
|
/**
|
|
137484
137856
|
* Copyright (c) 2022, Salesforce, Inc.,
|
|
@@ -137764,7 +138136,7 @@ function buildAdapterValidationConfig(displayName, paramsMeta) {
|
|
|
137764
138136
|
}
|
|
137765
138137
|
const keyPrefix = 'UiApi';
|
|
137766
138138
|
|
|
137767
|
-
const { assign, create, freeze, isFrozen, keys } = Object;
|
|
138139
|
+
const { assign, create, freeze, getPrototypeOf, isFrozen, keys } = Object;
|
|
137768
138140
|
const { isArray } = Array;
|
|
137769
138141
|
const { concat, filter, includes, push, reduce } = Array.prototype;
|
|
137770
138142
|
|
|
@@ -138767,4 +139139,4 @@ const { luvio } = getRuntime();
|
|
|
138767
139139
|
setDefaultLuvio({ luvio });
|
|
138768
139140
|
|
|
138769
139141
|
export { createPrimingSession, draftManager, draftQueue, evictCacheRecordsByIds, evictExpiredCacheEntries, executeAdapter, executeMutatingAdapter, getImperativeAdapterNames, importLuvioAdapterModule, importOneStoreAdapterModule, invokeAdapter, invokeAdapterWithDraftToMerge, invokeAdapterWithDraftToReplace, invokeAdapterWithMetadata, nimbusDraftQueue, registerReportObserver, setMetadataTTL, setUiApiRecordTTL, stopEviction, subscribeToAdapter };
|
|
138770
|
-
// version: 1.
|
|
139142
|
+
// version: 1.456.0-cef836b978
|