@lostgradient/weft 0.17.0 → 0.19.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.
Files changed (172) hide show
  1. package/README.md +3 -1
  2. package/dist/cli/conformance.js +14 -18
  3. package/dist/cli/generated/operation-catalog.snapshot.json +331 -16
  4. package/dist/cli/generated/operation-client.generated.d.ts +39 -6
  5. package/dist/cli/generated/operation-client.generated.js +6 -0
  6. package/dist/core/context/child-workflow-pipe.d.ts +1 -1
  7. package/dist/core/context/child-workflow-pipe.js +1 -1
  8. package/dist/core/engine/construction.d.ts +2 -0
  9. package/dist/core/engine/construction.js +3 -0
  10. package/dist/core/engine/index.js +1 -0
  11. package/dist/core/engine/listing.d.ts +1 -0
  12. package/dist/core/engine/listing.js +6 -4
  13. package/dist/core/weft-error.d.ts +1 -1
  14. package/dist/core/weft-error.js +2 -1
  15. package/dist/core/worker-execution-dispatcher.d.ts +8 -0
  16. package/dist/core/worker-execution-dispatcher.js +4 -0
  17. package/dist/core/worker-execution-strategy-options.d.ts +16 -0
  18. package/dist/core/worker-execution-strategy.js +71 -89
  19. package/dist/core/worker-fault-handling.d.ts +45 -0
  20. package/dist/core/worker-fault-handling.js +88 -0
  21. package/dist/core/worker-protocol.d.ts +18 -1
  22. package/dist/core/worker-protocol.js +1 -1
  23. package/dist/core/worker-realm-readiness.d.ts +78 -0
  24. package/dist/core/worker-realm-readiness.js +127 -0
  25. package/dist/index.d.ts +3 -1
  26. package/dist/index.js +28 -1
  27. package/dist/json-schema.js +1 -1
  28. package/dist/runtime/portable.d.ts +14 -0
  29. package/dist/runtime/portable.js +10 -0
  30. package/dist/server/authorization-scope.d.ts +32 -2
  31. package/dist/server/index.d.ts +73 -8
  32. package/dist/server/index.js +11 -3
  33. package/dist/server/operations/get-principal.d.ts +75 -0
  34. package/dist/server/operations/get-principal.js +41 -0
  35. package/dist/server/operations/get-task-diagnostics.d.ts +43 -18
  36. package/dist/server/operations/get-task-diagnostics.js +87 -126
  37. package/dist/server/operations/get-worker-diagnostics.d.ts +177 -0
  38. package/dist/server/operations/get-worker-diagnostics.js +117 -0
  39. package/dist/server/operations/list-worker-registration-rejections.d.ts +79 -0
  40. package/dist/server/operations/list-worker-registration-rejections.js +60 -0
  41. package/dist/server/operations/list-workers.js +1 -3
  42. package/dist/server/operations/static-registrations.d.ts +28 -0
  43. package/dist/server/operations/static-registrations.js +248 -0
  44. package/dist/server/rest-bindings.d.ts +5 -0
  45. package/dist/server/rest-bindings.js +34 -313
  46. package/dist/server/runtime/authentication-bridge.js +6 -14
  47. package/dist/server/runtime/context.d.ts +23 -0
  48. package/dist/server/runtime/task-dispatch.d.ts +7 -1
  49. package/dist/server/runtime/task-dispatch.js +126 -55
  50. package/dist/server/runtime/task-ledger-completion.d.ts +68 -0
  51. package/dist/server/runtime/task-ledger-completion.js +72 -0
  52. package/dist/server/runtime/task-ledger-recovery.d.ts +55 -0
  53. package/dist/server/runtime/task-ledger-recovery.js +73 -0
  54. package/dist/server/runtime/task-ledger-runtime.d.ts +64 -0
  55. package/dist/server/runtime/task-ledger-runtime.js +34 -0
  56. package/dist/server/runtime/task-metrics.d.ts +6 -4
  57. package/dist/server/runtime/task-polling.d.ts +14 -12
  58. package/dist/server/runtime/task-polling.js +106 -82
  59. package/dist/server/runtime/task-reconciliation.d.ts +35 -8
  60. package/dist/server/runtime/task-reconciliation.js +75 -74
  61. package/dist/server/runtime/task-result-resolution.d.ts +2 -10
  62. package/dist/server/runtime/task-result-resolution.js +0 -67
  63. package/dist/server/runtime/task-result-view.d.ts +82 -0
  64. package/dist/server/runtime/task-result-view.js +48 -0
  65. package/dist/server/runtime/websocket-worker-messaging.d.ts +16 -0
  66. package/dist/server/runtime/websocket-worker-messaging.js +32 -0
  67. package/dist/server/runtime/websocket-worker-registration.d.ts +41 -0
  68. package/dist/server/runtime/websocket-worker-registration.js +134 -0
  69. package/dist/server/runtime/websocket-worker.d.ts +0 -1
  70. package/dist/server/runtime/websocket-worker.js +64 -116
  71. package/dist/server/serve-internals.d.ts +9 -6
  72. package/dist/server/serve-internals.js +14 -40
  73. package/dist/server/task-ledger-codec.d.ts +40 -0
  74. package/dist/server/task-ledger-codec.js +195 -0
  75. package/dist/server/task-ledger-keys.d.ts +13 -0
  76. package/dist/server/task-ledger-keys.js +5 -0
  77. package/dist/server/task-ledger-limits.d.ts +34 -0
  78. package/dist/server/task-ledger-limits.js +5 -0
  79. package/dist/server/task-ledger-transition-helpers.d.ts +38 -0
  80. package/dist/server/task-ledger-transition-helpers.js +42 -0
  81. package/dist/server/task-ledger-transitions-cancellation.d.ts +31 -0
  82. package/dist/server/task-ledger-transitions-cancellation.js +73 -0
  83. package/dist/server/task-ledger-transitions.d.ts +129 -0
  84. package/dist/server/task-ledger-transitions.js +162 -0
  85. package/dist/server/task-ledger-types.d.ts +220 -0
  86. package/dist/server/task-ledger-types.js +1 -0
  87. package/dist/server/task-ledger.d.ts +17 -0
  88. package/dist/server/task-ledger.js +24 -0
  89. package/dist/server/task-state.d.ts +25 -152
  90. package/dist/server/task-state.js +0 -188
  91. package/dist/server/worker-admission-policy.d.ts +70 -0
  92. package/dist/server/worker-admission-policy.js +0 -0
  93. package/dist/storage/compressed-storage.js +1 -1
  94. package/dist/storage/index.d.ts +0 -2
  95. package/dist/storage/interface.d.ts +0 -2
  96. package/dist/storage/interface.js +1 -1
  97. package/dist/storage/lmdb.js +1 -1
  98. package/dist/storage/memory.js +1 -1
  99. package/dist/storage/neon.js +1 -1
  100. package/dist/storage/postgres.js +1 -1
  101. package/dist/storage/resolve.js +1 -1
  102. package/dist/storage/scoped-storage.js +1 -1
  103. package/dist/storage/testing.js +1 -1
  104. package/dist/storage/turso.js +1 -1
  105. package/dist/storage/web-extension.js +2 -2
  106. package/dist/version.d.ts +1 -1
  107. package/dist/version.js +1 -1
  108. package/dist/web-extension.js +1 -1
  109. package/dist/worker/index.d.ts +2 -0
  110. package/dist/worker/index.js +30 -4
  111. package/dist/worker/manifest/canonical-json.d.ts +20 -0
  112. package/dist/worker/manifest/canonical-json.js +13 -0
  113. package/dist/worker/manifest/capabilities.d.ts +24 -0
  114. package/dist/worker/manifest/capabilities.js +74 -0
  115. package/dist/worker/manifest/content-digest.d.ts +20 -0
  116. package/dist/worker/manifest/content-digest.js +13 -0
  117. package/dist/worker/manifest/declared-shape-digest.d.ts +14 -0
  118. package/dist/worker/manifest/declared-shape-digest.js +4 -0
  119. package/dist/worker/manifest/digest.d.ts +82 -0
  120. package/dist/worker/manifest/digest.js +9 -0
  121. package/dist/worker/manifest/execution-identity.d.ts +92 -0
  122. package/dist/worker/manifest/execution-identity.js +36 -0
  123. package/dist/worker/manifest/failure.d.ts +59 -0
  124. package/dist/worker/manifest/failure.js +4 -0
  125. package/dist/worker/manifest/index.d.ts +22 -0
  126. package/dist/worker/manifest/index.js +23 -0
  127. package/dist/worker/manifest/internal-realm.d.ts +50 -0
  128. package/dist/worker/manifest/internal-realm.js +39 -0
  129. package/dist/worker/manifest/is-record.d.ts +12 -0
  130. package/dist/worker/manifest/is-record.js +6 -0
  131. package/dist/worker/manifest/json-scan.d.ts +26 -0
  132. package/dist/worker/manifest/json-scan.js +88 -0
  133. package/dist/worker/manifest/limits.d.ts +138 -0
  134. package/dist/worker/manifest/limits.js +1 -0
  135. package/dist/worker/manifest/normalize.d.ts +63 -0
  136. package/dist/worker/manifest/normalize.js +73 -0
  137. package/dist/worker/manifest/parse-json.d.ts +24 -0
  138. package/dist/worker/manifest/parse-json.js +15 -0
  139. package/dist/worker/manifest/parse.d.ts +86 -0
  140. package/dist/worker/manifest/parse.js +188 -0
  141. package/dist/worker/manifest/registry-contract-builder.d.ts +120 -0
  142. package/dist/worker/manifest/registry-contract-builder.js +65 -0
  143. package/dist/worker/manifest/types.d.ts +263 -0
  144. package/dist/worker/manifest/types.js +1 -0
  145. package/dist/worker/manifest/utf8.d.ts +13 -0
  146. package/dist/worker/manifest/utf8.js +7 -0
  147. package/dist/worker/options.d.ts +55 -8
  148. package/dist/worker/options.js +65 -9
  149. package/dist/worker/protocol-internals.d.ts +1 -2
  150. package/dist/worker/protocol-internals.js +0 -5
  151. package/dist/worker/protocol-messages.d.ts +33 -17
  152. package/dist/worker/protocol-schemas.d.ts +36 -74
  153. package/dist/worker/protocol-schemas.js +25 -18
  154. package/dist/worker/protocol-version.d.ts +18 -14
  155. package/dist/worker/protocol-version.js +1 -1
  156. package/dist/worker/protocol.js +1 -1
  157. package/dist/worker/registry/deployment-consistency.d.ts +78 -0
  158. package/dist/worker/registry/deployment-consistency.js +27 -0
  159. package/dist/worker/registry/drain.d.ts +14 -0
  160. package/dist/worker/registry/drain.js +24 -0
  161. package/dist/worker/registry/rejections.d.ts +31 -0
  162. package/dist/worker/registry/rejections.js +10 -0
  163. package/dist/worker/registry/summary.d.ts +0 -3
  164. package/dist/worker/registry/summary.js +2 -5
  165. package/dist/worker/registry/types.d.ts +10 -3
  166. package/dist/worker/registry.d.ts +47 -2
  167. package/dist/worker/registry.js +45 -32
  168. package/dist/workers/workflow-worker-entry.d.ts +12 -7
  169. package/dist/workers/workflow-worker-entry.js +9 -2
  170. package/package.json +3 -3
  171. package/dist/server/task-resolved-record.d.ts +0 -12
  172. package/dist/server/task-resolved-record.js +0 -35
