@shivaedev/jobs 0.30.0 → 0.31.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 (381) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +52 -19
  3. package/dist/display.d.ts +14 -0
  4. package/dist/display.d.ts.map +1 -0
  5. package/dist/display.js +2 -0
  6. package/dist/display.js.map +1 -0
  7. package/dist/server/ClientDatabase.d.ts +21 -0
  8. package/dist/server/ClientDatabase.d.ts.map +1 -0
  9. package/dist/server/ClientDatabase.js +2 -0
  10. package/dist/server/ClientDatabase.js.map +1 -0
  11. package/dist/server/PgBoss.d.ts +2 -2
  12. package/dist/server/PgBoss.d.ts.map +1 -1
  13. package/dist/server/adapters/batchClockOffset.d.ts +2 -2
  14. package/dist/server/adapters/batchClockOffset.d.ts.map +1 -1
  15. package/dist/server/adapters/batchClockOffset.js +5 -4
  16. package/dist/server/adapters/batchClockOffset.js.map +1 -1
  17. package/dist/server/adapters/batchHandler.d.ts +5 -0
  18. package/dist/server/adapters/batchHandler.d.ts.map +1 -0
  19. package/dist/server/{internal → adapters}/batchHandler.js +6 -6
  20. package/dist/server/adapters/batchHandler.js.map +1 -0
  21. package/dist/server/adapters/clientCache.d.ts +10 -0
  22. package/dist/server/adapters/clientCache.d.ts.map +1 -0
  23. package/dist/server/{internal → adapters}/clientCache.js +5 -19
  24. package/dist/server/adapters/clientCache.js.map +1 -0
  25. package/dist/server/adapters/clientErrorLogger.js +1 -1
  26. package/dist/server/adapters/clientErrorLogger.js.map +1 -1
  27. package/dist/server/adapters/defaultClientFactory.d.ts +4 -0
  28. package/dist/server/adapters/defaultClientFactory.d.ts.map +1 -0
  29. package/dist/server/adapters/defaultClientFactory.js.map +1 -0
  30. package/dist/server/adapters/deferralCount.d.ts +3 -3
  31. package/dist/server/adapters/deferralCount.d.ts.map +1 -1
  32. package/dist/server/adapters/deferralCount.js +2 -2
  33. package/dist/server/adapters/deferralCount.js.map +1 -1
  34. package/dist/server/adapters/expireAttempt.d.ts +4 -0
  35. package/dist/server/adapters/expireAttempt.d.ts.map +1 -0
  36. package/dist/server/{internal → adapters}/expireAttempt.js +1 -1
  37. package/dist/server/{internal → adapters}/expireAttempt.js.map +1 -1
  38. package/dist/server/adapters/installSchema.d.ts +1 -1
  39. package/dist/server/adapters/installSchema.d.ts.map +1 -1
  40. package/dist/server/adapters/installSchema.js +1 -1
  41. package/dist/server/adapters/installSchema.js.map +1 -1
  42. package/dist/server/adapters/jobEngine.d.ts +5 -0
  43. package/dist/server/adapters/jobEngine.d.ts.map +1 -0
  44. package/dist/server/adapters/jobEngine.js +50 -0
  45. package/dist/server/adapters/jobEngine.js.map +1 -0
  46. package/dist/server/adapters/lifecycle.d.ts +11 -0
  47. package/dist/server/adapters/lifecycle.d.ts.map +1 -0
  48. package/dist/server/adapters/lifecycle.js +48 -0
  49. package/dist/server/adapters/lifecycle.js.map +1 -0
  50. package/dist/server/adapters/listJobs.d.ts +5 -0
  51. package/dist/server/adapters/listJobs.d.ts.map +1 -0
  52. package/dist/server/adapters/listJobs.js +37 -0
  53. package/dist/server/adapters/listJobs.js.map +1 -0
  54. package/dist/server/adapters/observeTestingSettlements.d.ts +6 -0
  55. package/dist/server/adapters/observeTestingSettlements.d.ts.map +1 -0
  56. package/dist/server/adapters/observeTestingSettlements.js.map +1 -0
  57. package/dist/server/adapters/queueAdministration.d.ts +4 -0
  58. package/dist/server/adapters/queueAdministration.d.ts.map +1 -0
  59. package/dist/server/adapters/queueAdministration.js +42 -0
  60. package/dist/server/adapters/queueAdministration.js.map +1 -0
  61. package/dist/server/adapters/registerWorker.d.ts +5 -3
  62. package/dist/server/adapters/registerWorker.d.ts.map +1 -1
  63. package/dist/server/adapters/registerWorker.js +9 -6
  64. package/dist/server/adapters/registerWorker.js.map +1 -1
  65. package/dist/server/adapters/retireJobs.d.ts +3 -3
  66. package/dist/server/adapters/retireJobs.d.ts.map +1 -1
  67. package/dist/server/adapters/retireJobs.js +3 -3
  68. package/dist/server/adapters/retireJobs.js.map +1 -1
  69. package/dist/server/adapters/schemaIndexBuilds.d.ts +2 -2
  70. package/dist/server/adapters/schemaIndexBuilds.d.ts.map +1 -1
  71. package/dist/server/adapters/schemaIndexBuilds.js.map +1 -1
  72. package/dist/server/adapters/settleDeferral.d.ts +7 -0
  73. package/dist/server/adapters/settleDeferral.d.ts.map +1 -0
  74. package/dist/server/{internal → adapters}/settleDeferral.js +2 -2
  75. package/dist/server/adapters/settleDeferral.js.map +1 -0
  76. package/dist/server/adapters/testingClient.d.ts +14 -0
  77. package/dist/server/adapters/testingClient.d.ts.map +1 -0
  78. package/dist/server/{internal → adapters}/testingClient.js +12 -11
  79. package/dist/server/adapters/testingClient.js.map +1 -0
  80. package/dist/server/adapters/testingController.d.ts +34 -0
  81. package/dist/server/adapters/testingController.d.ts.map +1 -0
  82. package/dist/server/adapters/testingController.js +98 -0
  83. package/dist/server/adapters/testingController.js.map +1 -0
  84. package/dist/server/adapters/testingDueNow.d.ts +3 -3
  85. package/dist/server/adapters/testingDueNow.d.ts.map +1 -1
  86. package/dist/server/adapters/testingDueNow.js +2 -2
  87. package/dist/server/adapters/testingDueNow.js.map +1 -1
  88. package/dist/server/adapters/testingEngine.d.ts +5 -0
  89. package/dist/server/adapters/testingEngine.d.ts.map +1 -0
  90. package/dist/server/adapters/testingEngine.js +23 -0
  91. package/dist/server/adapters/testingEngine.js.map +1 -0
  92. package/dist/server/adapters/testingExpirations.d.ts +6 -4
  93. package/dist/server/adapters/testingExpirations.d.ts.map +1 -1
  94. package/dist/server/adapters/testingExpirations.js.map +1 -1
  95. package/dist/server/adapters/transactionDb.d.ts +2 -2
  96. package/dist/server/adapters/transactionDb.d.ts.map +1 -1
  97. package/dist/server/adapters/transactionDb.js.map +1 -1
  98. package/dist/server/client.d.ts +92 -18
  99. package/dist/server/client.d.ts.map +1 -1
  100. package/dist/server/clientOptions.d.ts +75 -0
  101. package/dist/server/clientOptions.d.ts.map +1 -0
  102. package/dist/server/clientOptions.js +2 -0
  103. package/dist/server/clientOptions.js.map +1 -0
  104. package/dist/server/defineSchedule.d.ts +1 -1
  105. package/dist/server/defineSchedule.d.ts.map +1 -1
  106. package/dist/server/defineSchedule.js +2 -1
  107. package/dist/server/defineSchedule.js.map +1 -1
  108. package/dist/server/definition.d.ts +17 -15
  109. package/dist/server/definition.d.ts.map +1 -1
  110. package/dist/server/definition.js +3 -1
  111. package/dist/server/definition.js.map +1 -1
  112. package/dist/server/engineClient.d.ts +26 -0
  113. package/dist/server/engineClient.d.ts.map +1 -0
  114. package/dist/server/engineClient.js +2 -0
  115. package/dist/server/engineClient.js.map +1 -0
  116. package/dist/server/enqueueOptions.d.ts +22 -0
  117. package/dist/server/enqueueOptions.d.ts.map +1 -0
  118. package/dist/server/enqueueOptions.js +2 -0
  119. package/dist/server/enqueueOptions.js.map +1 -0
  120. package/dist/server/error.d.ts +11 -1
  121. package/dist/server/error.d.ts.map +1 -1
  122. package/dist/server/error.js +8 -1
  123. package/dist/server/error.js.map +1 -1
  124. package/dist/server/health.d.ts +2 -2
  125. package/dist/server/health.d.ts.map +1 -1
  126. package/dist/server/internal/acquireClient.d.ts +11 -0
  127. package/dist/server/internal/acquireClient.d.ts.map +1 -0
  128. package/dist/server/internal/acquireClient.js +21 -0
  129. package/dist/server/internal/acquireClient.js.map +1 -0
  130. package/dist/server/internal/adapters/testingFetches.d.ts +2 -2
  131. package/dist/server/internal/adapters/testingFetches.d.ts.map +1 -1
  132. package/dist/server/internal/adapters/testingFetches.js.map +1 -1
  133. package/dist/server/internal/clientErrors.d.ts +1 -1
  134. package/dist/server/internal/clientErrors.d.ts.map +1 -1
  135. package/dist/server/internal/countsFor.d.ts +3 -3
  136. package/dist/server/internal/countsFor.d.ts.map +1 -1
  137. package/dist/server/internal/countsFor.js +2 -2
  138. package/dist/server/internal/countsFor.js.map +1 -1
  139. package/dist/server/internal/deadLetterResolutionPlan.js +1 -1
  140. package/dist/server/internal/deadLetterResolutionPlan.js.map +1 -1
  141. package/dist/server/internal/deadlineOf.d.ts +2 -2
  142. package/dist/server/internal/deadlineOf.d.ts.map +1 -1
  143. package/dist/server/internal/deadlineOf.js.map +1 -1
  144. package/dist/server/internal/deferrableAttempt.d.ts +4 -5
  145. package/dist/server/internal/deferrableAttempt.d.ts.map +1 -1
  146. package/dist/server/internal/deferrableAttempt.js +5 -14
  147. package/dist/server/internal/deferrableAttempt.js.map +1 -1
  148. package/dist/server/internal/deferral.d.ts +3 -3
  149. package/dist/server/internal/deferral.d.ts.map +1 -1
  150. package/dist/server/internal/deferral.js.map +1 -1
  151. package/dist/server/internal/deferralStorePlan.js +2 -2
  152. package/dist/server/internal/deferralStorePlan.js.map +1 -1
  153. package/dist/server/internal/definitionOptions.d.ts +7 -7
  154. package/dist/server/internal/definitionOptions.d.ts.map +1 -1
  155. package/dist/server/internal/engine.d.ts +30 -0
  156. package/dist/server/internal/engine.d.ts.map +1 -0
  157. package/dist/server/internal/engine.js +6 -0
  158. package/dist/server/internal/engine.js.map +1 -0
  159. package/dist/server/internal/enqueueFor.d.ts +2 -2
  160. package/dist/server/internal/enqueueFor.d.ts.map +1 -1
  161. package/dist/server/internal/enqueueFor.js +3 -3
  162. package/dist/server/internal/enqueueFor.js.map +1 -1
  163. package/dist/server/internal/ensureQueue.d.ts +2 -3
  164. package/dist/server/internal/ensureQueue.d.ts.map +1 -1
  165. package/dist/server/internal/ensureQueue.js +2 -2
  166. package/dist/server/internal/ensureQueue.js.map +1 -1
  167. package/dist/server/internal/healthFor.d.ts +3 -3
  168. package/dist/server/internal/healthFor.d.ts.map +1 -1
  169. package/dist/server/internal/healthFor.js +2 -2
  170. package/dist/server/internal/healthFor.js.map +1 -1
  171. package/dist/server/internal/jobControl.d.ts +9 -4
  172. package/dist/server/internal/jobControl.d.ts.map +1 -1
  173. package/dist/server/internal/jobControl.js +13 -40
  174. package/dist/server/internal/jobControl.js.map +1 -1
  175. package/dist/server/internal/jobListings.d.ts +16 -0
  176. package/dist/server/internal/jobListings.d.ts.map +1 -0
  177. package/dist/server/internal/jobListings.js +52 -0
  178. package/dist/server/internal/jobListings.js.map +1 -0
  179. package/dist/server/internal/jobStorePlans.js +2 -2
  180. package/dist/server/internal/jobStorePlans.js.map +1 -1
  181. package/dist/server/internal/lifecycle.d.ts +11 -7
  182. package/dist/server/internal/lifecycle.d.ts.map +1 -1
  183. package/dist/server/internal/lifecycle.js +2 -49
  184. package/dist/server/internal/lifecycle.js.map +1 -1
  185. package/dist/server/internal/makeService.d.ts +5 -3
  186. package/dist/server/internal/makeService.d.ts.map +1 -1
  187. package/dist/server/internal/makeService.js +15 -11
  188. package/dist/server/internal/makeService.js.map +1 -1
  189. package/dist/server/internal/register.d.ts +5 -5
  190. package/dist/server/internal/register.d.ts.map +1 -1
  191. package/dist/server/internal/register.js +6 -6
  192. package/dist/server/internal/register.js.map +1 -1
  193. package/dist/server/internal/registerReleasedJobs.d.ts +4 -4
  194. package/dist/server/internal/registerReleasedJobs.d.ts.map +1 -1
  195. package/dist/server/internal/registerReleasedJobs.js +2 -2
  196. package/dist/server/internal/registerReleasedJobs.js.map +1 -1
  197. package/dist/server/internal/retryWake.d.ts +1 -1
  198. package/dist/server/internal/retryWake.d.ts.map +1 -1
  199. package/dist/server/internal/retryWake.js +2 -2
  200. package/dist/server/internal/retryWake.js.map +1 -1
  201. package/dist/server/internal/runQueueWorker.d.ts +4 -4
  202. package/dist/server/internal/runQueueWorker.d.ts.map +1 -1
  203. package/dist/server/internal/runQueueWorker.js +5 -5
  204. package/dist/server/internal/runQueueWorker.js.map +1 -1
  205. package/dist/server/internal/storedRows.d.ts +2 -2
  206. package/dist/server/internal/storedRows.d.ts.map +1 -1
  207. package/dist/server/internal/storedRows.js +2 -2
  208. package/dist/server/internal/storedRows.js.map +1 -1
  209. package/dist/server/internal/testingDeferrals.d.ts +3 -3
  210. package/dist/server/internal/testingDeferrals.d.ts.map +1 -1
  211. package/dist/server/internal/testingDeferrals.js +2 -2
  212. package/dist/server/internal/testingDeferrals.js.map +1 -1
  213. package/dist/server/internal/testingIdle.d.ts +3 -3
  214. package/dist/server/internal/testingIdle.d.ts.map +1 -1
  215. package/dist/server/internal/testingIdle.js +2 -2
  216. package/dist/server/internal/testingIdle.js.map +1 -1
  217. package/dist/server/internal/testingReadout.d.ts +7 -41
  218. package/dist/server/internal/testingReadout.d.ts.map +1 -1
  219. package/dist/server/internal/testingReadout.js +2 -2
  220. package/dist/server/internal/testingReadout.js.map +1 -1
  221. package/dist/server/internal/testingRegistrations.d.ts +1 -1
  222. package/dist/server/internal/testingRegistrations.d.ts.map +1 -1
  223. package/dist/server/internal/testingSchedules.d.ts +3 -3
  224. package/dist/server/internal/testingSchedules.d.ts.map +1 -1
  225. package/dist/server/internal/testingSchedules.js +1 -1
  226. package/dist/server/internal/testingSchedules.js.map +1 -1
  227. package/dist/server/internal/testingSnapshot.d.ts +4 -4
  228. package/dist/server/internal/testingSnapshot.d.ts.map +1 -1
  229. package/dist/server/internal/testingSnapshot.js +2 -2
  230. package/dist/server/internal/testingSnapshot.js.map +1 -1
  231. package/dist/server/internal/testingWaits.d.ts +8 -7
  232. package/dist/server/internal/testingWaits.d.ts.map +1 -1
  233. package/dist/server/internal/testingWaits.js +3 -3
  234. package/dist/server/internal/testingWaits.js.map +1 -1
  235. package/dist/server/internal/tracing.d.ts +2 -2
  236. package/dist/server/internal/tracing.d.ts.map +1 -1
  237. package/dist/server/internal/tracing.js.map +1 -1
  238. package/dist/server/internal/validateQueueNames.d.ts +2 -2
  239. package/dist/server/internal/validateQueueNames.d.ts.map +1 -1
  240. package/dist/server/internal/validateQueueNames.js +1 -1
  241. package/dist/server/internal/validateQueueNames.js.map +1 -1
  242. package/dist/server/internal/waitForBatchExpiry.d.ts +4 -4
  243. package/dist/server/internal/waitForBatchExpiry.d.ts.map +1 -1
  244. package/dist/server/internal/waitForBatchExpiry.js +1 -1
  245. package/dist/server/internal/waitForBatchExpiry.js.map +1 -1
  246. package/dist/server/job.d.ts +42 -0
  247. package/dist/server/job.d.ts.map +1 -0
  248. package/dist/server/job.js +2 -0
  249. package/dist/server/job.js.map +1 -0
  250. package/dist/server/jobModule.d.ts +6 -4
  251. package/dist/server/jobModule.d.ts.map +1 -1
  252. package/dist/server/jobModule.js +7 -5
  253. package/dist/server/jobModule.js.map +1 -1
  254. package/dist/server/queueOptions.d.ts +19 -0
  255. package/dist/server/queueOptions.d.ts.map +1 -0
  256. package/dist/server/queueOptions.js +2 -0
  257. package/dist/server/queueOptions.js.map +1 -0
  258. package/dist/server/readJobFailure.d.ts +5 -0
  259. package/dist/server/readJobFailure.d.ts.map +1 -0
  260. package/dist/server/readJobFailure.js +8 -0
  261. package/dist/server/readJobFailure.js.map +1 -0
  262. package/dist/server/schema.d.ts +1 -1
  263. package/dist/server/schema.d.ts.map +1 -1
  264. package/dist/server/schema.js +18 -7
  265. package/dist/server/schema.js.map +1 -1
  266. package/dist/server/service.d.ts +15 -10
  267. package/dist/server/service.d.ts.map +1 -1
  268. package/dist/server/service.js +18 -27
  269. package/dist/server/service.js.map +1 -1
  270. package/dist/server/testing.d.ts +30 -69
  271. package/dist/server/testing.d.ts.map +1 -1
  272. package/dist/server/testing.js +5 -97
  273. package/dist/server/testing.js.map +1 -1
  274. package/dist/server/workerOptions.d.ts +25 -0
  275. package/dist/server/workerOptions.d.ts.map +1 -0
  276. package/dist/server/workerOptions.js +2 -0
  277. package/dist/server/workerOptions.js.map +1 -0
  278. package/package.json +11 -16
  279. package/src/display.ts +12 -0
  280. package/src/server/ClientDatabase.ts +7 -0
  281. package/src/server/PgBoss.ts +2 -2
  282. package/src/server/adapters/batchClockOffset.ts +8 -5
  283. package/src/server/{internal → adapters}/batchHandler.ts +13 -13
  284. package/src/server/{internal → adapters}/clientCache.ts +10 -22
  285. package/src/server/adapters/clientErrorLogger.ts +1 -1
  286. package/src/server/{defaultClientFactory.ts → adapters/defaultClientFactory.ts} +4 -2
  287. package/src/server/adapters/deferralCount.ts +5 -5
  288. package/src/server/{internal → adapters}/expireAttempt.ts +4 -3
  289. package/src/server/adapters/installSchema.ts +2 -2
  290. package/src/server/adapters/jobEngine.ts +59 -0
  291. package/src/server/adapters/lifecycle.ts +67 -0
  292. package/src/server/adapters/listJobs.ts +43 -0
  293. package/src/server/{internal → adapters}/observeTestingSettlements.ts +2 -2
  294. package/src/server/adapters/queueAdministration.ts +47 -0
  295. package/src/server/adapters/registerWorker.ts +17 -12
  296. package/src/server/adapters/retireJobs.ts +5 -5
  297. package/src/server/adapters/schemaIndexBuilds.ts +2 -2
  298. package/src/server/{internal → adapters}/settleDeferral.ts +5 -5
  299. package/src/server/{internal → adapters}/testingClient.ts +31 -26
  300. package/src/server/adapters/testingController.ts +109 -0
  301. package/src/server/adapters/testingDueNow.ts +5 -5
  302. package/src/server/adapters/testingEngine.ts +28 -0
  303. package/src/server/adapters/testingExpirations.ts +6 -4
  304. package/src/server/adapters/transactionDb.ts +2 -2
  305. package/src/server/client.ts +83 -30
  306. package/src/server/clientOptions.ts +81 -0
  307. package/src/server/defineSchedule.ts +3 -2
  308. package/src/server/definition.ts +20 -17
  309. package/src/server/engineClient.ts +24 -0
  310. package/src/server/enqueueOptions.ts +20 -0
  311. package/src/server/error.ts +17 -2
  312. package/src/server/health.ts +2 -2
  313. package/src/server/internal/acquireClient.ts +26 -0
  314. package/src/server/internal/adapters/testingFetches.ts +2 -2
  315. package/src/server/internal/clientErrors.ts +1 -1
  316. package/src/server/internal/countsFor.ts +5 -5
  317. package/src/server/internal/deadLetterResolutionPlan.ts +1 -1
  318. package/src/server/internal/deadlineOf.ts +2 -2
  319. package/src/server/internal/deferrableAttempt.ts +5 -22
  320. package/src/server/internal/deferral.ts +3 -3
  321. package/src/server/internal/deferralStorePlan.ts +2 -2
  322. package/src/server/internal/definitionOptions.ts +1 -1
  323. package/src/server/internal/engine.ts +41 -0
  324. package/src/server/internal/enqueueFor.ts +5 -5
  325. package/src/server/internal/ensureQueue.ts +5 -6
  326. package/src/server/internal/healthFor.ts +4 -4
  327. package/src/server/internal/jobControl.ts +15 -50
  328. package/src/server/internal/jobListings.ts +85 -0
  329. package/src/server/internal/jobStorePlans.ts +2 -2
  330. package/src/server/internal/lifecycle.ts +14 -55
  331. package/src/server/internal/makeService.ts +21 -13
  332. package/src/server/internal/register.ts +9 -9
  333. package/src/server/internal/registerReleasedJobs.ts +5 -5
  334. package/src/server/internal/retryWake.ts +3 -3
  335. package/src/server/internal/runQueueWorker.ts +8 -8
  336. package/src/server/internal/storedRows.ts +3 -3
  337. package/src/server/internal/testingDeferrals.ts +5 -5
  338. package/src/server/internal/testingIdle.ts +5 -5
  339. package/src/server/internal/testingReadout.ts +12 -6
  340. package/src/server/internal/testingRegistrations.ts +1 -1
  341. package/src/server/internal/testingSchedules.ts +4 -4
  342. package/src/server/internal/testingSnapshot.ts +6 -6
  343. package/src/server/internal/testingWaits.ts +11 -10
  344. package/src/server/internal/tracing.ts +2 -2
  345. package/src/server/internal/validateQueueNames.ts +2 -2
  346. package/src/server/internal/waitForBatchExpiry.ts +4 -4
  347. package/src/server/job.ts +42 -0
  348. package/src/server/jobModule.ts +19 -7
  349. package/src/server/queueOptions.ts +20 -0
  350. package/src/server/readJobFailure.ts +12 -0
  351. package/src/server/schema.ts +18 -7
  352. package/src/server/service.ts +40 -44
  353. package/src/server/testing.ts +7 -109
  354. package/src/server/workerOptions.ts +28 -0
  355. package/dist/server/defaultClientFactory.d.ts +0 -3
  356. package/dist/server/defaultClientFactory.d.ts.map +0 -1
  357. package/dist/server/defaultClientFactory.js.map +0 -1
  358. package/dist/server/internal/batchHandler.d.ts +0 -5
  359. package/dist/server/internal/batchHandler.d.ts.map +0 -1
  360. package/dist/server/internal/batchHandler.js.map +0 -1
  361. package/dist/server/internal/clientCache.d.ts +0 -8
  362. package/dist/server/internal/clientCache.d.ts.map +0 -1
  363. package/dist/server/internal/clientCache.js.map +0 -1
  364. package/dist/server/internal/expireAttempt.d.ts +0 -3
  365. package/dist/server/internal/expireAttempt.d.ts.map +0 -1
  366. package/dist/server/internal/listJobs.d.ts +0 -5
  367. package/dist/server/internal/listJobs.d.ts.map +0 -1
  368. package/dist/server/internal/listJobs.js +0 -75
  369. package/dist/server/internal/listJobs.js.map +0 -1
  370. package/dist/server/internal/observeTestingSettlements.d.ts +0 -6
  371. package/dist/server/internal/observeTestingSettlements.d.ts.map +0 -1
  372. package/dist/server/internal/observeTestingSettlements.js.map +0 -1
  373. package/dist/server/internal/settleDeferral.d.ts +0 -7
  374. package/dist/server/internal/settleDeferral.d.ts.map +0 -1
  375. package/dist/server/internal/settleDeferral.js.map +0 -1
  376. package/dist/server/internal/testingClient.d.ts +0 -13
  377. package/dist/server/internal/testingClient.d.ts.map +0 -1
  378. package/dist/server/internal/testingClient.js.map +0 -1
  379. package/src/server/internal/listJobs.ts +0 -116
  380. /package/dist/server/{defaultClientFactory.js → adapters/defaultClientFactory.js} +0 -0
  381. /package/dist/server/{internal → adapters}/observeTestingSettlements.js +0 -0
