@qlever-llc/trellis 0.10.17 → 0.19.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (283) hide show
  1. package/esm/auth/mod.d.ts +1 -1
  2. package/esm/auth/mod.d.ts.map +1 -1
  3. package/esm/auth/mod.js +1 -1
  4. package/esm/auth/protocol.d.ts +416 -398
  5. package/esm/auth/protocol.d.ts.map +1 -1
  6. package/esm/auth/protocol.js +35 -33
  7. package/esm/codec.d.ts +1 -0
  8. package/esm/codec.d.ts.map +1 -1
  9. package/esm/codec.js +1 -0
  10. package/esm/contract_support/canonical.d.ts +3 -0
  11. package/esm/contract_support/canonical.d.ts.map +1 -1
  12. package/esm/contract_support/canonical.js +3 -0
  13. package/esm/contract_support/mod.d.ts +28 -4
  14. package/esm/contract_support/mod.d.ts.map +1 -1
  15. package/esm/contract_support/mod.js +85 -4
  16. package/esm/contract_support/protocol.d.ts +92 -7
  17. package/esm/contract_support/protocol.d.ts.map +1 -1
  18. package/esm/contract_support/protocol.js +40 -6
  19. package/esm/errors/index.d.ts +9 -9
  20. package/esm/generated-sdk/auth/api.d.ts +4 -1
  21. package/esm/generated-sdk/auth/api.d.ts.map +1 -1
  22. package/esm/generated-sdk/auth/api.js +6 -1
  23. package/esm/generated-sdk/auth/client.d.ts +47 -32
  24. package/esm/generated-sdk/auth/client.d.ts.map +1 -1
  25. package/esm/generated-sdk/auth/contract.d.ts +1 -1
  26. package/esm/generated-sdk/auth/contract.d.ts.map +1 -1
  27. package/esm/generated-sdk/auth/contract.js +1570 -1202
  28. package/esm/generated-sdk/auth/schemas.d.ts +1757 -1759
  29. package/esm/generated-sdk/auth/schemas.d.ts.map +1 -1
  30. package/esm/generated-sdk/auth/schemas.js +963 -768
  31. package/esm/generated-sdk/auth/types.d.ts +292 -302
  32. package/esm/generated-sdk/auth/types.d.ts.map +1 -1
  33. package/esm/generated-sdk/auth/types.js +1 -1
  34. package/esm/generated-sdk/health/client.d.ts +4 -4
  35. package/esm/generated-sdk/health/client.d.ts.map +1 -1
  36. package/esm/generated-sdk/health/contract.d.ts +1 -1
  37. package/esm/generated-sdk/health/contract.d.ts.map +1 -1
  38. package/esm/generated-sdk/health/contract.js +2 -10
  39. package/esm/generated-sdk/health/schemas.d.ts +1 -14
  40. package/esm/generated-sdk/health/schemas.d.ts.map +1 -1
  41. package/esm/generated-sdk/health/schemas.js +1 -9
  42. package/esm/generated-sdk/health/types.d.ts +3 -5
  43. package/esm/generated-sdk/health/types.d.ts.map +1 -1
  44. package/esm/generated-sdk/health/types.js +1 -2
  45. package/esm/generated-sdk/jobs/api.d.ts +13 -0
  46. package/esm/generated-sdk/jobs/api.d.ts.map +1 -1
  47. package/esm/generated-sdk/jobs/client.d.ts +6 -4
  48. package/esm/generated-sdk/jobs/client.d.ts.map +1 -1
  49. package/esm/generated-sdk/jobs/contract.d.ts +14 -1
  50. package/esm/generated-sdk/jobs/contract.d.ts.map +1 -1
  51. package/esm/generated-sdk/jobs/contract.js +268 -1
  52. package/esm/generated-sdk/jobs/owned_api.d.ts +13 -0
  53. package/esm/generated-sdk/jobs/owned_api.d.ts.map +1 -1
  54. package/esm/generated-sdk/jobs/owned_api.js +20 -1
  55. package/esm/generated-sdk/jobs/schemas.d.ts +437 -0
  56. package/esm/generated-sdk/jobs/schemas.d.ts.map +1 -1
  57. package/esm/generated-sdk/jobs/schemas.js +211 -0
  58. package/esm/generated-sdk/jobs/types.d.ts +123 -1
  59. package/esm/generated-sdk/jobs/types.d.ts.map +1 -1
  60. package/esm/generated-sdk/jobs/types.js +1 -1
  61. package/esm/generated-sdk/state/client.d.ts +4 -4
  62. package/esm/generated-sdk/state/client.d.ts.map +1 -1
  63. package/esm/generated-sdk/trellis-core/api.d.ts +4 -1
  64. package/esm/generated-sdk/trellis-core/api.d.ts.map +1 -1
  65. package/esm/generated-sdk/trellis-core/api.js +6 -1
  66. package/esm/generated-sdk/trellis-core/client.d.ts +28 -3
  67. package/esm/generated-sdk/trellis-core/client.d.ts.map +1 -1
  68. package/esm/generated-sdk/trellis-core/contract.d.ts +1 -1
  69. package/esm/generated-sdk/trellis-core/contract.d.ts.map +1 -1
  70. package/esm/generated-sdk/trellis-core/contract.js +91 -1
  71. package/esm/generated-sdk/trellis-core/schemas.d.ts +113 -0
  72. package/esm/generated-sdk/trellis-core/schemas.d.ts.map +1 -1
  73. package/esm/generated-sdk/trellis-core/schemas.js +81 -0
  74. package/esm/generated-sdk/trellis-core/types.d.ts +23 -1
  75. package/esm/generated-sdk/trellis-core/types.d.ts.map +1 -1
  76. package/esm/generated-sdk/trellis-core/types.js +1 -1
  77. package/esm/health.d.ts +1 -1
  78. package/esm/health.d.ts.map +1 -1
  79. package/esm/health.js +1 -1
  80. package/esm/index.d.ts +2 -2
  81. package/esm/index.d.ts.map +1 -1
  82. package/esm/index.js +1 -1
  83. package/esm/jobs.d.ts +69 -3
  84. package/esm/jobs.d.ts.map +1 -1
  85. package/esm/jobs.js +92 -3
  86. package/esm/server/health.d.ts +2 -6
  87. package/esm/server/health.d.ts.map +1 -1
  88. package/esm/server/health_schemas.d.ts +0 -8
  89. package/esm/server/health_schemas.d.ts.map +1 -1
  90. package/esm/server/health_schemas.js +0 -5
  91. package/esm/server/internal_jobs/bindings.d.ts +11 -0
  92. package/esm/server/internal_jobs/bindings.d.ts.map +1 -1
  93. package/esm/server/internal_jobs/job-manager.d.ts +44 -1
  94. package/esm/server/internal_jobs/job-manager.d.ts.map +1 -1
  95. package/esm/server/internal_jobs/job-manager.js +361 -51
  96. package/esm/server/internal_jobs/key-coordinator.d.ts +260 -0
  97. package/esm/server/internal_jobs/key-coordinator.d.ts.map +1 -0
  98. package/esm/server/internal_jobs/key-coordinator.js +580 -0
  99. package/esm/server/internal_jobs/projection.d.ts.map +1 -1
  100. package/esm/server/internal_jobs/projection.js +2 -0
  101. package/esm/server/internal_jobs/runtime-worker.d.ts +5 -1
  102. package/esm/server/internal_jobs/runtime-worker.d.ts.map +1 -1
  103. package/esm/server/internal_jobs/runtime-worker.js +14 -2
  104. package/esm/server/internal_jobs/types.d.ts +5 -5
  105. package/esm/server/internal_jobs/types.d.ts.map +1 -1
  106. package/esm/server/internal_jobs/types.js +6 -0
  107. package/esm/server/service.d.ts +8 -3
  108. package/esm/server/service.d.ts.map +1 -1
  109. package/esm/server/service.js +127 -6
  110. package/esm/service/drizzle.d.ts +27 -0
  111. package/esm/service/drizzle.d.ts.map +1 -0
  112. package/esm/service/drizzle.js +84 -0
  113. package/esm/service/mod.d.ts +1 -1
  114. package/esm/service/mod.d.ts.map +1 -1
  115. package/esm/service/mod.js +1 -1
  116. package/esm/service/outbox_inbox.d.ts.map +1 -1
  117. package/esm/service/outbox_inbox.js +13 -2
  118. package/esm/trellis.d.ts +24 -8
  119. package/esm/trellis.d.ts.map +1 -1
  120. package/esm/trellis.js +44 -22
  121. package/package.json +14 -2
  122. package/script/auth/mod.d.ts +1 -1
  123. package/script/auth/mod.d.ts.map +1 -1
  124. package/script/auth/mod.js +22 -6
  125. package/script/auth/protocol.d.ts +416 -398
  126. package/script/auth/protocol.d.ts.map +1 -1
  127. package/script/auth/protocol.js +40 -37
  128. package/script/codec.d.ts +1 -0
  129. package/script/codec.d.ts.map +1 -1
  130. package/script/codec.js +1 -0
  131. package/script/contract_support/canonical.d.ts +3 -0
  132. package/script/contract_support/canonical.d.ts.map +1 -1
  133. package/script/contract_support/canonical.js +3 -0
  134. package/script/contract_support/mod.d.ts +28 -4
  135. package/script/contract_support/mod.d.ts.map +1 -1
  136. package/script/contract_support/mod.js +90 -4
  137. package/script/contract_support/protocol.d.ts +92 -7
  138. package/script/contract_support/protocol.d.ts.map +1 -1
  139. package/script/contract_support/protocol.js +41 -7
  140. package/script/errors/index.d.ts +9 -9
  141. package/script/generated-sdk/auth/api.d.ts +4 -1
  142. package/script/generated-sdk/auth/api.d.ts.map +1 -1
  143. package/script/generated-sdk/auth/api.js +6 -1
  144. package/script/generated-sdk/auth/client.d.ts +47 -32
  145. package/script/generated-sdk/auth/client.d.ts.map +1 -1
  146. package/script/generated-sdk/auth/contract.d.ts +1 -1
  147. package/script/generated-sdk/auth/contract.d.ts.map +1 -1
  148. package/script/generated-sdk/auth/contract.js +1570 -1202
  149. package/script/generated-sdk/auth/schemas.d.ts +1757 -1759
  150. package/script/generated-sdk/auth/schemas.d.ts.map +1 -1
  151. package/script/generated-sdk/auth/schemas.js +963 -768
  152. package/script/generated-sdk/auth/types.d.ts +292 -302
  153. package/script/generated-sdk/auth/types.d.ts.map +1 -1
  154. package/script/generated-sdk/auth/types.js +1 -1
  155. package/script/generated-sdk/health/client.d.ts +4 -4
  156. package/script/generated-sdk/health/client.d.ts.map +1 -1
  157. package/script/generated-sdk/health/contract.d.ts +1 -1
  158. package/script/generated-sdk/health/contract.d.ts.map +1 -1
  159. package/script/generated-sdk/health/contract.js +2 -10
  160. package/script/generated-sdk/health/schemas.d.ts +1 -14
  161. package/script/generated-sdk/health/schemas.d.ts.map +1 -1
  162. package/script/generated-sdk/health/schemas.js +1 -9
  163. package/script/generated-sdk/health/types.d.ts +3 -5
  164. package/script/generated-sdk/health/types.d.ts.map +1 -1
  165. package/script/generated-sdk/health/types.js +1 -2
  166. package/script/generated-sdk/jobs/api.d.ts +13 -0
  167. package/script/generated-sdk/jobs/api.d.ts.map +1 -1
  168. package/script/generated-sdk/jobs/client.d.ts +6 -4
  169. package/script/generated-sdk/jobs/client.d.ts.map +1 -1
  170. package/script/generated-sdk/jobs/contract.d.ts +14 -1
  171. package/script/generated-sdk/jobs/contract.d.ts.map +1 -1
  172. package/script/generated-sdk/jobs/contract.js +268 -1
  173. package/script/generated-sdk/jobs/owned_api.d.ts +13 -0
  174. package/script/generated-sdk/jobs/owned_api.d.ts.map +1 -1
  175. package/script/generated-sdk/jobs/owned_api.js +19 -0
  176. package/script/generated-sdk/jobs/schemas.d.ts +437 -0
  177. package/script/generated-sdk/jobs/schemas.d.ts.map +1 -1
  178. package/script/generated-sdk/jobs/schemas.js +212 -1
  179. package/script/generated-sdk/jobs/types.d.ts +123 -1
  180. package/script/generated-sdk/jobs/types.d.ts.map +1 -1
  181. package/script/generated-sdk/jobs/types.js +1 -1
  182. package/script/generated-sdk/state/client.d.ts +4 -4
  183. package/script/generated-sdk/state/client.d.ts.map +1 -1
  184. package/script/generated-sdk/trellis-core/api.d.ts +4 -1
  185. package/script/generated-sdk/trellis-core/api.d.ts.map +1 -1
  186. package/script/generated-sdk/trellis-core/api.js +6 -1
  187. package/script/generated-sdk/trellis-core/client.d.ts +28 -3
  188. package/script/generated-sdk/trellis-core/client.d.ts.map +1 -1
  189. package/script/generated-sdk/trellis-core/contract.d.ts +1 -1
  190. package/script/generated-sdk/trellis-core/contract.d.ts.map +1 -1
  191. package/script/generated-sdk/trellis-core/contract.js +91 -1
  192. package/script/generated-sdk/trellis-core/schemas.d.ts +113 -0
  193. package/script/generated-sdk/trellis-core/schemas.d.ts.map +1 -1
  194. package/script/generated-sdk/trellis-core/schemas.js +81 -0
  195. package/script/generated-sdk/trellis-core/types.d.ts +23 -1
  196. package/script/generated-sdk/trellis-core/types.d.ts.map +1 -1
  197. package/script/generated-sdk/trellis-core/types.js +1 -1
  198. package/script/health.d.ts +1 -1
  199. package/script/health.d.ts.map +1 -1
  200. package/script/health.js +1 -2
  201. package/script/index.d.ts +2 -2
  202. package/script/index.d.ts.map +1 -1
  203. package/script/index.js +2 -3
  204. package/script/jobs.d.ts +69 -3
  205. package/script/jobs.d.ts.map +1 -1
  206. package/script/jobs.js +93 -3
  207. package/script/server/health.d.ts +2 -6
  208. package/script/server/health.d.ts.map +1 -1
  209. package/script/server/health_schemas.d.ts +0 -8
  210. package/script/server/health_schemas.d.ts.map +1 -1
  211. package/script/server/health_schemas.js +1 -6
  212. package/script/server/internal_jobs/bindings.d.ts +11 -0
  213. package/script/server/internal_jobs/bindings.d.ts.map +1 -1
  214. package/script/server/internal_jobs/job-manager.d.ts +44 -1
  215. package/script/server/internal_jobs/job-manager.d.ts.map +1 -1
  216. package/script/server/internal_jobs/job-manager.js +361 -51
  217. package/script/server/internal_jobs/key-coordinator.d.ts +260 -0
  218. package/script/server/internal_jobs/key-coordinator.d.ts.map +1 -0
  219. package/script/server/internal_jobs/key-coordinator.js +593 -0
  220. package/script/server/internal_jobs/projection.d.ts.map +1 -1
  221. package/script/server/internal_jobs/projection.js +2 -0
  222. package/script/server/internal_jobs/runtime-worker.d.ts +5 -1
  223. package/script/server/internal_jobs/runtime-worker.d.ts.map +1 -1
  224. package/script/server/internal_jobs/runtime-worker.js +14 -2
  225. package/script/server/internal_jobs/types.d.ts +5 -5
  226. package/script/server/internal_jobs/types.d.ts.map +1 -1
  227. package/script/server/internal_jobs/types.js +6 -0
  228. package/script/server/service.d.ts +8 -3
  229. package/script/server/service.d.ts.map +1 -1
  230. package/script/server/service.js +126 -5
  231. package/script/service/drizzle.d.ts +27 -0
  232. package/script/service/drizzle.d.ts.map +1 -0
  233. package/script/service/drizzle.js +88 -0
  234. package/script/service/mod.d.ts +1 -1
  235. package/script/service/mod.d.ts.map +1 -1
  236. package/script/service/mod.js +1 -2
  237. package/script/service/outbox_inbox.d.ts.map +1 -1
  238. package/script/service/outbox_inbox.js +13 -2
  239. package/script/trellis.d.ts +24 -8
  240. package/script/trellis.d.ts.map +1 -1
  241. package/script/trellis.js +44 -22
  242. package/src/auth/mod.ts +28 -2
  243. package/src/auth/protocol.ts +72 -37
  244. package/src/codec.ts +1 -0
  245. package/src/contract_support/canonical.ts +3 -0
  246. package/src/contract_support/mod.ts +158 -5
  247. package/src/contract_support/protocol.ts +56 -9
  248. package/src/health.ts +0 -1
  249. package/src/index.ts +2 -1
  250. package/src/jobs.ts +138 -1
  251. package/src/sdk/_generated/auth/api.ts +9 -2
  252. package/src/sdk/_generated/auth/client.ts +85 -78
  253. package/src/sdk/_generated/auth/contract.ts +1803 -1435
  254. package/src/sdk/_generated/auth/schemas.ts +1166 -971
  255. package/src/sdk/_generated/auth/types.ts +330 -314
  256. package/src/sdk/_generated/core/api.ts +9 -2
  257. package/src/sdk/_generated/core/client.ts +41 -2
  258. package/src/sdk/_generated/core/contract.ts +91 -1
  259. package/src/sdk/_generated/core/schemas.ts +81 -0
  260. package/src/sdk/_generated/core/types.ts +23 -1
  261. package/src/sdk/_generated/health/client.ts +6 -6
  262. package/src/sdk/_generated/health/contract.ts +2 -10
  263. package/src/sdk/_generated/health/schemas.ts +1 -9
  264. package/src/sdk/_generated/health/types.ts +6 -2
  265. package/src/sdk/_generated/jobs/client.ts +17 -6
  266. package/src/sdk/_generated/jobs/contract.ts +269 -1
  267. package/src/sdk/_generated/jobs/owned_api.ts +21 -0
  268. package/src/sdk/_generated/jobs/schemas.ts +213 -0
  269. package/src/sdk/_generated/jobs/types.ts +116 -1
  270. package/src/sdk/_generated/state/client.ts +6 -6
  271. package/src/server/health.ts +2 -6
  272. package/src/server/health_schemas.ts +0 -6
  273. package/src/server/internal_jobs/bindings.ts +11 -0
  274. package/src/server/internal_jobs/job-manager.ts +436 -16
  275. package/src/server/internal_jobs/key-coordinator.ts +955 -0
  276. package/src/server/internal_jobs/projection.ts +2 -0
  277. package/src/server/internal_jobs/runtime-worker.ts +17 -1
  278. package/src/server/internal_jobs/types.ts +6 -0
  279. package/src/server/service.ts +168 -9
  280. package/src/service/drizzle.ts +125 -0
  281. package/src/service/mod.ts +0 -1
  282. package/src/service/outbox_inbox.ts +16 -6
  283. package/src/trellis.ts +76 -27
