nmtjs 0.15.0-beta.2 → 0.15.0-beta.21

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 (254) hide show
  1. package/dist/cli.d.ts +2 -0
  2. package/dist/cli.js +3 -2
  3. package/dist/cli.js.map +1 -0
  4. package/dist/config.d.ts +51 -0
  5. package/dist/config.js +1 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/entrypoints/cli.d.ts +1 -0
  8. package/dist/entrypoints/cli.js +1 -0
  9. package/dist/entrypoints/cli.js.map +1 -0
  10. package/dist/entrypoints/main.d.ts +5 -0
  11. package/dist/entrypoints/main.js +83 -15
  12. package/dist/entrypoints/main.js.map +1 -0
  13. package/dist/entrypoints/thread.d.ts +14 -0
  14. package/dist/entrypoints/thread.js +130 -24
  15. package/dist/entrypoints/thread.js.map +1 -0
  16. package/dist/entrypoints/worker.d.ts +3 -0
  17. package/dist/entrypoints/worker.js +4 -3
  18. package/dist/entrypoints/worker.js.map +1 -0
  19. package/dist/index.d.ts +69 -0
  20. package/dist/{_exports/index.js → index.js} +9 -5
  21. package/dist/index.js.map +1 -0
  22. package/dist/resolver.d.ts +2 -0
  23. package/dist/resolver.js +1 -0
  24. package/dist/resolver.js.map +1 -0
  25. package/dist/runtime/application/api/api.d.ts +49 -0
  26. package/dist/runtime/application/api/api.js +193 -0
  27. package/dist/runtime/application/api/api.js.map +1 -0
  28. package/dist/runtime/application/api/constants.d.ts +14 -0
  29. package/dist/runtime/application/api/constants.js +8 -0
  30. package/dist/runtime/application/api/constants.js.map +1 -0
  31. package/dist/runtime/application/api/filters.d.ts +14 -0
  32. package/dist/runtime/application/api/filters.js +11 -0
  33. package/dist/runtime/application/api/filters.js.map +1 -0
  34. package/dist/runtime/application/api/guards.d.ts +13 -0
  35. package/dist/runtime/application/api/guards.js +8 -0
  36. package/dist/runtime/application/api/guards.js.map +1 -0
  37. package/dist/runtime/application/api/index.d.ts +8 -0
  38. package/dist/runtime/application/api/index.js +9 -0
  39. package/dist/runtime/application/api/index.js.map +1 -0
  40. package/dist/runtime/application/api/middlewares.d.ts +14 -0
  41. package/dist/runtime/application/api/middlewares.js +12 -0
  42. package/dist/runtime/application/api/middlewares.js.map +1 -0
  43. package/dist/runtime/application/api/procedure.d.ts +67 -0
  44. package/dist/runtime/application/api/procedure.js +50 -0
  45. package/dist/runtime/application/api/procedure.js.map +1 -0
  46. package/dist/runtime/application/api/router.d.ts +71 -0
  47. package/dist/runtime/application/api/router.js +51 -0
  48. package/dist/runtime/application/api/router.js.map +1 -0
  49. package/dist/runtime/application/api/types.d.ts +32 -0
  50. package/dist/runtime/application/api/types.js +2 -0
  51. package/dist/runtime/application/api/types.js.map +1 -0
  52. package/dist/runtime/application/config.d.ts +26 -0
  53. package/dist/runtime/application/config.js +21 -0
  54. package/dist/runtime/application/config.js.map +1 -0
  55. package/dist/runtime/application/constants.d.ts +2 -0
  56. package/dist/runtime/application/constants.js +2 -0
  57. package/dist/runtime/application/constants.js.map +1 -0
  58. package/dist/runtime/application/hook.d.ts +19 -0
  59. package/dist/runtime/application/hook.js +11 -0
  60. package/dist/runtime/application/hook.js.map +1 -0
  61. package/dist/runtime/application/hooks.d.ts +3 -0
  62. package/dist/runtime/application/hooks.js +4 -0
  63. package/dist/runtime/application/hooks.js.map +1 -0
  64. package/dist/runtime/application/index.d.ts +5 -0
  65. package/dist/runtime/application/index.js +6 -0
  66. package/dist/runtime/application/index.js.map +1 -0
  67. package/dist/runtime/constants.d.ts +8 -0
  68. package/dist/runtime/constants.js +5 -0
  69. package/dist/runtime/constants.js.map +1 -0
  70. package/dist/runtime/core/hooks.d.ts +4 -0
  71. package/dist/runtime/core/hooks.js +4 -0
  72. package/dist/runtime/core/hooks.js.map +1 -0
  73. package/dist/runtime/core/plugin.d.ts +8 -0
  74. package/dist/runtime/core/plugin.js +4 -0
  75. package/dist/runtime/core/plugin.js.map +1 -0
  76. package/dist/runtime/core/runtime.d.ts +27 -0
  77. package/dist/runtime/core/runtime.js +81 -0
  78. package/dist/runtime/core/runtime.js.map +1 -0
  79. package/dist/runtime/enums.d.ts +21 -0
  80. package/dist/runtime/enums.js +26 -0
  81. package/dist/runtime/enums.js.map +1 -0
  82. package/dist/runtime/index.d.ts +21 -0
  83. package/dist/runtime/index.js +22 -0
  84. package/dist/runtime/index.js.map +1 -0
  85. package/dist/runtime/injectables.d.ts +23 -0
  86. package/dist/runtime/injectables.js +20 -0
  87. package/dist/runtime/injectables.js.map +1 -0
  88. package/dist/runtime/jobs/job.d.ts +132 -0
  89. package/dist/runtime/jobs/job.js +68 -0
  90. package/dist/runtime/jobs/job.js.map +1 -0
  91. package/dist/runtime/jobs/manager.d.ts +113 -0
  92. package/dist/runtime/jobs/manager.js +210 -0
  93. package/dist/runtime/jobs/manager.js.map +1 -0
  94. package/dist/runtime/jobs/router.d.ts +266 -0
  95. package/dist/runtime/jobs/router.js +432 -0
  96. package/dist/runtime/jobs/router.js.map +1 -0
  97. package/dist/runtime/jobs/runner.d.ts +64 -0
  98. package/dist/runtime/jobs/runner.js +256 -0
  99. package/dist/runtime/jobs/runner.js.map +1 -0
  100. package/dist/runtime/jobs/step.d.ts +23 -0
  101. package/dist/runtime/jobs/step.js +18 -0
  102. package/dist/runtime/jobs/step.js.map +1 -0
  103. package/dist/runtime/jobs/ui.d.ts +3 -0
  104. package/dist/runtime/jobs/ui.js +17 -0
  105. package/dist/runtime/jobs/ui.js.map +1 -0
  106. package/dist/runtime/pubsub/manager.d.ts +48 -0
  107. package/dist/runtime/pubsub/manager.js +119 -0
  108. package/dist/runtime/pubsub/manager.js.map +1 -0
  109. package/dist/runtime/pubsub/redis.d.ts +16 -0
  110. package/dist/runtime/pubsub/redis.js +98 -0
  111. package/dist/runtime/pubsub/redis.js.map +1 -0
  112. package/dist/runtime/scheduler/index.d.ts +22 -0
  113. package/dist/runtime/scheduler/index.js +20 -0
  114. package/dist/runtime/scheduler/index.js.map +1 -0
  115. package/dist/runtime/server/applications.d.ts +52 -0
  116. package/dist/runtime/server/applications.js +133 -0
  117. package/dist/runtime/server/applications.js.map +1 -0
  118. package/dist/runtime/server/config.d.ts +121 -0
  119. package/dist/runtime/server/config.js +33 -0
  120. package/dist/runtime/server/config.js.map +1 -0
  121. package/dist/runtime/server/jobs.d.ts +41 -0
  122. package/dist/runtime/server/jobs.js +181 -0
  123. package/dist/runtime/server/jobs.js.map +1 -0
  124. package/dist/runtime/server/pool.d.ts +54 -0
  125. package/dist/runtime/server/pool.js +194 -0
  126. package/dist/runtime/server/pool.js.map +1 -0
  127. package/dist/runtime/server/proxy.d.ts +21 -0
  128. package/dist/runtime/server/proxy.js +79 -0
  129. package/dist/runtime/server/proxy.js.map +1 -0
  130. package/dist/runtime/server/server.d.ts +53 -0
  131. package/dist/runtime/server/server.js +90 -0
  132. package/dist/runtime/server/server.js.map +1 -0
  133. package/dist/runtime/store/index.d.ts +3 -0
  134. package/dist/runtime/store/index.js +23 -0
  135. package/dist/runtime/store/index.js.map +1 -0
  136. package/dist/runtime/types.d.ts +103 -0
  137. package/dist/runtime/types.js +2 -0
  138. package/dist/runtime/types.js.map +1 -0
  139. package/dist/runtime/workers/application.d.ts +47 -0
  140. package/dist/runtime/workers/application.js +162 -0
  141. package/dist/runtime/workers/application.js.map +1 -0
  142. package/dist/runtime/workers/base.d.ts +16 -0
  143. package/dist/runtime/workers/base.js +46 -0
  144. package/dist/runtime/workers/base.js.map +1 -0
  145. package/dist/runtime/workers/cli.d.ts +1 -0
  146. package/dist/runtime/workers/cli.js +2 -0
  147. package/dist/runtime/workers/cli.js.map +1 -0
  148. package/dist/runtime/workers/job.d.ts +20 -0
  149. package/dist/runtime/workers/job.js +172 -0
  150. package/dist/runtime/workers/job.js.map +1 -0
  151. package/dist/typings.d.ts +5 -0
  152. package/dist/typings.js +4 -3
  153. package/dist/typings.js.map +1 -0
  154. package/dist/vite/builder.d.ts +5 -0
  155. package/dist/vite/builder.js +5 -1
  156. package/dist/vite/builder.js.map +1 -0
  157. package/dist/vite/config.d.ts +28 -0
  158. package/dist/vite/config.js +1 -0
  159. package/dist/vite/config.js.map +1 -0
  160. package/dist/vite/plugins.d.ts +2 -0
  161. package/dist/vite/plugins.js +1 -0
  162. package/dist/vite/plugins.js.map +1 -0
  163. package/dist/vite/runners/worker.d.ts +4 -0
  164. package/dist/vite/runners/worker.js +1 -0
  165. package/dist/vite/runners/worker.js.map +1 -0
  166. package/dist/vite/server.d.ts +3 -0
  167. package/dist/vite/server.js +6 -1
  168. package/dist/vite/server.js.map +1 -0
  169. package/dist/vite/servers/main.d.ts +8 -0
  170. package/dist/vite/servers/main.js +1 -0
  171. package/dist/vite/servers/main.js.map +1 -0
  172. package/dist/vite/servers/worker.d.ts +11 -0
  173. package/dist/vite/servers/worker.js +28 -0
  174. package/dist/vite/servers/worker.js.map +1 -0
  175. package/package.json +31 -18
  176. package/src/cli.ts +144 -0
  177. package/src/config.ts +64 -0
  178. package/src/entrypoints/cli.ts +13 -0
  179. package/src/entrypoints/main.ts +200 -0
  180. package/src/entrypoints/thread.ts +184 -0
  181. package/src/entrypoints/worker.ts +48 -0
  182. package/src/index.ts +82 -0
  183. package/src/resolver.ts +16 -0
  184. package/src/runtime/application/api/api.ts +265 -0
  185. package/src/runtime/application/api/constants.ts +22 -0
  186. package/src/runtime/application/api/filters.ts +39 -0
  187. package/src/runtime/application/api/guards.ts +29 -0
  188. package/src/runtime/application/api/index.ts +8 -0
  189. package/src/runtime/application/api/middlewares.ts +37 -0
  190. package/src/runtime/application/api/procedure.ts +229 -0
  191. package/src/runtime/application/api/router.ts +193 -0
  192. package/src/runtime/application/api/types.ts +124 -0
  193. package/src/runtime/application/config.ts +69 -0
  194. package/src/runtime/application/constants.ts +4 -0
  195. package/src/runtime/application/hook.ts +51 -0
  196. package/src/runtime/application/hooks.ts +3 -0
  197. package/src/runtime/application/index.ts +5 -0
  198. package/src/runtime/constants.ts +13 -0
  199. package/src/runtime/core/hooks.ts +5 -0
  200. package/src/runtime/core/plugin.ts +13 -0
  201. package/src/runtime/core/runtime.ts +109 -0
  202. package/src/runtime/enums.ts +24 -0
  203. package/src/runtime/index.ts +21 -0
  204. package/src/runtime/injectables.ts +61 -0
  205. package/src/runtime/jobs/job.ts +370 -0
  206. package/src/runtime/jobs/manager.ts +348 -0
  207. package/src/runtime/jobs/router.ts +896 -0
  208. package/src/runtime/jobs/runner.ts +320 -0
  209. package/src/runtime/jobs/step.ts +66 -0
  210. package/src/runtime/jobs/ui.ts +21 -0
  211. package/src/runtime/pubsub/manager.ts +211 -0
  212. package/src/runtime/pubsub/redis.ts +108 -0
  213. package/src/runtime/scheduler/index.ts +39 -0
  214. package/src/runtime/server/applications.ts +210 -0
  215. package/src/runtime/server/config.ts +158 -0
  216. package/src/runtime/server/jobs.ts +250 -0
  217. package/src/runtime/server/pool.ts +260 -0
  218. package/src/runtime/server/proxy.ts +118 -0
  219. package/src/runtime/server/server.ts +155 -0
  220. package/src/runtime/store/index.ts +30 -0
  221. package/src/runtime/types.ts +93 -0
  222. package/src/runtime/workers/application.ts +209 -0
  223. package/src/runtime/workers/base.ts +68 -0
  224. package/src/runtime/workers/cli.ts +0 -0
  225. package/src/runtime/workers/job.ts +153 -0
  226. package/src/typings.ts +30 -0
  227. package/src/vite/builder.ts +122 -0
  228. package/src/vite/config.ts +45 -0
  229. package/src/vite/plugins.ts +26 -0
  230. package/src/vite/runners/worker.ts +57 -0
  231. package/src/vite/server.ts +39 -0
  232. package/src/vite/servers/main.ts +34 -0
  233. package/src/vite/servers/worker.ts +143 -0
  234. package/dist/_exports/application.js +0 -1
  235. package/dist/_exports/common.js +0 -1
  236. package/dist/_exports/contract.js +0 -2
  237. package/dist/_exports/core.js +0 -1
  238. package/dist/_exports/gateway.js +0 -1
  239. package/dist/_exports/http-transport/bun.js +0 -1
  240. package/dist/_exports/http-transport/deno.js +0 -1
  241. package/dist/_exports/http-transport/node.js +0 -1
  242. package/dist/_exports/http-transport.js +0 -1
  243. package/dist/_exports/json-format.js +0 -1
  244. package/dist/_exports/protocol/client.js +0 -1
  245. package/dist/_exports/protocol/server.js +0 -1
  246. package/dist/_exports/protocol.js +0 -1
  247. package/dist/_exports/runtime/types.js +0 -1
  248. package/dist/_exports/runtime.js +0 -1
  249. package/dist/_exports/type.js +0 -2
  250. package/dist/_exports/ws-transport/bun.js +0 -1
  251. package/dist/_exports/ws-transport/deno.js +0 -1
  252. package/dist/_exports/ws-transport/node.js +0 -1
  253. package/dist/_exports/ws-transport.js +0 -1
  254. package/dist/command.js +0 -30