@@ -1,4 +1,16 @@
1
+ import {
2
+ DeploymentConsistencyGuard
3
+ } from "./registry/deployment-consistency.js";
4
+ import {
5
+ createDrainRecord,
6
+ isWorkerDraining,
7
+ workerHealth
8
+ } from "./registry/drain.js";
1
9
  import { FairShareCounters } from "./registry/fair-share.js";
10
+ import {
11
+ appendRegistrationRejection,
12
+ recentRegistrationRejections
13
+ } from "./registry/rejections.js";
2
14
  import {
3
15
  matchesWorkerCapabilities,
4
16
  pickFairShare,
@@ -18,6 +30,8 @@ export class WorkerRegistry {
18
30
  #policy;
19
31
  #roundRobinCursor;
20
32
  #fairShareCounts;
33
+ #deploymentConsistency;
34
+ #rejections;
21
35
  constructor(options) {
22
36
  this.#workers = new Map;
23
37
  this.#inFlightTasks = new Map;
@@ -25,10 +39,18 @@ export class WorkerRegistry {
25
39
  this.#policy = options?.policy ?? "least-loaded";
26
40
  this.#roundRobinCursor = new Map;
27
41
  this.#fairShareCounts = new FairShareCounters;
42
+ this.#deploymentConsistency = new DeploymentConsistencyGuard;
43
+ this.#rejections = [];
28
44
  }
29
45
  get policy() {
30
46
  return this.#policy;
31
47
  }
48
+ checkDeploymentConsistency(deploymentName, buildId, artifactDigest) {
49
+ return this.#deploymentConsistency.check(deploymentName, buildId, artifactDigest);
50
+ }
51
+ recordDeploymentConsistency(deploymentName, buildId, artifactDigest) {
52
+ this.#deploymentConsistency.record(deploymentName, buildId, artifactDigest);
53
+ }
32
54
  register(info) {
33
55
  const now = Date.now();
34
56
  let inFlight = 0;
@@ -43,7 +65,8 @@ export class WorkerRegistry {
43
65
  ...info.deploymentName !== void 0 ? { deploymentName: info.deploymentName } : {},
44
66
  ...info.buildId !== void 0 ? { buildId: info.buildId } : {},
45
67
  ...info.runtimeVersion !== void 0 ? { runtimeVersion: info.runtimeVersion } : {},
46
- ...info.gitSha !== void 0 ? { gitSha: info.gitSha } : {},
68
+ manifest: info.manifest,
69
+ acceptedManifestDigest: info.acceptedManifestDigest,
47
70
  startedAt: info.startedAt ?? now,
48
71
  capabilities: { ...info.capabilities },
49
72
  inFlight,
@@ -98,7 +121,7 @@ export class WorkerRegistry {
98
121
  return !1;
99
122
  if (!matchesWorkerCapabilities(worker, activityName, queue))
100
123
  return !1;
101
- if (this.#isWorkerDraining(worker))
124
+ if (isWorkerDraining(worker, this.#deploymentDrainStates))
102
125
  return !1;
103
126
  return !0;
104
127
  }
@@ -124,6 +147,15 @@ export class WorkerRegistry {
124
147
  this.#inFlightTasks.set(operationId, task);
125
148
  this.taskAssigned(workerId);
126
149
  }
150
+ releaseReservation(operationId) {
151
+ const task = this.#inFlightTasks.get(operationId);
152
+ if (task === void 0)
153
+ return;
154
+ this.#inFlightTasks.delete(operationId);
155
+ this.taskCompleted(task.workerId);
156
+ this.#releaseFairShare(task);
157
+ return task;
158
+ }
127
159
  checkExpiredTasks(now) {
128
160
  const expired = [];
129
161
  for (const task of this.#inFlightTasks.values())
@@ -179,6 +211,12 @@ export class WorkerRegistry {
179
211
  getAll() {
180
212
  return [...this.#workers.values()];
181
213
  }
214
+ recordRejection(entry) {
215
+ appendRegistrationRejection(this.#rejections, entry);
216
+ }
217
+ getRecentRejections(limit) {
218
+ return recentRegistrationRejections(this.#rejections, limit);
219
+ }
182
220
  markWorkerDraining(workerId, options) {
183
221
  const worker = this.#workers.get(workerId);
184
222
  if (worker === void 0)
@@ -194,7 +232,7 @@ export class WorkerRegistry {
194
232
  workerId,
195
233
  affectedWorkers: 1,
196
234
  inFlight: worker.inFlight,
197
- health: this.#workerHealth(worker)
235
+ health: workerHealth(worker, this.#deploymentDrainStates)
198
236
  };
199
237
  }
200
238
  clearWorkerDrain(workerId) {
@@ -208,7 +246,7 @@ export class WorkerRegistry {
208
246
  workerId,
209
247
  affectedWorkers: 1,
210
248
  inFlight: worker.inFlight,
211
- health: this.#workerHealth(worker)
249
+ health: workerHealth(worker, this.#deploymentDrainStates)
212
250
  };
213
251
  }
214
252
  markDeploymentDraining(deploymentName, options) {
@@ -234,11 +272,10 @@ export class WorkerRegistry {
234
272
  lastHeartbeat: worker.lastHeartbeat,
235
273
  startedAt: worker.startedAt,
236
274
  capabilities: worker.capabilities,
237
- health: this.#workerHealth(worker),
275
+ health: workerHealth(worker, this.#deploymentDrainStates),
238
276
  deploymentName: worker.deploymentName,
239
277
  buildId: worker.buildId,
240
- runtimeVersion: worker.runtimeVersion,
241
- gitSha: worker.gitSha
278
+ runtimeVersion: worker.runtimeVersion
242
279
  }));
243
280
  }
244
281
  getDeploymentSummaries(_now) {
@@ -249,7 +286,7 @@ export class WorkerRegistry {
249
286
  return this.#workers.size;
250
287
  }
251
288
  #deploymentDrainResult(deploymentName) {
252
- const workers = [...this.#workers.values()].filter((worker) => worker.deploymentName === deploymentName), inFlight = workers.reduce((total, worker) => total + worker.inFlight, 0), healthValues = workers.map((worker) => this.#workerHealth(worker));
289
+ const workers = [...this.#workers.values()].filter((worker) => worker.deploymentName === deploymentName), inFlight = workers.reduce((total, worker) => total + worker.inFlight, 0), healthValues = workers.map((worker) => workerHealth(worker, this.#deploymentDrainStates));
253
290
  return {
254
291
  target: "deployment",
255
292
  deploymentName,
@@ -258,33 +295,9 @@ export class WorkerRegistry {
258
295
  health: deploymentHealth(healthValues, this.#deploymentDrainStates.has(deploymentName))
259
296
  };
260
297
  }
261
- #isWorkerDraining(worker) {
262
- return this.#drainRecordForWorker(worker) !== void 0;
263
- }
264
- #workerHealth(worker) {
265
- if (!this.#isWorkerDraining(worker))
266
- return "active";
267
- return worker.inFlight > 0 ? "draining" : "drained";
268
- }
269
- #drainRecordForWorker(worker) {
270
- if (worker.drainStartedAt !== void 0)
271
- return {
272
- startedAt: worker.drainStartedAt,
273
- ...worker.drainReason !== void 0 ? { reason: worker.drainReason } : {}
274
- };
275
- if (worker.deploymentName === void 0)
276
- return;
277
- return this.#deploymentDrainStates.get(worker.deploymentName);
278
- }
279
298
  #releaseFairShare(task) {
280
299
  if (task.fairShareKey === void 0)
281
300
  return;
282
301
  this.#fairShareCounts.release(task.workerId, task.fairShareKey);
283
302
  }
284
303
  }
285
- function createDrainRecord(options) {
286
- return {
287
- startedAt: options?.updatedAt ?? Date.now(),
288
- ...options?.reason !== void 0 ? { reason: options.reason } : {}
289
- };
290
- }
@@ -9,16 +9,21 @@
9
9
  */
10
10
  import type { WorkerWorkflowContext } from './workflow-runner.ts';
11
11
  /**
12
- * Factory that resolves a workflow type name to its handler. Handlers receive
13
- * a worker-side {@link WorkerWorkflowContext} as the first argument so they
14
- * can read `ctx.workflowId` exactly like inline-mode handlers do.
12
+ * A workflow handler. Receives a worker-side {@link WorkerWorkflowContext} as
13
+ * the first argument so it can read `ctx.workflowId` exactly like inline-mode
14
+ * handlers do.
15
15
  */
16
- export type WorkflowHandlerFactory = (type: string) => ((ctx: WorkerWorkflowContext, input: unknown) => AsyncGenerator) | undefined;
16
+ export type WorkflowHandler = (ctx: WorkerWorkflowContext, input: unknown) => AsyncGenerator;
17
17
  /**
18
18
  * Initialize the worker message loop. Call this from within a Web Worker
19
19
  * to wire up the message protocol.
20
20
  *
21
- * @param getWorkflowHandler - Factory that resolves a workflow type name to
22
- * its async generator function. Typically backed by a registration map.
21
+ * Sends a {@link WorkerRealmReadyMessage} first (WFT-28), built from exactly the
22
+ * workflow type names in `workflows` the host validates it against its own
23
+ * expected manifest before this realm can receive its first `run` turn.
24
+ *
25
+ * @param workflows - Map of workflow type name to its async generator
26
+ * function. This is also the realm's complete workflow-type advertisement:
27
+ * the same names the ready manifest reports.
23
28
  */
24
- export declare function initializeWorkerMessageLoop(getWorkflowHandler: WorkflowHandlerFactory): void;
29
+ export declare function initializeWorkerMessageLoop(workflows: Readonly<Record<string, WorkflowHandler>>): void;
@@ -3,6 +3,7 @@ import {
3
3
  createBoundedWorkerFailureMessage,
4
4
  WORKER_PROTOCOL_VERSION
5
5
  } from "../core/worker-protocol.js";
6
+ import { buildInternalRealmManifest } from "../worker/manifest/internal-realm.js";
6
7
  import {
7
8
  cleanupWorkflowRunnerState,
8
9
  createWorkflowRunnerContext,
@@ -14,8 +15,14 @@ const workerPostMessage = self.postMessage.bind(self), workerClose = "close" in
14
15
  assertWorkerProtocolMessageWithinLimit(message, maxProtocolMessageBytes);
15
16
  workerPostMessage(message);
16
17
  };
17
- export function initializeWorkerMessageLoop(getWorkflowHandler) {
18
- const runnerContext = createWorkflowRunnerContext();
18
+ export function initializeWorkerMessageLoop(workflows) {
19
+ const runnerContext = createWorkflowRunnerContext(), getWorkflowHandler = (type) => workflows[type], readyMessage = {
20
+ type: "ready",
21
+ protocolVersion: WORKER_PROTOCOL_VERSION,
22
+ realmGeneration: crypto.randomUUID(),
23
+ manifest: buildInternalRealmManifest(Object.keys(workflows))
24
+ };
25
+ workerPostMessage(readyMessage);
19
26
  self.addEventListener("message", async (event) => {
20
27
  const message = event.data;
21
28
  switch (message.type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lostgradient/weft",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "A Bun-native durable execution engine with pluggable key-value storage.",
5
5
  "keywords": [
6
6
  "bun",
@@ -283,8 +283,8 @@
283
283
  "husky": "^9.1.7",
284
284
  "lint-staged": "^16.4.0",
285
285
  "lmdb": "^3.5.2",
286
- "oxlint": "^1.56.0",
287
- "oxlint-tsgolint": "^0.17.0",
286
+ "oxlint": "^1.79.0",
287
+ "oxlint-tsgolint": "^7.0.2001",
288
288
  "pg": "^8.11.0",
289
289
  "playwright": "^1.60.0",
290
290
  "prettier": "^3.8.1",
@@ -1,12 +0,0 @@
1
- import type { InflightRecord, ResolvedRecord, TaskResolutionReason } from './task-state.ts';
2
- export declare function buildResolvedRecord(parameters: {
3
- operationId: string;
4
- status: 'completed' | 'failed';
5
- resolvedAt: number;
6
- normalizedRecord: InflightRecord | null;
7
- resolutionReason: TaskResolutionReason;
8
- value?: unknown;
9
- error?: string | undefined;
10
- queueLatencyMs?: number | undefined;
11
- executionLatencyMs?: number | undefined;
12
- }): ResolvedRecord;
@@ -1,35 +0,0 @@
1
- export function buildResolvedRecord(parameters) {
2
- const resolvedRecord = {
3
- operationId: parameters.operationId,
4
- status: parameters.status,
5
- resolvedAt: parameters.resolvedAt
6
- };
7
- if (parameters.value !== void 0)
8
- resolvedRecord.value = parameters.value;
9
- if (parameters.error !== void 0)
10
- resolvedRecord.error = parameters.error;
11
- const { normalizedRecord } = parameters;
12
- if (normalizedRecord === null)
13
- return resolvedRecord;
14
- return {
15
- ...resolvedRecord,
16
- activityName: normalizedRecord.activityName,
17
- queue: normalizedRecord.queue,
18
- workerId: normalizedRecord.workerId,
19
- attempt: normalizedRecord.attempt,
20
- visibilityTimeout: normalizedRecord.visibilityTimeout,
21
- ...normalizedRecord.workflowId === void 0 ? {} : { workflowId: normalizedRecord.workflowId },
22
- firstQueuedAt: normalizedRecord.firstQueuedAt,
23
- lastQueuedAt: normalizedRecord.lastQueuedAt,
24
- lastDispatchedAt: normalizedRecord.lastDispatchedAt,
25
- startedAt: normalizedRecord.startedAt,
26
- completedAt: parameters.resolvedAt,
27
- lastHeartbeatAt: normalizedRecord.lastHeartbeatAt,
28
- retryCount: normalizedRecord.retryCount,
29
- requeueCount: normalizedRecord.requeueCount,
30
- lastRequeueReason: normalizedRecord.lastRequeueReason,
31
- resolutionReason: parameters.resolutionReason,
32
- queueLatencyMs: parameters.queueLatencyMs,
33
- executionLatencyMs: parameters.executionLatencyMs
34
- };
35
- }