@@ -9,12 +9,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _JobManager_instances, _JobManager_context, _JobManager_meta, _JobManager_getQueueBinding, _JobManager_publishJobEvent;
12
+ var _JobManager_instances, _JobManager_context, _JobManager_meta, _JobManager_getQueueBinding, _JobManager_publishJobEvent, _JobManager_submit, _JobManager_admitKeyedCreate, _JobManager_removeQueuedKeyedReservation, _JobManager_restoreReplacedKeyedReservation, _JobManager_publishSkipped, _JobManager_keyedHeartbeat, _JobManager_releaseKeyedSlot, _JobManager_releaseKeyedSlotAfterPublishFailure, _JobManager_publishStaleCompletionIgnored;
13
13
  import { headers as natsHeaders } from "@nats-io/nats-core";
14
14
  import { ulid } from "ulid";
15
15
  import { createMapCarrier, injectTraceContext, } from "../../telemetry/carrier.js";
16
16
  import { recordTrellisError } from "../../telemetry/mod.js";
17
+ import { JobNotEnqueuedError } from "../../jobs.js";
17
18
  import { ActiveJob, ActiveJobRuntimeError, JobCancellationToken, } from "./active-job.js";
19
+ import { normalizeJobKeyPolicy } from "./key-coordinator.js";
18
20
  export class JobProcessError extends Error {
19
21
  constructor(kind, message) {
20
22
  super(message);
@@ -41,41 +43,47 @@ export class JobManager {
41
43
  __classPrivateFieldSet(this, _JobManager_context, context, "f");
42
44
  }
43
45
  async create(type, payload) {
44
- const binding = __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_getQueueBinding).call(this, type);
45
- const meta = __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this);
46
- const now = meta.nowIso();
47
- const id = meta.nextJobId();
48
- const context = createJobContext();
49
- const namespace = __classPrivateFieldGet(this, _JobManager_context, "f").jobs.namespace;
50
- const deadline = computeDeadline(now, binding.defaultDeadlineMs);
51
- const job = {
52
- id,
53
- service: namespace,
54
- type,
55
- state: "pending",
56
- context,
57
- payload,
58
- createdAt: now,
59
- updatedAt: now,
60
- tries: 0,
61
- maxTries: binding.maxDeliver,
62
- ...(deadline ? { deadline } : {}),
63
- };
64
- const event = {
65
- jobId: id,
66
- service: job.service,
67
- jobType: type,
68
- eventType: "created",
69
- state: "pending",
70
- context,
71
- tries: 0,
72
- maxTries: binding.maxDeliver,
73
- payload,
74
- ...(deadline ? { deadline } : {}),
75
- timestamp: now,
76
- };
77
- await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, type, id, event);
78
- return job;
46
+ const outcome = await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_submit).call(this, type, payload, true);
47
+ if (outcome.kind === "accepted") {
48
+ return outcome.job;
49
+ }
50
+ if (outcome.kind === "coalesced") {
51
+ throw new JobNotEnqueuedError({
52
+ reason: "coalesced",
53
+ key: outcome.key,
54
+ active: 0,
55
+ queued: 1,
56
+ limit: 0,
57
+ existingJobId: outcome.existing.id,
58
+ });
59
+ }
60
+ if (outcome.kind === "replaced") {
61
+ throw new JobNotEnqueuedError({
62
+ reason: "queue-depth",
63
+ key: outcome.key,
64
+ active: 0,
65
+ queued: 1,
66
+ limit: 0,
67
+ existingJobId: outcome.replaced.id,
68
+ });
69
+ }
70
+ throw new JobNotEnqueuedError({
71
+ reason: outcome.reason,
72
+ key: outcome.key,
73
+ active: outcome.active,
74
+ queued: outcome.queued,
75
+ limit: outcome.limit,
76
+ });
77
+ }
78
+ async submit(type, payload) {
79
+ return await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_submit).call(this, type, payload, false);
80
+ }
81
+ async cleanupQueuedKeyedJob(job) {
82
+ const queue = __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_getQueueBinding).call(this, job.type);
83
+ const keyedPolicy = getKeyPolicy(queue);
84
+ if (!keyedPolicy)
85
+ return;
86
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_removeQueuedKeyedReservation).call(this, job, keyedPolicy);
79
87
  }