@@ -0,0 +1,348 @@
1
+ import assert from 'node:assert'
2
+ import { randomUUID } from 'node:crypto'
3
+
4
+ import type {
5
+ Job,
6
+ JobState,
7
+ JobType,
8
+ QueueEventsListener,
9
+ RedisClient,
10
+ } from 'bullmq'
11
+ import { pick } from '@nmtjs/core'
12
+ import {
13
+ Queue,
14
+ QueueEvents,
15
+ QueueEventsProducer,
16
+ UnrecoverableError,
17
+ } from 'bullmq'
18
+
19
+ import type { ServerStoreConfig } from '../server/config.ts'
20
+ import type { Store } from '../types.ts'
21
+ import type { AnyJob, JobBackoffOptions } from './job.ts'
22
+ import { createStoreClient } from '../store/index.ts'
23
+
24
+ /**
25
+ * Get the dedicated BullMQ queue name for a job
26
+ */
27
+ export function getJobQueueName(job: AnyJob): string {
28
+ return `job.${job.options.name}`
29
+ }
30
+
31
+ type QueueJobResultOptions<T extends AnyJob = AnyJob> = {
32
+ job: T
33
+ bullJob: Job<T['_']['input'], T['_']['output'], T['options']['name']>
34
+ events: QueueEvents
35
+ }
36
+
37
+ type QueueJobAddOptions = {
38
+ jobId?: string
39
+ priority?: number
40
+ forceMissingWorkers?: boolean
41
+ attempts?: number
42
+ backoff?: JobBackoffOptions
43
+ oneoff?: boolean
44
+ delay?: number
45
+ }
46
+
47
+ export class QueueJobResult<T extends AnyJob = AnyJob> {
48
+ #options: QueueJobResultOptions<T>
49
+
50
+ constructor(options: QueueJobResultOptions<T>) {
51
+ this.#options = options
52
+ }
53
+
54
+ get id() {
55
+ return this.#options.bullJob.id
56
+ }
57
+
58
+ get name() {
59
+ return this.#options.job.options.name
60
+ }
61
+
62
+ async waitResult() {
63
+ return await this.#options.bullJob.waitUntilFinished(this.#options.events)
64
+ }
65
+ }
66
+
67
+ export type JobItem<T extends AnyJob = AnyJob> = Pick<
68
+ Job<T['_']['input'], T['_']['output'], T['options']['name']>,
69
+ | 'queueName'
70
+ | 'priority'
71
+ | 'progress'
72
+ | 'name'
73
+ | 'data'
74
+ | 'returnvalue'
75
+ | 'attemptsMade'
76
+ | 'processedOn'
77
+ | 'finishedOn'
78
+ | 'failedReason'
79
+ | 'stacktrace'
80
+ > & { id: string; status: JobState | 'unknown' }
81
+
82
+ export type JobStepInfo = { label?: string; conditional: boolean }
83
+
84
+ export type JobInfo = { name: string; steps: JobStepInfo[] }
85
+
86
+ export interface JobManagerInstance {
87
+ list<T extends AnyJob>(
88
+ job: T,
89
+ options?: { page?: number; limit?: number; state?: JobState[] },
90
+ ): Promise<{
91
+ items: JobItem<T>[]
92
+ page: number
93
+ limit: number
94
+ pages: number
95
+ total: number
96
+ }>
97
+ get<T extends AnyJob>(job: T, id: string): Promise<JobItem<T> | null>
98
+ getInfo(job: AnyJob): JobInfo
99
+ add<T extends AnyJob>(
100
+ job: T,
101
+ data: T['_']['input'],
102
+ options?: QueueJobAddOptions,
103
+ ): Promise<QueueJobResult<T>>
104
+ retry(
105
+ job: AnyJob,
106
+ id: string,
107
+ options?: { clearState?: boolean },
108
+ ): Promise<void>
109
+ remove(job: AnyJob, id: string): Promise<void>
110
+ cancel(job: AnyJob, id: string): Promise<void>
111
+ }
112
+
113
+ export type CustomJobsEvents = QueueEventsListener & {
114
+ [K in `cancel:${string}`]: (args: {}, id: string) => void
115
+ }
116
+
117
+ type JobQueueEntry = {
118
+ queue: Queue
119
+ events: QueueEvents
120
+ custom: QueueEventsProducer
121
+ }
122
+
123
+ export class JobManager {
124
+ protected store!: Store
125
+ /**
126
+ * Per-job dedicated queues. Each job has its own queue for granular control.
127
+ */
128
+ protected jobQueues = new Map<string, JobQueueEntry>()
129
+
130
+ constructor(
131
+ protected storeConfig: ServerStoreConfig,
132
+ protected jobs: AnyJob[],
133
+ ) {}
134
+
135
+ get publicInstance(): JobManagerInstance {
136
+ return {
137
+ // @ts-expect-error
138
+ list: this.list.bind(this),
139
+ add: this.add.bind(this),
140
+ get: this.get.bind(this),
141
+ getInfo: this.getInfo.bind(this),
142
+ retry: this.retry.bind(this),
143
+ remove: this.remove.bind(this),
144
+ cancel: this.cancel.bind(this),
145
+ }
146
+ }
147
+
148
+ async initialize() {
149
+ this.store = await createStoreClient(this.storeConfig)
150
+ await this.store.connect()
151
+
152
+ // Create a dedicated queue for each job
153
+ for (const job of this.jobs) {
154
+ const queueName = getJobQueueName(job)
155
+ const entry: JobQueueEntry = {
156
+ queue: new Queue(queueName, { connection: this.store as RedisClient }),
157
+ events: new QueueEvents(queueName, {
158
+ connection: this.store as RedisClient,
159
+ autorun: true,
160
+ }),
161
+ custom: new QueueEventsProducer(queueName, {
162
+ connection: this.store as RedisClient,
163
+ }),
164
+ }
165
+ this.jobQueues.set(job.options.name, entry)
166
+ }
167
+
168
+ // Wait for all queues to be ready
169
+ await Promise.all(
170
+ Array.from(this.jobQueues.values()).flatMap((entry) => [
171
+ entry.queue.waitUntilReady(),
172
+ entry.events.waitUntilReady(),
173
+ entry.custom.waitUntilReady(),
174
+ ]),
175
+ )
176
+ }
177
+
178
+ async terminate() {
179
+ await Promise.allSettled(
180
+ Array.from(this.jobQueues.values()).flatMap((entry) => [
181
+ entry.queue.close(),
182
+ entry.events.close(),
183
+ entry.custom.close(),
184
+ ]),
185
+ )
186
+ this.store.disconnect(false)
187
+ }
188
+
189
+ protected getJobQueue(job: AnyJob): JobQueueEntry {
190
+ const entry = this.jobQueues.get(job.options.name)
191
+ if (!entry) {
192
+ throw new Error(`Job queue for [${job.options.name}] not found`)
193
+ }
194
+ return entry
195
+ }
196
+
197
+ getInfo(job: AnyJob): JobInfo {
198
+ return {
199
+ name: job.options.name,
200
+ steps: job.steps.map((step, index) => ({
201
+ label: step.label,
202
+ conditional: job.conditions.has(index),
203
+ })),
204
+ }
205
+ }
206
+
207
+ async list<T extends AnyJob>(
208
+ job: T,
209
+ {
210
+ limit = 20,
211
+ page = 1,
212
+ state = [],
213
+ }: { page?: number; limit?: number; state?: JobType[] },
214
+ ) {
215
+ const { queue } = this.getJobQueue(job)
216
+ const jobsCount = await queue.getJobCountByTypes(...state)
217
+ const totalPages = Math.ceil(jobsCount / limit)
218
+ if (page > totalPages) return []
219
+ const jobs = await queue.getJobs(
220
+ state,
221
+ (page - 1) * limit,
222
+ page * limit - 1,
223
+ )
224
+ const items = await Promise.all(jobs.map((job) => this._mapJob(job)))
225
+ return { items, page, limit, pages: totalPages, total: jobsCount }
226
+ }
227
+
228
+ async get<T extends AnyJob>(job: T, id: string) {
229
+ const { queue } = this.getJobQueue(job)
230
+ const bullJob = await queue.getJob(id)
231
+ if (!bullJob) return null
232
+ return await this._mapJob(bullJob)
233
+ }
234
+
235
+ async add<T extends AnyJob>(
236
+ job: T,
237
+ data: T['_']['input'],
238
+ {
239
+ forceMissingWorkers = false,
240
+ jobId = randomUUID(),
241
+ priority,
242
+ attempts = job.options.attempts,
243
+ backoff = job.options.backoff,
244
+ oneoff = job.options.oneoff ?? true,
245
+ delay,
246
+ }: QueueJobAddOptions = {},
247
+ ) {
248
+ const { queue, events } = this.getJobQueue(job)
249
+
250
+ if (!forceMissingWorkers) {
251
+ if ((await queue.getWorkersCount()) === 0) {
252
+ throw new Error(
253
+ `No workers available for [${getJobQueueName(job)}] queue`,
254
+ )
255
+ }
256
+ }
257
+ const bullJob = await queue.add(job.options.name as any, data as any, {
258
+ attempts,
259
+ backoff,
260
+ jobId,
261
+ priority,
262
+ delay,
263
+ removeOnComplete: oneoff,
264
+ removeOnFail: oneoff,
265
+ })
266
+
267
+ return new QueueJobResult({ job, bullJob, events })
268
+ }
269
+
270
+ async retry(job: AnyJob, id: string, options?: { clearState?: boolean }) {
271
+ const { queue } = this.getJobQueue(job)
272
+ const bullJob = await queue.getJob(id)
273
+ if (!bullJob) throw new Error(`Job with id [${id}] not found`)
274
+
275
+ const state = await bullJob.getState()
276
+ // For completed jobs, clear state by default so it reruns from scratch
277
+ // For failed jobs, keep state by default so it resumes from checkpoint
278
+ const shouldClearState = options?.clearState ?? state === 'completed'
279
+
280
+ if (shouldClearState) {
281
+ await bullJob.updateProgress({})
282
+ }
283
+
284
+ await bullJob.retry()
285
+ }
286
+
287
+ async remove(job: AnyJob, id: string) {
288
+ const { queue } = this.getJobQueue(job)
289
+ const bullJob = await queue.getJob(id)
290
+ if (!bullJob) throw new Error(`Job with id [${id}] not found`)
291
+ await bullJob.remove()
292
+ }
293
+
294
+ async cancel(job: AnyJob, id: string) {
295
+ const { custom, queue } = this.getJobQueue(job)
296
+ const bullJob = await queue.getJob(id)
297
+ if (!bullJob) throw new Error(`Job with id [${id}] not found`)
298
+ if (bullJob.finishedOn) return
299
+ if ((await bullJob.getState()) === 'waiting') {
300
+ return await bullJob.remove()
301
+ }
302
+ if ((await bullJob.getState()) === 'active') {
303
+ await custom.publishEvent({ eventName: `cancel:${id}` })
304
+ }
305
+ }
306
+
307
+ cancellationSignal(job: AnyJob, id: string) {
308
+ const { events } = this.getJobQueue(job)
309
+ const controller = new AbortController()
310
+ const handler = () => {
311
+ controller.abort(new UnrecoverableError('Job cancelled'))
312
+ }
313
+ events.on<CustomJobsEvents>(`cancel:${id}`, handler)
314
+ const signal = controller.signal
315
+ return Object.assign(signal, {
316
+ [Symbol.dispose]: () => {
317
+ events.off<CustomJobsEvents>(`cancel:${id}`, handler)
318
+ },
319
+ })
320
+ }
321
+
322
+ getQueue(job: AnyJob) {
323
+ return this.getJobQueue(job)
324
+ }
325
+
326
+ protected async _mapJob(bullJob: Job): Promise<JobItem> {
327
+ const status = await bullJob.getState()
328
+ const id = bullJob.id
329
+ assert(typeof id === 'string', 'Expected job id to be a string')
330
+ return {
331
+ ...pick(bullJob, {
332
+ queueName: true,
333
+ priority: true,
334
+ progress: true,
335
+ name: true,
336
+ data: true,
337
+ returnvalue: true,
338
+ attemptsMade: true,
339
+ processedOn: true,
340
+ finishedOn: true,
341
+ failedReason: true,
342
+ stacktrace: true,
343
+ }),
344
+ id,
345
+ status,
346
+ }
347
+ }
348
+ }