@@ -1,18 +1,16 @@
1
1
  import { Clock, Duration, Effect, Schema } from "effect";
2
- import type { Job, policies, Queue, ScheduleOptions, WorkOptions } from "pg-boss";
3
- import { maxDeferrals, nativeQueueOptions } from "#internal/definitionOptions.ts";
2
+ import type { QueueDisplay, SubjectColumn } from "#display.ts";
3
+ import type { ScheduleOptions } from "#server/enqueueOptions.ts";
4
+ import { maxDeferrals, nativeQueueOptions } from "#server/internal/definitionOptions.ts";
5
+ import type { WorkerJob } from "#server/job.ts";
6
+ import type { QueueOptions, QueuePolicy } from "#server/queueOptions.ts";
7
+ import type { WorkerOptions } from "#server/workerOptions.ts";
4
8
 
5
9
  export class RetryAt extends Schema.TaggedError<RetryAt>()("RetryAt", {
6
10
  at: Schema.DateTimeUtc,
7
11
  reason: Schema.String,
8
12
  }) {}
9
13
 
10
- export type QueuePolicy = (typeof policies)[keyof typeof policies];
11
- export type QueueOptions = Omit<Queue, "name" | "deadLetter" | "policy"> & {
12
- readonly maxDeferrals?: number;
13
- readonly policy?: QueuePolicy;
14
- };
15
-
16
14
  export interface JobPayloadSchema extends Schema.Top {
17
15
  readonly Encoded: object;
18
16
  readonly Type: object;
@@ -29,7 +27,7 @@ export interface JobContext {
29
27
  readonly signal: AbortSignal;
30
28
  }
31
29
 
32
- export interface QueueDefinition<TName extends string = string, TPayload extends JobPayloadSchema = JobPayloadSchema> {
30
+ export interface QueueDefinition<TName extends string = string, TPayload extends JobPayloadSchema = JobPayloadSchema> extends QueueDisplay {
33
31
  readonly _tag: "QueueDefinition";
34
32
  readonly handle: <E, R>(
35
33
  handler: (payload: Schema.Schema.Type<TPayload>, job: JobContext) => Effect.Effect<unknown, E, R>,
@@ -37,9 +35,9 @@ export interface QueueDefinition<TName extends string = string, TPayload extends
37
35
  readonly key?: ((payload: Schema.Schema.Type<TPayload>) => string) | undefined;
38
36
  readonly maxDeferrals: number;
39
37
  readonly name: TName;
40
- readonly queueOptions: Omit<Queue, "name" | "deadLetter">;
38
+ readonly queueOptions: Omit<QueueOptions, "maxDeferrals">;
41
39
  readonly schema: TPayload;
42
- readonly workerOptions: WorkOptions;
40
+ readonly workerOptions: WorkerOptions;
43
41
  }
44
42
 
45
43
  export interface QueueWorker<TPayload extends JobPayloadSchema = JobPayloadSchema, TRequirements = unknown> {
@@ -53,15 +51,15 @@ export type JobRegistration<TRequirements = unknown> =
53
51
  | QueueWorker<JobPayloadSchema & { readonly DecodingServices: TRequirements }, TRequirements>
54
52
  | ScheduledWorker<TRequirements>;
55
53
 
56
- export interface ScheduleDefinition<TName extends string = string> {
54
+ export interface ScheduleDefinition<TName extends string = string> extends QueueDisplay {
57
55
  readonly _tag: "ScheduleDefinition";
58
56
  readonly cron: string;
59
57
  readonly maxDeferrals: number;
60
58
  readonly name: TName;
61
- readonly queueOptions: Omit<Queue, "name" | "deadLetter">;
59
+ readonly queueOptions: Omit<QueueOptions, "maxDeferrals">;
62
60
  readonly run: <E, R>(effect: Effect.Effect<unknown, E, R>) => ScheduledWorker<R>;
63
61
  readonly scheduleOptions: ScheduleOptions;
64
- readonly workerOptions: WorkOptions;
62
+ readonly workerOptions: WorkerOptions;
65
63
  }
66
64
 
67
65
  export interface ScheduledWorker<TRequirements = unknown> {
@@ -79,9 +77,11 @@ export type RegistrationRequirements<TRegistrations extends readonly JobRegistra
79
77
  : never;
80
78
 
81
79
  export type DefineQueueOptions<TName extends string, TPayload extends JobPayloadSchema> = {
80
+ readonly label?: string;
82
81
  readonly name: TName;
83
82
  readonly schema: TPayload;
84
- readonly worker?: WorkOptions;
83
+ readonly subject?: readonly SubjectColumn<NoInfer<TPayload>>[];
84
+ readonly worker?: WorkerOptions;
85
85
  } & (
86
86
  | { readonly key: (payload: Schema.Schema.Type<TPayload>) => string; readonly queue: QueueOptions & { readonly policy: "singleton" } }
87
87
  | { readonly key?: never; readonly queue?: QueueOptions & { readonly policy?: Exclude<QueuePolicy, "singleton"> } }
@@ -102,6 +102,8 @@ export function defineQueue<const TName extends string, const TPayload extends J
102
102
  const definition: QueueDefinition<TName, TPayload> = {
103
103
  _tag: "QueueDefinition",
104
104
  ...(options.key === undefined ? {} : { key: options.key }),
105
+ ...(options.label === undefined ? {} : { label: options.label }),
106
+ ...(options.subject === undefined ? {} : { subject: Object.freeze(options.subject.map((column) => Object.freeze({ ...column }))) }),
105
107
  handle: (handler) =>
106
108
  Object.freeze({
107
109
  _tag: "QueueWorker" as const,
@@ -119,13 +121,14 @@ export function defineQueue<const TName extends string, const TPayload extends J
119
121
 
120
122
  export interface DefineScheduleOptions<TName extends string> {
121
123
  readonly cron: string;
124
+ readonly label?: string;
122
125
  readonly name: TName;
123
126
  readonly queue?: QueueOptions;
124
127
  readonly schedule?: ScheduleOptions;
125
- readonly worker?: WorkOptions;
128
+ readonly worker?: WorkerOptions;
126
129
  }
127
130
 
128
- export function jobContext(job: Job<unknown>, deadline: number, deferralCount = 0): JobContext {
131
+ export function jobContext(job: WorkerJob<unknown>, deadline: number, deferralCount = 0): JobContext {
129
132
  return {
130
133
  deferralCount,
131
134
  expireInSeconds: job.expireInSeconds,
@@ -0,0 +1,24 @@
1
+ import type { ClientDatabase } from "#server/ClientDatabase.ts";
2
+ import type { JobReadOptions, PgBossClient } from "#server/client.ts";
3
+ import type { ScheduleOptions } from "#server/enqueueOptions.ts";
4
+ import type { Job } from "#server/job.ts";
5
+
6
+ export interface EngineSchedule {
7
+ cron: string;
8
+ data?: object;
9
+ key: string;
10
+ name: string;
11
+ options?: ScheduleOptions;
12
+ timezone: string;
13
+ }
14
+
15
+ export interface EngineClient extends Required<PgBossClient> {
16
+ readonly emit: (event: "error", error: Error) => boolean;
17
+ readonly findJobs: <T = unknown>(name: string, options?: JobReadOptions) => Promise<Job<T>[]>;
18
+ readonly getDb: () => ClientDatabase;
19
+ readonly getJobById: <T = unknown>(name: string, id: string) => Promise<Job<T> | null>;
20
+ readonly getSchedules: (name?: string, key?: string) => Promise<EngineSchedule[]>;
21
+ readonly getSpy: (name: string) => { clear: () => void; waitForJob: (selector: () => boolean, state: "completed" | "failed") => Promise<unknown> };
22
+ readonly schemaVersion: () => Promise<number | null>;
23
+ readonly supervise: (name?: string) => Promise<void>;
24
+ }
@@ -0,0 +1,20 @@
1
+ import type { ClientDatabase } from "#server/ClientDatabase.ts";
2
+ import type { RetryOptions } from "#server/queueOptions.ts";
3
+
4
+ export interface EnqueueOptions extends RetryOptions {
5
+ readonly db?: ClientDatabase;
6
+ readonly deadLetter?: string;
7
+ readonly group?: { readonly id: string; readonly tier?: string };
8
+ readonly id?: string;
9
+ readonly priority?: number;
10
+ readonly singletonKey?: string;
11
+ readonly singletonNextSlot?: boolean;
12
+ readonly singletonSeconds?: number;
13
+ readonly startAfter?: number | string | Date;
14
+ }
15
+
16
+ export interface ScheduleOptions extends EnqueueOptions {
17
+ readonly key?: string;
18
+ readonly missed?: "skip" | "once";
19
+ readonly tz?: string;
20
+ }
@@ -1,19 +1,34 @@
1
1
  import { Cause, Data, Duration, Redacted } from "effect";
2
- import { failureOutput } from "#internal/failureOutput.ts";
2
+ import { failureOutput } from "#server/internal/failureOutput.ts";
3
3
 
4
4
  export type PgBossOperation =
5
5
  | "counts"
6
6
  | "deadLetteredJobs"
7
+ | "deleteQueue"
7
8
  | "enqueue"
8
9
  | "failedJobs"
9
10
  | "getJob"
10
11
  | "health"
11
12
  | "install"
12
13
  | "register"
14
+ | "refreshQueueStats"
13
15
  | "retry"
14
16
  | "settle"
15
17
  | "start"
16
- | "stop";
18
+ | "stop"
19
+ | "unschedule";
20
+
21
+ export class PgBossNotFoundError extends Data.TaggedError("PgBossNotFoundError")<{
22
+ readonly operation: "deleteQueue" | "unschedule";
23
+ readonly queue: string;
24
+ readonly key?: string;
25
+ }> {
26
+ override get message(): string {
27
+ return this.operation === "deleteQueue"
28
+ ? `Queue ${this.queue} does not exist`
29
+ : `Schedule ${this.queue} with key ${JSON.stringify(this.key ?? "")} does not exist`;
30
+ }
31
+ }
17
32
 
18
33
  export class PgBossError extends Data.TaggedError("PgBossError")<{
19
34
  readonly operation: PgBossOperation;
@@ -1,6 +1,6 @@
1
1
  import type { DateTime, Option } from "effect";
2
- import type { JobWithMetadata } from "pg-boss";
3
2
  import type { JobFailure } from "#JobFailure.ts";
3
+ import type { JobState } from "#server/job.ts";
4
4
 
5
5
  export interface QueueCounts {
6
6
  readonly activeCount: number;
@@ -42,7 +42,7 @@ export interface ListedJob<TData> {
42
42
  readonly retryCount: number;
43
43
  readonly retryLimit: number;
44
44
  readonly startedOn: Option.Option<DateTime.Utc>;
45
- readonly state: JobWithMetadata["state"];
45
+ readonly state: JobState;
46
46
  }
47
47
 
48
48
  export interface DeadLetteredJob<TData> extends ListedJob<TData> {
@@ -0,0 +1,26 @@
1
+ import { Effect, Redacted } from "effect";
2
+ import { clientErrorLogger } from "#server/adapters/clientErrorLogger.ts";
3
+ import type { PgBossOptions } from "#server/service.ts";
4
+ import { ClientEngine } from "./lifecycle.ts";
5
+
6
+ export const acquireClient = Effect.fnUntraced(function* (options: PgBossOptions) {
7
+ const { connectionString, clientFactory, clientCacheKey, stop, ...settings } = options;
8
+ const constructorOptions = {
9
+ ...settings,
10
+ idleTimeoutMillis: settings.idleTimeoutMillis ?? 60_000,
11
+ maxLifetimeSeconds: settings.maxLifetimeSeconds ?? 600,
12
+ ...(connectionString === undefined ? {} : { connectionString: Redacted.value(connectionString) }),
13
+ };
14
+ const report = yield* clientErrorLogger();
15
+ const engine = yield* ClientEngine;
16
+ const acquired = yield* engine.acquire(
17
+ {
18
+ clientCacheKey,
19
+ clientFactory,
20
+ constructor: constructorOptions,
21
+ },
22
+ report,
23
+ stop,
24
+ );
25
+ return { ...acquired, schema: settings.schema, stop };
26
+ });
@@ -1,4 +1,4 @@
1
- import type { PgBoss } from "pg-boss";
1
+ import type { EngineClient } from "#server/engineClient.ts";
2
2
 
3
3
  // pg-boss offers no hook for a worker fetch that finds nothing, so the controller recognizes its claim statement on the client's database.
4
4
  const claim = /UPDATE\s+\S+\s+j\s+SET\s+state\s*=\s*'active'/u;
@@ -9,7 +9,7 @@ export interface TestingFetches {
9
9
  readonly passedSince: (queue: string, begun: number) => number;
10
10
  }
11
11
 
12
- export function testingFetches(db: ReturnType<PgBoss["getDb"]>, changed: () => void): TestingFetches {
12
+ export function testingFetches(db: ReturnType<EngineClient["getDb"]>, changed: () => void): TestingFetches {
13
13
  const begun = new Map<string, number>();
14
14
  const passed = new Map<string, number[]>();
15
15
  const executeSql = db.executeSql.bind(db);
@@ -1,6 +1,6 @@
1
1
  import { Effect } from "effect";
2
2
  import { isSensitiveKey, redactText } from "@shivaedev/errors/sensitive.ts";
3
- import type { PgBossClient } from "#client.ts";
3
+ import type { PgBossClient } from "#server/client.ts";
4
4
 
5
5
  type Listener = (error: Error) => void;
6
6
 
@@ -1,8 +1,8 @@
1
1
  import { Effect, Schema } from "effect";
2
- import type { PgBossClient } from "#client.ts";
3
- import { toPgBossError } from "#error.ts";
4
- import type { QueueCounts } from "#health.ts";
5
- import { quotedSchema } from "#internal/storedRows.ts";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import { toPgBossError } from "#server/error.ts";
4
+ import type { QueueCounts } from "#server/health.ts";
5
+ import { quotedSchema } from "#server/internal/storedRows.ts";
6
6
 
7
7
  const Counts = Schema.Struct({
8
8
  activeCount: Schema.Number,
@@ -11,7 +11,7 @@ const Counts = Schema.Struct({
11
11
  totalCount: Schema.Number,
12
12
  });
13
13
 
14
- export function countsFor(client: PgBossClient, schema: string, name: string): Effect.Effect<QueueCounts, import("#error.ts").PgBossError> {
14
+ export function countsFor(client: PgBossClient, schema: string, name: string): Effect.Effect<QueueCounts, import("#server/error.ts").PgBossError> {
15
15
  return Effect.tryPromise({
16
16
  catch: (error) => toPgBossError("counts", error, name),
17
17
  try: async () => {
@@ -1,4 +1,4 @@
1
- import { quotedSchema } from "#internal/storedRows.ts";
1
+ import { quotedSchema } from "#server/internal/storedRows.ts";
2
2
 
3
3
  export function deadLetterResolutionPlan(schema: string): string {
4
4
  const quoted = quotedSchema(schema);
@@ -1,6 +1,6 @@
1
- import type { Job } from "pg-boss";
1
+ import type { WorkerJob } from "#server/job.ts";
2
2
 
3
- export function deadlineOf(job: Job<unknown>): number {
3
+ export function deadlineOf(job: WorkerJob<unknown>): number {
4
4
  if (!("startedOn" in job && job.startedOn instanceof Date && Number.isFinite(job.startedOn.getTime()))) {
5
5
  throw new TypeError("Worker jobs must include pg-boss startedOn metadata");
6
6
  }
@@ -1,42 +1,25 @@
1
1
  import { Clock, DateTime, Effect, Schema } from "effect";
2
- import type { Job } from "pg-boss";
3
- import type { PgBossClient } from "#client.ts";
4
- import { RetryAt } from "#definition.ts";
5
- import { toPgBossError } from "#error.ts";
6
- import { deferralObservers, deferredAttempt } from "#internal/deferral.ts";
7
- import { settleDeferral } from "#internal/settleDeferral.ts";
2
+ import { RetryAt } from "#server/definition.ts";
3
+ import { deferredAttempt } from "#server/internal/deferral.ts";
4
+ import { type JobAttempt, JobEngine } from "#server/internal/engine.ts";
8
5
 
9
6
  const recordDeferral = Effect.fnUntraced(function* (at: string, reason: string) {
10
7
  const span = yield* Effect.currentSpan.pipe(Effect.orDie);
11
8
  span.event("job.deferred", yield* Clock.currentTimeNanos, { at, reason });
12
9
  });
13
10
 
14
- export function deferrableAttempt<A, E, R>(
15
- effect: Effect.Effect<A, E, R>,
16
- client: PgBossClient,
17
- schema: string,
18
- job: Job<unknown>,
19
- maxDeferrals: number,
20
- ) {
11
+ export function deferrableAttempt<A, E, R>(effect: Effect.Effect<A, E, R>, job: JobAttempt, maxDeferrals: number) {
21
12
  return effect.pipe(
22
13
  Effect.catchIf(Schema.is(RetryAt), (error) => {
23
14
  if (maxDeferrals === 0) {
24
15
  return Effect.fail(error);
25
16
  }
26
17
  const at = DateTime.formatIso(error.at);
27
- return Effect.tryPromise({
28
- catch: (failure) => toPgBossError("settle", failure, job.name),
29
- try: () => settleDeferral(client, schema, job, at, error.reason, maxDeferrals),
30
- }).pipe(
18
+ return Effect.flatMap(JobEngine, (engine) => engine.settleDeferral(job, at, error.reason, maxDeferrals)).pipe(
31
19
  Effect.flatMap((settled) => {
32
20
  if (settled.claimed && !settled.deferred) {
33
21
  return Effect.fail(error);
34
22
  }
35
- // Native batch settlement must not match a sibling's new claim at the unchanged retry count.
36
- job.retryCount = Number.MAX_SAFE_INTEGER;
37
- if (settled.deferred) {
38
- deferralObservers.get(client)?.();
39
- }
40
23
  return (settled.deferred ? recordDeferral(at, error.reason) : Effect.void).pipe(Effect.as(deferredAttempt));
41
24
  }),
42
25
  );
@@ -1,6 +1,6 @@
1
1
  import { Schema } from "effect";
2
- import type { Job } from "pg-boss";
3
- import type { PgBossClient } from "#client.ts";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import type { WorkerJob } from "#server/job.ts";
4
4
 
5
5
  export const deferredAttempt = Symbol("deferredAttempt");
6
6
  export const deferralObservers = new WeakMap<PgBossClient, () => void>();
@@ -13,7 +13,7 @@ export const Deferral = Schema.Struct({
13
13
 
14
14
  const Output = Schema.Struct({ jobDeferral: Deferral });
15
15
 
16
- export function deferralOf(job: Job<unknown>) {
16
+ export function deferralOf(job: WorkerJob<unknown>) {
17
17
  const output: unknown = Reflect.get(job, "output");
18
18
  return Schema.is(Output)(output) ? output.jobDeferral : undefined;
19
19
  }
@@ -1,5 +1,5 @@
1
- import { STATELY_DEFERRAL_POLICY } from "#internal/deferral.ts";
2
- import { quotedSchema } from "#internal/storedRows.ts";
1
+ import { STATELY_DEFERRAL_POLICY } from "#server/internal/deferral.ts";
2
+ import { quotedSchema } from "#server/internal/storedRows.ts";
3
3
 
4
4
  export function deferralStorePlan(schema: string): string {
5
5
  const quoted = quotedSchema(schema);
@@ -1,4 +1,4 @@
1
- import type { QueueOptions } from "#definition.ts";
1
+ import type { QueueOptions } from "#server/queueOptions.ts";
2
2
 
3
3
  export function maxDeferrals(options: QueueOptions | undefined): number {
4
4
  const limit = options?.maxDeferrals ?? 10;
@@ -0,0 +1,41 @@
1
+ import { Context, type Effect } from "effect";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import type { PgBossError, PgBossTestingError } from "#server/error.ts";
4
+ import type { PgBossService } from "#server/service.ts";
5
+
6
+ export type StoredJob = Awaited<ReturnType<NonNullable<PgBossClient["findJobs"]>>>[number];
7
+ export type JobAttempt = Pick<StoredJob, "name" | "id" | "retryCount">;
8
+ export type Listing = "deadLetteredJobs" | "failedJobs";
9
+
10
+ export class JobEngine extends Context.Service<
11
+ JobEngine,
12
+ Pick<PgBossService, "deleteQueue" | "refreshQueueStats" | "unschedule"> & {
13
+ readonly getJob: (queue: string, id: string) => Effect.Effect<StoredJob | undefined, PgBossError>;
14
+ readonly retry: (queue: string, id: string) => Effect.Effect<void, PgBossError>;
15
+ readonly listJobs: (
16
+ listing: Listing,
17
+ queue: string,
18
+ after: readonly [string, string] | undefined,
19
+ limit: number,
20
+ ) => Effect.Effect<readonly unknown[], PgBossError>;
21
+ readonly settleDeferral: (
22
+ job: JobAttempt,
23
+ at: string,
24
+ reason: string,
25
+ maxDeferrals: number,
26
+ ) => Effect.Effect<{ readonly claimed: boolean; readonly deferred: boolean }, PgBossError>;
27
+ }
28
+ >()("@shivaedev/jobs/JobEngine") {}
29
+
30
+ export interface TestingSettlements {
31
+ readonly close: Effect.Effect<void>;
32
+ readonly watch: (name: string) => Effect.Effect<void, PgBossTestingError>;
33
+ }
34
+
35
+ export class TestingEngine extends Context.Service<
36
+ TestingEngine,
37
+ {
38
+ readonly expireAttempt: (job: JobAttempt, cause?: "expiry" | "heartbeat") => Effect.Effect<void, PgBossTestingError>;
39
+ readonly observeSettlements: (settled: (name: string) => void) => Effect.Effect<TestingSettlements>;
40
+ }
41
+ >()("@shivaedev/jobs/TestingEngine") {}
@@ -1,9 +1,9 @@
1
1
  import { Effect, Option, Redacted, Schema } from "effect";
2
- import { transactionDb } from "#adapters/transactionDb.ts";
3
- import type { PgBossClient } from "#client.ts";
4
- import { PgBossPayloadError, toPgBossError } from "#error.ts";
5
- import { capturePayload } from "#internal/tracing.ts";
6
- import type { PgBossService } from "#service.ts";
2
+ import { transactionDb } from "#server/adapters/transactionDb.ts";
3
+ import type { PgBossClient } from "#server/client.ts";
4
+ import { PgBossPayloadError, toPgBossError } from "#server/error.ts";
5
+ import { capturePayload } from "#server/internal/tracing.ts";
6
+ import type { PgBossService } from "#server/service.ts";
7
7
 
8
8
  export function enqueueFor(client: PgBossClient): PgBossService["enqueue"] {
9
9
  return (queue, payload, options) =>
@@ -1,15 +1,14 @@
1
1
  import { Effect, Schedule } from "effect";
2
- import type { Queue } from "pg-boss";
3
- import type { PgBossClient } from "#client.ts";
4
- import { PgBossQueueOptionsError } from "#error.ts";
5
- import { deadLetterQueueName } from "#health.ts";
2
+ import type { ClientQueueOptions, PgBossClient } from "#server/client.ts";
3
+ import { PgBossQueueOptionsError } from "#server/error.ts";
4
+ import { deadLetterQueueName } from "#server/health.ts";
6
5
 
7
6
  const DEADLOCK_DETECTED = "40P01";
8
7
  const CREATE_QUEUE_ATTEMPTS = 6;
9
8
 
10
9
  // A partitioned queue attaches its table to pg-boss's job table, which can deadlock with job traffic on other queues.
11
10
  // PostgreSQL rolls the whole creation back, so trying it again is safe.
12
- function createQueue(client: PgBossClient, name: string, options?: Omit<Queue, "name">) {
11
+ function createQueue(client: PgBossClient, name: string, options?: ClientQueueOptions) {
13
12
  return Effect.tryPromise({ catch: (error) => error, try: () => client.createQueue(name, options) }).pipe(
14
13
  Effect.retry({
15
14
  schedule: Schedule.exponential(25).pipe(Schedule.upTo({ times: CREATE_QUEUE_ATTEMPTS - 1 })),
@@ -18,7 +17,7 @@ function createQueue(client: PgBossClient, name: string, options?: Omit<Queue, "
18
17
  );
19
18
  }
20
19
 
21
- export const ensureQueue = Effect.fnUntraced(function* (client: PgBossClient, name: string, options: Omit<Queue, "name" | "deadLetter">) {
20
+ export const ensureQueue = Effect.fnUntraced(function* (client: PgBossClient, name: string, options: Omit<ClientQueueOptions, "deadLetter">) {
22
21
  const deadLetter = deadLetterQueueName(name);
23
22
  const desired = { retryBackoff: true, retryLimit: 3, ...options, deadLetter };
24
23
  yield* createQueue(client, deadLetter);
@@ -1,9 +1,9 @@
1
1
  import { Effect } from "effect";
2
- import type { PgBossClient } from "#client.ts";
3
- import { toPgBossError } from "#error.ts";
4
- import { deadLetterQueueName, type JobsHealth, type QueueHealth } from "#health.ts";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import { toPgBossError } from "#server/error.ts";
4
+ import { deadLetterQueueName, type JobsHealth, type QueueHealth } from "#server/health.ts";
5
5
 
6
- export function healthFor(client: PgBossClient, names: readonly string[]): Effect.Effect<JobsHealth, import("#error.ts").PgBossError> {
6
+ export function healthFor(client: PgBossClient, names: readonly string[]): Effect.Effect<JobsHealth, import("#server/error.ts").PgBossError> {
7
7
  return Effect.forEach(
8
8
  names,
9
9
  (name) =>
@@ -1,62 +1,27 @@
1
- import { Effect, Option, Redacted, Schema } from "effect";
1
+ import { Effect, Option } from "effect";
2
2
  import { redact } from "@shivaedev/errors/redact.ts";
3
- import type { PgBossClient } from "#client.ts";
4
- import { PgBossPayloadError, toPgBossError } from "#error.ts";
5
- import { deferralOf } from "#internal/deferral.ts";
6
- import { decodeStoredData } from "#internal/storedRows.ts";
7
- import { JobFailure } from "#JobFailure.ts";
8
- import type { PgBossService } from "#service.ts";
3
+ import { deferralOf } from "#server/internal/deferral.ts";
4
+ import { JobEngine } from "#server/internal/engine.ts";
5
+ import { decodeStoredData } from "#server/internal/storedRows.ts";
6
+ import { readJobFailure } from "#server/readJobFailure.ts";
7
+ import type { PgBossService } from "#server/service.ts";
9
8
 
10
- const StoredFailure = Schema.Union([JobFailure, Schema.Struct({ value: JobFailure })]);
11
-
12
- function decodeFailure(queue: string, output: unknown) {
13
- return Schema.decodeUnknownEffect(StoredFailure)(output).pipe(
14
- Effect.map((failure) => ("value" in failure ? failure.value : failure)),
15
- Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue })),
16
- );
17
- }
18
-
19
- export function getJobFor(client: PgBossClient): PgBossService["getJob"] {
20
- return (queue, id) =>
21
- Effect.tryPromise({
22
- catch: (error) => toPgBossError("getJob", error, queue.name),
23
- try: async () => {
24
- if (client.findJobs === undefined) {
25
- throw new TypeError("This pg-boss client does not support findJobs");
26
- }
27
- return (await client.findJobs(queue.name, { id }))[0];
28
- },
29
- }).pipe(
9
+ export const jobControl = Effect.gen(function* () {
10
+ const engine = yield* JobEngine;
11
+ const getJob: PgBossService["getJob"] = (queue, id) =>
12
+ engine.getJob(queue.name, id).pipe(
30
13
  Effect.flatMap(
31
14
  Effect.fnUntraced(function* (job) {
32
15
  if (job === undefined) {
33
16
  return Option.none();
34
17
  }
35
18
  const data = yield* decodeStoredData(queue, job.data);
36
- const output = job.output === null || deferralOf(job) !== undefined ? job.output : yield* decodeFailure(queue.name, job.output);
37
- const sourceOutput = job.sourceOutput === null ? null : yield* decodeFailure(queue.name, job.sourceOutput);
19
+ const output = deferralOf(job) === undefined ? yield* readJobFailure(queue.name, job.output) : job.output;
20
+ const sourceOutput = yield* readJobFailure(queue.name, job.sourceOutput);
38
21
  return Option.some({ ...job, data: redact(data), output, sourceOutput });
39
22
  }),
40
23
  ),
41
24
  );
42
- }
43
-
44
- export function retryFor(client: PgBossClient): PgBossService["retry"] {
45
- return (queue, id) =>
46
- Effect.tryPromise({
47
- catch: (error) => toPgBossError("retry", error, queue.name),
48
- try: async () => {
49
- if (client.findJobs === undefined || client.retry === undefined || client.update === undefined) {
50
- throw new TypeError("This pg-boss client does not support findJobs, retry and update");
51
- }
52
- const job = (await client.findJobs(queue.name, { id }))[0];
53
- if (job?.state !== "failed" && job?.state !== "retry") {
54
- return;
55
- }
56
- if (job.state === "failed") {
57
- await client.retry(queue.name, id);
58
- }
59
- await client.update(queue.name, undefined, { id, startAfter: 0 });
60
- },
61
- });
62
- }
25
+ const retry: PgBossService["retry"] = (queue, id) => engine.retry(queue.name, id);
26
+ return { getJob, retry };
27
+ });
@@ -0,0 +1,85 @@
1
+ import { type Context, Effect, Option, Redacted, Schema } from "effect";
2
+ import { redact } from "@shivaedev/errors/redact.ts";
3
+ import type { JobPayloadSchema } from "#server/definition.ts";
4
+ import { type PgBossError, PgBossPayloadError } from "#server/error.ts";
5
+ import type { DeadLetteredJob, JobPage, JobPageOptions } from "#server/health.ts";
6
+ import { JobEngine, type Listing } from "#server/internal/engine.ts";
7
+ import { decodeStoredData } from "#server/internal/storedRows.ts";
8
+ import { readJobFailure } from "#server/readJobFailure.ts";
9
+ import type { PgBossService } from "#server/service.ts";
10
+
11
+ const Cursor = Schema.StringFromBase64Url.pipe(
12
+ Schema.decodeTo(
13
+ Schema.fromJsonString(
14
+ Schema.Tuple([
15
+ Schema.String.check(Schema.makeFilter((value) => Option.isSome(Schema.decodeUnknownOption(Schema.DateTimeUtcFromString)(value)))),
16
+ Schema.String.check(Schema.isUUID()),
17
+ ]),
18
+ ),
19
+ ),
20
+ );
21
+ const PageOptions = Schema.Struct({
22
+ cursor: Schema.optionalKey(Schema.UndefinedOr(Cursor)),
23
+ limit: Schema.Number.check(Schema.isInt(), Schema.isGreaterThan(0)),
24
+ });
25
+
26
+ const Row = Schema.Struct({
27
+ completedOn: Schema.OptionFromNullOr(Schema.DateTimeUtcFromDate),
28
+ createdOn: Schema.DateTimeUtcFromDate,
29
+ cursorAt: Schema.String,
30
+ data: Schema.Unknown,
31
+ id: Schema.String,
32
+ output: Schema.Unknown,
33
+ queue: Schema.String,
34
+ retryCount: Schema.Number,
35
+ retryLimit: Schema.Number,
36
+ sourceId: Schema.OptionFromNullOr(Schema.String),
37
+ sourceOutput: Schema.Unknown,
38
+ startedOn: Schema.OptionFromNullOr(Schema.DateTimeUtcFromDate),
39
+ state: Schema.Literals(["created", "retry", "active", "completed", "cancelled", "failed"]),
40
+ });
41
+
42
+ const Rows = Schema.Array(Row);
43
+
44
+ export const jobListings = Effect.gen(function* () {
45
+ const engine = yield* JobEngine;
46
+ const failedJobs: PgBossService["failedJobs"] = (queue, options) =>
47
+ listJobs(engine, "failedJobs", queue, options).pipe(
48
+ Effect.map(({ jobs, next }) => ({ jobs: jobs.map(({ sourceId: _id, sourceOutput: _output, ...job }) => job), next })),
49
+ );
50
+ const deadLetteredJobs: PgBossService["deadLetteredJobs"] = (queue, options) =>
51
+ listJobs(engine, "deadLetteredJobs", queue, options).pipe(
52
+ Effect.map(({ jobs, next }) => ({ jobs: jobs.map((job) => ({ ...job, sourceQueue: queue.name })), next })),
53
+ );
54
+ return { deadLetteredJobs, failedJobs };
55
+ });
56
+
57
+ const listJobs = Effect.fnUntraced(function* <const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(
58
+ engine: Context.Service.Shape<typeof JobEngine>,
59
+ listing: Listing,
60
+ queue: { readonly name: TName; readonly schema: TPayload },
61
+ options: JobPageOptions,
62
+ ): Effect.fn.Return<
63
+ JobPage<Omit<DeadLetteredJob<unknown>, "sourceQueue">>,
64
+ PgBossError | PgBossPayloadError | Schema.SchemaError,
65
+ TPayload["DecodingServices"]
66
+ > {
67
+ const { cursor: after, limit } = yield* Schema.decodeUnknownEffect(PageOptions)(options);
68
+ const rows = yield* engine.listJobs(listing, queue.name, after, limit);
69
+ const decodedRows = yield* Schema.decodeUnknownEffect(Rows)(rows).pipe(
70
+ Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue: queue.name })),
71
+ );
72
+ const page = decodedRows.slice(0, limit);
73
+ const last = page.at(-1);
74
+ const next = decodedRows.length > limit && last !== undefined ? Option.some(Schema.encodeSync(Cursor)([last.cursorAt, last.id])) : Option.none();
75
+ const jobs = yield* Effect.forEach(
76
+ page,
77
+ Effect.fnUntraced(function* ({ cursorAt: _, data, ...row }) {
78
+ const decoded = yield* decodeStoredData(queue, data);
79
+ const output = yield* readJobFailure(queue.name, row.output);
80
+ const sourceOutput = yield* readJobFailure(queue.name, row.sourceOutput);
81
+ return { ...row, attempt: Option.isSome(row.startedOn) ? row.retryCount + 1 : 0, data: redact(decoded), output, sourceOutput };
82
+ }),
83
+ );
84
+ return { jobs, next };
85
+ });