80
88
  process(job, cancellation, handler, metadata = {}, validation = {}) {
81
89
  return this.processWithHeartbeat(job, cancellation, () => {
@@ -83,25 +91,78 @@ export class JobManager {
83
91
  }, handler, metadata, validation);
84
92
  }
85
93
  async processWithHeartbeat(job, cancellation, heartbeat, handler, metadata = {}, validation = {}) {
86
- __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_getQueueBinding).call(this, job.type);
87
94
  const tries = job.tries + 1;
88
- await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, job.type, job.id, {
89
- jobId: job.id,
90
- service: job.service,
91
- jobType: job.type,
92
- eventType: "started",
93
- state: "active",
94
- previousState: job.state,
95
- context: job.context,
96
- tries,
97
- timestamp: __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this).nowIso(),
98
- });
95
+ const queue = __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_getQueueBinding).call(this, job.type);
96
+ const keyedPolicy = getKeyPolicy(queue);
97
+ let lease;
98
+ let staleSlots = [];
99
+ if (keyedPolicy) {
100
+ const coordinator = __classPrivateFieldGet(this, _JobManager_context, "f").keyCoordinator;
101
+ if (!coordinator) {
102
+ throw new Error(`Keyed jobs queue '${job.type}' requires the JOBS_KEYS coordinator`);
103
+ }
104
+ const acquired = await coordinator.acquireActiveSlot({
105
+ service: job.service,
106
+ jobType: job.type,
107
+ jobId: job.id,
108
+ payload: job.payload,
109
+ context: job.context,
110
+ lifecycleState: metadata.latestState ?? job.state,
111
+ tries,
112
+ instanceId: metadata.instanceId ?? "unknown",
113
+ now: __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this).nowIso(),
114
+ policy: keyedPolicy,
115
+ });
116
+ if (acquired.kind === "blocked") {
117
+ return { outcome: "deferred", tries, reason: acquired.reason };
118
+ }
119
+ lease = {
120
+ key: acquired.key,
121
+ keyHash: acquired.keyHash,
122
+ slotToken: acquired.slotToken,
123
+ policy: keyedPolicy,
124
+ };
125
+ staleSlots = acquired.stale;
126
+ }
127
+ try {
128
+ for (const stale of staleSlots) {
129
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, job.type, stale.jobId, {
130
+ jobId: stale.jobId,
131
+ service: job.service,
132
+ jobType: job.type,
133
+ eventType: "stale",
134
+ state: "stale",
135
+ previousState: "active",
136
+ context: stale.context,
137
+ tries: stale.tries,
138
+ error: "keyed job lease expired",
139
+ timestamp: __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this).nowIso(),
140
+ });
141
+ }
142
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, job.type, job.id, {
143
+ jobId: job.id,
144
+ service: job.service,
145
+ jobType: job.type,
146
+ eventType: "started",
147
+ state: "active",
148
+ previousState: job.state,
149
+ context: job.context,
150
+ tries,
151
+ timestamp: __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this).nowIso(),
152
+ });
153
+ }
154
+ catch (error) {
155
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_releaseKeyedSlotAfterPublishFailure).call(this, job, lease, error);
156
+ throw error;
157
+ }
99
158
  try {
100
- const result = await this.withActiveJobAndHeartbeat({ ...job, state: "active", tries }, cancellation, heartbeat, handler, metadata);
159
+ const result = await this.withActiveJobAndHeartbeat({ ...job, state: "active", tries }, cancellation, lease ? __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_keyedHeartbeat).call(this, job, lease, heartbeat) : heartbeat, handler, metadata, lease);
101
160
  if (cancellation.isHostShutdown()) {
161
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_releaseKeyedSlot).call(this, job, lease);
102
162
  return { outcome: "interrupted", tries };
103
163
  }
104
164
  if (cancellation.isCancelled()) {
165
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_releaseKeyedSlot).call(this, job, lease);
105
166
  return { outcome: "cancelled", tries };
106
167
  }
107
168
  try {
@@ -114,6 +175,11 @@ export class JobManager {
114
175
  catch (error) {
115
176
  throw JobProcessError.failed(error instanceof Error ? error.message : String(error));
116
177
  }
178
+ const release = await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_releaseKeyedSlot).call(this, job, lease);
179
+ if (release === "staleCompletion") {
180
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishStaleCompletionIgnored).call(this, job, tries);
181
+ return { outcome: "stale_completion_ignored", tries };
182
+ }
117
183
  await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, job.type, job.id, {
118
184
  jobId: job.id,
119
185
  service: job.service,
@@ -130,9 +196,11 @@ export class JobManager {
130
196
  }
131
197
  catch (error) {
132
198
  if (cancellation.isHostShutdown()) {
199
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_releaseKeyedSlot).call(this, job, lease);
133
200
  return { outcome: "interrupted", tries };
134
201
  }
135
202
  if (cancellation.isCancelled()) {
203
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_releaseKeyedSlot).call(this, job, lease);
136
204
  return { outcome: "cancelled", tries };
137
205
  }
138
206
  if (error instanceof JobProcessError) {
@@ -144,6 +212,11 @@ export class JobManager {
144
212
  operation: job.type,
145
213
  phase: "handler_result",
146
214
  });
215
+ const release = await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_releaseKeyedSlot).call(this, job, lease);
216
+ if (release === "staleCompletion") {
217
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishStaleCompletionIgnored).call(this, job, tries);
218
+ return { outcome: "stale_completion_ignored", tries };
219
+ }
147
220
  await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, job.type, job.id, {
148
221
  jobId: job.id,
149
222
  service: job.service,
@@ -164,6 +237,11 @@ export class JobManager {
164
237
  operation: job.type,
165
238
  phase: "handler_result",
166
239
  });
240
+ const release = await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_releaseKeyedSlot).call(this, job, lease);
241
+ if (release === "staleCompletion") {
242
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishStaleCompletionIgnored).call(this, job, tries);
243
+ return { outcome: "stale_completion_ignored", tries };
244
+ }
167
245
  await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, job.type, job.id, {
168
246
  jobId: job.id,
169
247
  service: job.service,
@@ -234,7 +312,10 @@ export class JobManager {
234
312
  throw new ActiveJobRuntimeError("worker heartbeat unavailable");
235
313
  }, f, metadata);
236
314
  }
237
- async withActiveJobAndHeartbeat(job, cancellation, heartbeat, f, metadata = {}) {
315
+ async withActiveJobAndHeartbeat(job, cancellation, heartbeat, f, metadata = {}, lease) {
316
+ const stopAutoHeartbeat = lease
317
+ ? startAutoHeartbeat(heartbeat, lease.policy.heartbeatIntervalMs)
318
+ : () => { };
238
319
  const activeJob = new ActiveJob(job, cancellation, {
239
320
  updateProgress: (progress) => this.emitProgress(job, progress),
240
321
  log: (entry) => this.emitLog(job, entry),
@@ -252,7 +333,12 @@ export class JobManager {
252
333
  }, {
253
334
  redeliveryCount: metadata.redeliveryCount ?? 0,
254
335
  });
255
- return await f(activeJob);
336
+ try {
337
+ return await f(activeJob);
338
+ }
339
+ finally {
340
+ stopAutoHeartbeat();
341
+ }
256
342
  }
257
343
  }
258
344
  _JobManager_context = new WeakMap(), _JobManager_instances = new WeakSet(), _JobManager_meta = function _JobManager_meta() {
@@ -282,7 +368,231 @@ _JobManager_context = new WeakMap(), _JobManager_instances = new WeakSet(), _Job
282
368
  });
283
369
  throw error;
284
370
  }
371
+ }, _JobManager_submit = async function _JobManager_submit(type, payload, strictCreate) {
372
+ const binding = __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_getQueueBinding).call(this, type);
373
+ const meta = __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this);
374
+ const now = meta.nowIso();
375
+ const id = meta.nextJobId();
376
+ const context = createJobContext();
377
+ const namespace = __classPrivateFieldGet(this, _JobManager_context, "f").jobs.namespace;
378
+ const deadline = computeDeadline(now, binding.defaultDeadlineMs);
379
+ const job = {
380
+ id,
381
+ service: namespace,
382
+ type,
383
+ state: "pending",
384
+ context,
385
+ payload,
386
+ createdAt: now,
387
+ updatedAt: now,
388
+ tries: 0,
389
+ maxTries: binding.maxDeliver,
390
+ ...(deadline ? { deadline } : {}),
391
+ };
392
+ const event = {
393
+ jobId: id,
394
+ service: job.service,
395
+ jobType: type,
396
+ eventType: "created",
397
+ state: "pending",
398
+ context,
399
+ tries: 0,
400
+ maxTries: binding.maxDeliver,
401
+ payload,
402
+ ...(deadline ? { deadline } : {}),
403
+ timestamp: now,
404
+ };
405
+ const keyedPolicy = getKeyPolicy(binding);
406
+ if (keyedPolicy) {
407
+ const admission = await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_admitKeyedCreate).call(this, {
408
+ type,
409
+ job,
410
+ event,
411
+ policy: keyedPolicy,
412
+ strictCreate,
413
+ });
414
+ if (admission.kind !== "accepted" && admission.kind !== "replaced") {
415
+ return admission;
416
+ }
417
+ if (strictCreate && admission.kind === "replaced") {
418
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_restoreReplacedKeyedReservation).call(this, job, admission.replaced, keyedPolicy);
419
+ return {
420
+ kind: "rejected",
421
+ key: admission.key,
422
+ reason: "queue-depth",
423
+ active: admission.state.active.length,
424
+ queued: admission.state.queued.length,
425
+ limit: keyedPolicy.queue.maxQueuedPerKey,
426
+ };
427
+ }
428
+ if (admission.kind === "replaced") {
429
+ try {
430
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishSkipped).call(this, type, admission.replaced, now);
431
+ }
432
+ catch (error) {
433
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_restoreReplacedKeyedReservation).call(this, job, admission.replaced, keyedPolicy);
434
+ throw error;
435
+ }
436
+ }
437
+ try {
438
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, type, id, event);
439
+ }
440
+ catch (error) {
441
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_removeQueuedKeyedReservation).call(this, job, keyedPolicy);
442
+ throw error;
443
+ }
444
+ if (admission.kind === "replaced") {
445
+ return {
446
+ kind: "replaced",
447
+ key: admission.key,
448
+ replaced: {
449
+ service: admission.replaced.service,
450
+ jobType: admission.replaced.jobType,
451
+ id: admission.replaced.id,
452
+ },
453
+ job,
454
+ };
455
+ }
456
+ return { kind: "accepted", job, key: admission.key };
457
+ }
458
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, type, id, event);
459
+ return { kind: "accepted", job };
460
+ }, _JobManager_admitKeyedCreate = async function _JobManager_admitKeyedCreate(args) {
461
+ const coordinator = __classPrivateFieldGet(this, _JobManager_context, "f").keyCoordinator;
462
+ if (!coordinator) {
463
+ throw new Error(`Keyed jobs queue '${args.type}' requires the JOBS_KEYS coordinator`);
464
+ }
465
+ return await coordinator.admitCreate({
466
+ service: args.job.service,
467
+ jobType: args.type,
468
+ jobId: args.job.id,
469
+ payload: args.job.payload,
470
+ context: args.event.context,
471
+ createdAt: args.event.timestamp,
472
+ policy: args.policy,
473
+ strictCreate: args.strictCreate,
474
+ });
475
+ }, _JobManager_removeQueuedKeyedReservation = async function _JobManager_removeQueuedKeyedReservation(job, policy) {
476
+ const coordinator = __classPrivateFieldGet(this, _JobManager_context, "f").keyCoordinator;
477
+ if (!coordinator)
478
+ return;
479
+ await coordinator.removeQueuedJob({
480
+ service: job.service,
481
+ jobType: job.type,
482
+ jobId: job.id,
483
+ payload: job.payload,
484
+ now: __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this).nowIso(),
485
+ policy,
486
+ });
487
+ }, _JobManager_restoreReplacedKeyedReservation = async function _JobManager_restoreReplacedKeyedReservation(job, replaced, policy) {
488
+ const coordinator = __classPrivateFieldGet(this, _JobManager_context, "f").keyCoordinator;
489
+ if (!coordinator)
490
+ return;
491
+ await coordinator.restoreReplacedQueuedJob({
492
+ service: job.service,
493
+ jobType: job.type,
494
+ replacementJobId: job.id,
495
+ replaced,
496
+ payload: job.payload,
497
+ now: __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this).nowIso(),
498
+ policy,
499
+ });
500
+ }, _JobManager_publishSkipped = async function _JobManager_publishSkipped(type, replaced, timestamp) {
501
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, type, replaced.id, {
502
+ jobId: replaced.id,
503
+ service: __classPrivateFieldGet(this, _JobManager_context, "f").jobs.namespace,
504
+ jobType: type,
505
+ eventType: "skipped",
506
+ state: "skipped",
507
+ previousState: "pending",
508
+ context: replaced.context,
509
+ tries: 0,
510
+ error: "replaced by newer keyed job",
511
+ timestamp,
512
+ });
513
+ }, _JobManager_keyedHeartbeat = function _JobManager_keyedHeartbeat(job, lease, heartbeat) {
514
+ return async () => {
515
+ await heartbeat();
516
+ const renewed = await __classPrivateFieldGet(this, _JobManager_context, "f").keyCoordinator.renewHeartbeat({
517
+ service: job.service,
518
+ jobType: job.type,
519
+ jobId: job.id,
520
+ lease,
521
+ now: __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this).nowIso(),
522
+ });
523
+ if (renewed.kind === "lost") {
524
+ recordTrellisError(new ActiveJobRuntimeError("keyed job slot lease was lost"), {
525
+ surface: "job",
526
+ direction: "worker",
527
+ operation: job.type,
528
+ phase: "heartbeat",
529
+ });
530
+ }
531
+ };
532
+ }, _JobManager_releaseKeyedSlot = async function _JobManager_releaseKeyedSlot(job, lease) {
533
+ if (!lease)
534
+ return undefined;
535
+ const released = await __classPrivateFieldGet(this, _JobManager_context, "f").keyCoordinator.releaseActiveSlot({
536
+ service: job.service,
537
+ jobType: job.type,
538
+ jobId: job.id,
539
+ lease,
540
+ now: __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this).nowIso(),
541
+ });
542
+ return released.kind === "released" ? "released" : "staleCompletion";
543
+ }, _JobManager_releaseKeyedSlotAfterPublishFailure = async function _JobManager_releaseKeyedSlotAfterPublishFailure(job, lease, publishError) {
544
+ try {
545
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_releaseKeyedSlot).call(this, job, lease);
546
+ }
547
+ catch (cleanupError) {
548
+ recordTrellisError(cleanupError, {
549
+ surface: "job",
550
+ direction: "worker",
551
+ operation: job.type,
552
+ phase: "keyed_slot_cleanup",
553
+ });
554
+ recordTrellisError(publishError, {
555
+ surface: "job",
556
+ direction: "worker",
557
+ operation: job.type,
558
+ phase: "publish",
559
+ });
560
+ }
561
+ }, _JobManager_publishStaleCompletionIgnored = async function _JobManager_publishStaleCompletionIgnored(job, tries) {
562
+ await __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_publishJobEvent).call(this, job.type, job.id, {
563
+ jobId: job.id,
564
+ service: job.service,
565
+ jobType: job.type,
566
+ eventType: "staleCompletionIgnored",
567
+ state: "stale",
568
+ previousState: "active",
569
+ context: job.context,
570
+ tries,
571
+ error: "keyed job slot lease was lost before completion",
572
+ timestamp: __classPrivateFieldGet(this, _JobManager_instances, "m", _JobManager_meta).call(this).nowIso(),
573
+ });
285
574
  };
575
+ function getKeyPolicy(binding) {
576
+ if (!binding.keyConcurrency) {
577
+ return undefined;
578
+ }
579
+ return normalizeJobKeyPolicy({
580
+ keyConcurrency: binding.keyConcurrency,
581
+ queue: binding.queue,
582
+ });
583
+ }
584
+ function startAutoHeartbeat(heartbeat, intervalMs) {
585
+ const timer = setInterval(() => {
586
+ void heartbeat().catch((error) => {
587
+ recordTrellisError(error, {
588
+ surface: "job",
589
+ direction: "worker",
590
+ phase: "heartbeat",
591
+ });
592
+ });
593
+ }, intervalMs);
594
+ return () => clearInterval(timer);
595
+ }
286
596
  function computeDeadline(now, deadlineMs) {
287
597
  if (deadlineMs === undefined) {
288
598
  return undefined;