@shivaedev/jobs 0.29.2 → 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 (383) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/README.md +74 -22
  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 +16 -7
  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 +15 -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 +20 -18
  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 +17 -29
  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 +6 -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 +11 -5
  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 +4 -0
  222. package/dist/server/internal/testingRegistrations.d.ts.map +1 -0
  223. package/dist/server/internal/testingRegistrations.js +8 -0
  224. package/dist/server/internal/testingRegistrations.js.map +1 -0
  225. package/dist/server/internal/testingSchedules.d.ts +3 -3
  226. package/dist/server/internal/testingSchedules.d.ts.map +1 -1
  227. package/dist/server/internal/testingSchedules.js +1 -1
  228. package/dist/server/internal/testingSchedules.js.map +1 -1
  229. package/dist/server/internal/testingSnapshot.d.ts +4 -4
  230. package/dist/server/internal/testingSnapshot.d.ts.map +1 -1
  231. package/dist/server/internal/testingSnapshot.js +7 -4
  232. package/dist/server/internal/testingSnapshot.js.map +1 -1
  233. package/dist/server/internal/testingWaits.d.ts +8 -7
  234. package/dist/server/internal/testingWaits.d.ts.map +1 -1
  235. package/dist/server/internal/testingWaits.js +3 -3
  236. package/dist/server/internal/testingWaits.js.map +1 -1
  237. package/dist/server/internal/tracing.d.ts +2 -2
  238. package/dist/server/internal/tracing.d.ts.map +1 -1
  239. package/dist/server/internal/tracing.js.map +1 -1
  240. package/dist/server/internal/validateQueueNames.d.ts +2 -2
  241. package/dist/server/internal/validateQueueNames.d.ts.map +1 -1
  242. package/dist/server/internal/validateQueueNames.js +1 -1
  243. package/dist/server/internal/validateQueueNames.js.map +1 -1
  244. package/dist/server/internal/waitForBatchExpiry.d.ts +4 -4
  245. package/dist/server/internal/waitForBatchExpiry.d.ts.map +1 -1
  246. package/dist/server/internal/waitForBatchExpiry.js +1 -1
  247. package/dist/server/internal/waitForBatchExpiry.js.map +1 -1
  248. package/dist/server/job.d.ts +42 -0
  249. package/dist/server/job.d.ts.map +1 -0
  250. package/dist/server/job.js +2 -0
  251. package/dist/server/job.js.map +1 -0
  252. package/dist/server/jobModule.d.ts +9 -0
  253. package/dist/server/jobModule.d.ts.map +1 -0
  254. package/dist/server/jobModule.js +15 -0
  255. package/dist/server/jobModule.js.map +1 -0
  256. package/dist/server/queueOptions.d.ts +19 -0
  257. package/dist/server/queueOptions.d.ts.map +1 -0
  258. package/dist/server/queueOptions.js +2 -0
  259. package/dist/server/queueOptions.js.map +1 -0
  260. package/dist/server/readJobFailure.d.ts +5 -0
  261. package/dist/server/readJobFailure.d.ts.map +1 -0
  262. package/dist/server/readJobFailure.js +8 -0
  263. package/dist/server/readJobFailure.js.map +1 -0
  264. package/dist/server/schema.d.ts +1 -1
  265. package/dist/server/schema.d.ts.map +1 -1
  266. package/dist/server/schema.js +18 -7
  267. package/dist/server/schema.js.map +1 -1
  268. package/dist/server/service.d.ts +15 -10
  269. package/dist/server/service.d.ts.map +1 -1
  270. package/dist/server/service.js +26 -33
  271. package/dist/server/service.js.map +1 -1
  272. package/dist/server/testing.d.ts +32 -70
  273. package/dist/server/testing.d.ts.map +1 -1
  274. package/dist/server/testing.js +9 -96
  275. package/dist/server/testing.js.map +1 -1
  276. package/dist/server/workerOptions.d.ts +25 -0
  277. package/dist/server/workerOptions.d.ts.map +1 -0
  278. package/dist/server/workerOptions.js +2 -0
  279. package/dist/server/workerOptions.js.map +1 -0
  280. package/package.json +11 -16
  281. package/src/display.ts +12 -0
  282. package/src/server/ClientDatabase.ts +7 -0
  283. package/src/server/PgBoss.ts +2 -2
  284. package/src/server/adapters/batchClockOffset.ts +8 -5
  285. package/src/server/{internal → adapters}/batchHandler.ts +13 -13
  286. package/src/server/{internal → adapters}/clientCache.ts +10 -22
  287. package/src/server/adapters/clientErrorLogger.ts +1 -1
  288. package/src/server/{defaultClientFactory.ts → adapters/defaultClientFactory.ts} +4 -2
  289. package/src/server/adapters/deferralCount.ts +5 -5
  290. package/src/server/{internal → adapters}/expireAttempt.ts +4 -3
  291. package/src/server/adapters/installSchema.ts +2 -2
  292. package/src/server/adapters/jobEngine.ts +59 -0
  293. package/src/server/adapters/lifecycle.ts +67 -0
  294. package/src/server/adapters/listJobs.ts +43 -0
  295. package/src/server/{internal → adapters}/observeTestingSettlements.ts +2 -2
  296. package/src/server/adapters/queueAdministration.ts +47 -0
  297. package/src/server/adapters/registerWorker.ts +24 -13
  298. package/src/server/adapters/retireJobs.ts +5 -5
  299. package/src/server/adapters/schemaIndexBuilds.ts +2 -2
  300. package/src/server/{internal → adapters}/settleDeferral.ts +5 -5
  301. package/src/server/{internal → adapters}/testingClient.ts +34 -26
  302. package/src/server/adapters/testingController.ts +109 -0
  303. package/src/server/adapters/testingDueNow.ts +5 -5
  304. package/src/server/adapters/testingEngine.ts +28 -0
  305. package/src/server/adapters/testingExpirations.ts +6 -4
  306. package/src/server/adapters/transactionDb.ts +2 -2
  307. package/src/server/client.ts +83 -30
  308. package/src/server/clientOptions.ts +81 -0
  309. package/src/server/defineSchedule.ts +3 -2
  310. package/src/server/definition.ts +24 -20
  311. package/src/server/engineClient.ts +24 -0
  312. package/src/server/enqueueOptions.ts +20 -0
  313. package/src/server/error.ts +17 -2
  314. package/src/server/health.ts +2 -2
  315. package/src/server/internal/acquireClient.ts +26 -0
  316. package/src/server/internal/adapters/testingFetches.ts +2 -2
  317. package/src/server/internal/clientErrors.ts +1 -1
  318. package/src/server/internal/countsFor.ts +5 -5
  319. package/src/server/internal/deadLetterResolutionPlan.ts +1 -1
  320. package/src/server/internal/deadlineOf.ts +2 -2
  321. package/src/server/internal/deferrableAttempt.ts +5 -22
  322. package/src/server/internal/deferral.ts +3 -3
  323. package/src/server/internal/deferralStorePlan.ts +2 -2
  324. package/src/server/internal/definitionOptions.ts +1 -1
  325. package/src/server/internal/engine.ts +41 -0
  326. package/src/server/internal/enqueueFor.ts +5 -5
  327. package/src/server/internal/ensureQueue.ts +5 -6
  328. package/src/server/internal/healthFor.ts +4 -4
  329. package/src/server/internal/jobControl.ts +15 -50
  330. package/src/server/internal/jobListings.ts +85 -0
  331. package/src/server/internal/jobStorePlans.ts +2 -2
  332. package/src/server/internal/lifecycle.ts +14 -55
  333. package/src/server/internal/makeService.ts +21 -13
  334. package/src/server/internal/register.ts +27 -45
  335. package/src/server/internal/registerReleasedJobs.ts +6 -6
  336. package/src/server/internal/retryWake.ts +3 -3
  337. package/src/server/internal/runQueueWorker.ts +14 -8
  338. package/src/server/internal/storedRows.ts +3 -3
  339. package/src/server/internal/testingDeferrals.ts +5 -5
  340. package/src/server/internal/testingIdle.ts +13 -8
  341. package/src/server/internal/testingReadout.ts +12 -6
  342. package/src/server/internal/testingRegistrations.ts +10 -0
  343. package/src/server/internal/testingSchedules.ts +4 -4
  344. package/src/server/internal/testingSnapshot.ts +11 -8
  345. package/src/server/internal/testingWaits.ts +11 -10
  346. package/src/server/internal/tracing.ts +2 -2
  347. package/src/server/internal/validateQueueNames.ts +2 -2
  348. package/src/server/internal/waitForBatchExpiry.ts +4 -4
  349. package/src/server/job.ts +42 -0
  350. package/src/server/jobModule.ts +30 -0
  351. package/src/server/queueOptions.ts +20 -0
  352. package/src/server/readJobFailure.ts +12 -0
  353. package/src/server/schema.ts +18 -7
  354. package/src/server/service.ts +63 -59
  355. package/src/server/testing.ts +17 -108
  356. package/src/server/workerOptions.ts +28 -0
  357. package/dist/server/defaultClientFactory.d.ts +0 -3
  358. package/dist/server/defaultClientFactory.d.ts.map +0 -1
  359. package/dist/server/defaultClientFactory.js.map +0 -1
  360. package/dist/server/internal/batchHandler.d.ts +0 -5
  361. package/dist/server/internal/batchHandler.d.ts.map +0 -1
  362. package/dist/server/internal/batchHandler.js.map +0 -1
  363. package/dist/server/internal/clientCache.d.ts +0 -8
  364. package/dist/server/internal/clientCache.d.ts.map +0 -1
  365. package/dist/server/internal/clientCache.js.map +0 -1
  366. package/dist/server/internal/expireAttempt.d.ts +0 -3
  367. package/dist/server/internal/expireAttempt.d.ts.map +0 -1
  368. package/dist/server/internal/listJobs.d.ts +0 -5
  369. package/dist/server/internal/listJobs.d.ts.map +0 -1
  370. package/dist/server/internal/listJobs.js +0 -75
  371. package/dist/server/internal/listJobs.js.map +0 -1
  372. package/dist/server/internal/observeTestingSettlements.d.ts +0 -6
  373. package/dist/server/internal/observeTestingSettlements.d.ts.map +0 -1
  374. package/dist/server/internal/observeTestingSettlements.js.map +0 -1
  375. package/dist/server/internal/settleDeferral.d.ts +0 -7
  376. package/dist/server/internal/settleDeferral.d.ts.map +0 -1
  377. package/dist/server/internal/settleDeferral.js.map +0 -1
  378. package/dist/server/internal/testingClient.d.ts +0 -13
  379. package/dist/server/internal/testingClient.d.ts.map +0 -1
  380. package/dist/server/internal/testingClient.js.map +0 -1
  381. package/src/server/internal/listJobs.ts +0 -116
  382. /package/dist/server/{defaultClientFactory.js → adapters/defaultClientFactory.js} +0 -0
  383. /package/dist/server/{internal → adapters}/observeTestingSettlements.js +0 -0
@@ -0,0 +1,10 @@
1
+ import type { PgBossClient } from "#server/client.ts";
2
+
3
+ export const testingRegistration = Symbol("jobs testing registration");
4
+
5
+ export function registerTestingQueue(client: PgBossClient, name: string) {
6
+ const observe: unknown = Reflect.get(client, testingRegistration);
7
+ if (typeof observe === "function") {
8
+ observe(name);
9
+ }
10
+ }
@@ -1,8 +1,8 @@
1
- import type { PgBoss } from "pg-boss";
2
- import type { ScheduleDefinition } from "#definition.ts";
3
- import { testingOperation } from "#internal/testingReadout.ts";
1
+ import type { ScheduleDefinition } from "#server/definition.ts";
2
+ import type { EngineClient } from "#server/engineClient.ts";
3
+ import { testingOperation } from "#server/internal/testingReadout.ts";
4
4
 
5
- export function testingSchedules(client: () => PgBoss, changed: () => void) {
5
+ export function testingSchedules(client: () => EngineClient, changed: () => void) {
6
6
  return {
7
7
  schedules: () =>
8
8
  testingOperation("schedules", async () => (await client().getSchedules()).map(({ name, cron, timezone }) => ({ cron, name, timezone }))),
@@ -1,9 +1,9 @@
1
1
  import { Effect, Schema } from "effect";
2
- import type { PgBoss } from "pg-boss";
3
- import type { PgBossPayloadError, PgBossTestingError } from "#error.ts";
4
- import { decodeStoredData, quotedSchema } from "#internal/storedRows.ts";
5
- import { testingOperation } from "#internal/testingReadout.ts";
6
- import type { SnapshotQueue, UnfinishedJob } from "#testing.ts";
2
+ import type { EngineClient } from "#server/engineClient.ts";
3
+ import type { PgBossPayloadError, PgBossTestingError } from "#server/error.ts";
4
+ import { decodeStoredData, quotedSchema } from "#server/internal/storedRows.ts";
5
+ import { testingOperation } from "#server/internal/testingReadout.ts";
6
+ import type { SnapshotQueue, UnfinishedJob } from "#server/testing.ts";
7
7
 
8
8
  const Rows = Schema.Array(
9
9
  Schema.Struct({
@@ -11,11 +11,11 @@ const Rows = Schema.Array(
11
11
  id: Schema.String,
12
12
  queue: Schema.String,
13
13
  startAfter: Schema.DateTimeUtcFromDate,
14
- state: Schema.Literals(["created", "retry", "active", "failed"]),
14
+ state: Schema.Literals(["created", "retry", "deferred", "active", "failed"]),
15
15
  }),
16
16
  );
17
17
 
18
- export function testingSnapshot(client: () => PgBoss, schema: () => string) {
18
+ export function testingSnapshot(client: () => EngineClient, schema: () => string) {
19
19
  return <const TQueues extends readonly SnapshotQueue[]>(
20
20
  queues: TQueues,
21
21
  ): Effect.Effect<
@@ -29,7 +29,10 @@ export function testingSnapshot(client: () => PgBoss, schema: () => string) {
29
29
  const { rows } = await client()
30
30
  .getDb()
31
31
  .executeSql(
32
- `SELECT id, name AS queue, state, data, start_after AS "startAfter"
32
+ `SELECT id, name AS queue, data, start_after AS "startAfter",
33
+ CASE WHEN state = 'retry' AND started_on IS NULL AND start_after > ${quoted}.job_now()
34
+ AND output ? 'jobDeferral'
35
+ THEN 'deferred' ELSE state::text END AS state
33
36
  FROM ${quoted}.job
34
37
  WHERE name = ANY($1::text[]) AND state IN ('created', 'retry', 'active', 'failed')
35
38
  ORDER BY created_on, id`,
@@ -1,11 +1,12 @@
1
1
  import { Clock, Duration, Effect, Option, Redacted } from "effect";
2
- import type { JobWithMetadata, PgBoss } from "pg-boss";
3
- import type { JobPayloadSchema, QueueDefinition } from "#definition.ts";
4
- import { type PgBossPayloadError, PgBossTestingError, PgBossWaitError } from "#error.ts";
5
- import type { TestingFetches } from "#internal/adapters/testingFetches.ts";
6
- import { decodeStoredData } from "#internal/storedRows.ts";
7
- import { testingOperation } from "#internal/testingReadout.ts";
8
- import type { PgBossTestingWaitOptions } from "#testing.ts";
2
+ import type { JobPayloadSchema, QueueDefinition } from "#server/definition.ts";
3
+ import type { EngineClient } from "#server/engineClient.ts";
4
+ import { type PgBossPayloadError, PgBossTestingError, PgBossWaitError } from "#server/error.ts";
5
+ import type { TestingFetches } from "#server/internal/adapters/testingFetches.ts";
6
+ import { decodeStoredData } from "#server/internal/storedRows.ts";
7
+ import { testingOperation } from "#server/internal/testingReadout.ts";
8
+ import type { Job, JobState } from "#server/job.ts";
9
+ import type { PgBossTestingWaitOptions } from "#server/testing.ts";
9
10
 
10
11
  interface Reading<A> {
11
12
  readonly arrived: Option.Option<A>;
@@ -49,7 +50,7 @@ function fetchesRefused(queue: Pick<QueueDefinition, "name">, original: Error) {
49
50
  return new PgBossTestingError({ operation: "fetchesPass", original: Redacted.make(original), queue: queue.name });
50
51
  }
51
52
 
52
- export function testingWaits(client: () => PgBoss, fetches: () => TestingFetches | undefined, signal: Signal) {
53
+ export function testingWaits(client: () => EngineClient, fetches: () => TestingFetches | undefined, signal: Signal) {
53
54
  return {
54
55
  fetchesPass: (queue: Pick<QueueDefinition, "name">, count: number, options?: PgBossTestingWaitOptions) =>
55
56
  Effect.gen(function* () {
@@ -75,14 +76,14 @@ export function testingWaits(client: () => PgBoss, fetches: () => TestingFetches
75
76
  untilJob: <TName extends string, TPayload extends JobPayloadSchema>(
76
77
  queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">,
77
78
  id: string,
78
- state: JobWithMetadata["state"],
79
+ state: JobState,
79
80
  options?: PgBossTestingWaitOptions,
80
81
  ) =>
81
82
  waitUntil(
82
83
  signal,
83
84
  `job ${id} in ${queue.name} is ${state}`,
84
85
  testingOperation("untilJob", () => client().getJobById<unknown>(queue.name, id), queue.name).pipe(
85
- Effect.flatMap((job): Effect.Effect<Reading<JobWithMetadata<TPayload["Type"]>>, PgBossPayloadError, TPayload["DecodingServices"]> => {
86
+ Effect.flatMap((job): Effect.Effect<Reading<Job<TPayload["Type"]>>, PgBossPayloadError, TPayload["DecodingServices"]> => {
86
87
  if (job === null) {
87
88
  return Effect.succeed({ arrived: Option.none(), seen: "no such job" });
88
89
  }
@@ -1,5 +1,5 @@
1
1
  import { Effect, Option, Schema, Tracer } from "effect";
2
- import type { Job } from "pg-boss";
2
+ import type { WorkerJob } from "#server/job.ts";
3
3
 
4
4
  const TracedPayload = Schema.Struct({
5
5
  _tag: Schema.Literal("@shivaedev/jobs/TracedPayload"),
@@ -25,7 +25,7 @@ export function payloadOf(data: unknown): unknown {
25
25
  return isTracedPayload(data) ? data.payload : data;
26
26
  }
27
27
 
28
- export function traceJob<A, E, R>(effect: Effect.Effect<A, E, R>, job: Job<unknown>, queue: string) {
28
+ export function traceJob<A, E, R>(effect: Effect.Effect<A, E, R>, job: WorkerJob<unknown>, queue: string) {
29
29
  return Effect.withSpan(effect, queue, {
30
30
  attributes: {
31
31
  "job.attempt": job.retryCount + 1,
@@ -1,6 +1,6 @@
1
1
  import { Effect } from "effect";
2
- import type { JobRegistration } from "#definition.ts";
3
- import { PgBossQueueNamesError } from "#error.ts";
2
+ import type { JobRegistration } from "#server/definition.ts";
3
+ import { PgBossQueueNamesError } from "#server/error.ts";
4
4
  import { registrationName } from "./register.ts";
5
5
 
6
6
  export const validateQueueNames = Effect.fnUntraced(function* (jobs: readonly JobRegistration[], declared: readonly string[] | undefined) {
@@ -1,12 +1,12 @@
1
1
  import { Clock, Effect } from "effect";
2
- import type { Job } from "pg-boss";
3
- import type { PgBossClient } from "#client.ts";
4
- import { type PgBossError, toPgBossError } from "#error.ts";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import { type PgBossError, toPgBossError } from "#server/error.ts";
4
+ import type { WorkerJob } from "#server/job.ts";
5
5
 
6
6
  export function waitForBatchExpiry(
7
7
  client: PgBossClient,
8
8
  name: string,
9
- jobs: readonly Job<unknown>[],
9
+ jobs: readonly WorkerJob<unknown>[],
10
10
  deadline: number,
11
11
  ): Effect.Effect<void, PgBossError> {
12
12
  return Effect.gen(function* () {
@@ -0,0 +1,42 @@
1
+ export type JobState = "created" | "retry" | "active" | "completed" | "cancelled" | "failed";
2
+
3
+ export interface WorkerJob<T = unknown> {
4
+ data: T;
5
+ expireInSeconds: number;
6
+ groupId?: string | null;
7
+ groupTier?: string | null;
8
+ heartbeatSeconds: number | null;
9
+ id: string;
10
+ name: string;
11
+ retryCount: number;
12
+ signal: AbortSignal;
13
+ }
14
+ export interface Job<T = unknown> extends WorkerJob<T> {
15
+ blocked: boolean;
16
+ blocking: boolean;
17
+ completedOn: Date | null;
18
+ createdOn: Date;
19
+ deadLetter: string;
20
+ deleteAfterSeconds: number;
21
+ heartbeatOn: Date | null;
22
+ keepUntil: Date;
23
+ output: object | null;
24
+ pendingDependencies: number;
25
+ policy: string;
26
+ priority: number;
27
+ retryBackoff: boolean;
28
+ retryDelay: number;
29
+ retryDelayMax?: number;
30
+ retryLimit: number;
31
+ singletonKey: string | null;
32
+ singletonOn: Date | null;
33
+ sourceCreatedOn: Date | null;
34
+ sourceId: string | null;
35
+ sourceName: string | null;
36
+ sourceOutput: object | null;
37
+ sourceRetryCount: number | null;
38
+ sourceRootId: string | null;
39
+ startAfter: Date;
40
+ startedOn: Date | null;
41
+ state: JobState;
42
+ }
@@ -0,0 +1,30 @@
1
+ import type { JobRegistration, QueueDefinition, QueueWorker, ScheduledWorker } from "#server/definition.ts";
2
+ import type { PgBossDefinition, PgBossLayerOptions } from "#server/service.ts";
3
+
4
+ export function jobModule<TIdentifier extends string, const TJobs extends readonly JobRegistration[], R = never>(
5
+ layer: PgBossDefinition<TIdentifier>["layer"],
6
+ options: PgBossLayerOptions<TJobs, R>,
7
+ ) {
8
+ return {
9
+ queues: moduleQueues(options.jobs),
10
+ workers: layer(options),
11
+ };
12
+ }
13
+
14
+ type ModuleQueue<TJob extends JobRegistration> = TJob extends QueueDefinition
15
+ ? TJob
16
+ : TJob extends QueueWorker
17
+ ? TJob["queue"]
18
+ : TJob extends ScheduledWorker
19
+ ? TJob["schedule"]
20
+ : never;
21
+
22
+ function moduleQueues<const TJobs extends readonly JobRegistration[]>(jobs: TJobs): ModuleQueue<TJobs[number]>[];
23
+ function moduleQueues(jobs: readonly JobRegistration[]) {
24
+ return jobs.map((job) => {
25
+ if (job._tag === "QueueDefinition") {
26
+ return job;
27
+ }
28
+ return job._tag === "QueueWorker" ? job.queue : job.schedule;
29
+ });
30
+ }
@@ -0,0 +1,20 @@
1
+ export type QueuePolicy = "standard" | "short" | "singleton" | "stately" | "exclusive" | "key_strict_fifo";
2
+
3
+ export interface RetryOptions {
4
+ deleteAfterSeconds?: number;
5
+ expireInSeconds?: number;
6
+ heartbeatSeconds?: number;
7
+ retentionSeconds?: number;
8
+ retryBackoff?: boolean;
9
+ retryDelay?: number;
10
+ retryDelayMax?: number;
11
+ retryLimit?: number;
12
+ }
13
+
14
+ export interface QueueOptions extends RetryOptions {
15
+ readonly maxDeferrals?: number;
16
+ readonly notify?: boolean;
17
+ readonly partition?: boolean;
18
+ readonly policy?: QueuePolicy;
19
+ readonly warningQueueSize?: number;
20
+ }
@@ -0,0 +1,12 @@
1
+ import { Effect, Redacted, Schema } from "effect";
2
+ import { JobFailure } from "#JobFailure.ts";
3
+ import { PgBossPayloadError } from "#server/error.ts";
4
+
5
+ const StoredFailure = Schema.NullOr(Schema.Union([JobFailure, Schema.Struct({ value: JobFailure })]));
6
+
7
+ export function readJobFailure(queue: string, output: unknown): Effect.Effect<JobFailure | null, PgBossPayloadError> {
8
+ return Schema.decodeUnknownEffect(StoredFailure)(output).pipe(
9
+ Effect.map((failure) => (failure !== null && "value" in failure ? failure.value : failure)),
10
+ Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue })),
11
+ );
12
+ }
@@ -2,12 +2,12 @@ import { Effect, Schema } from "effect";
2
2
  import { SqlClient } from "effect/sql";
3
3
  import pgBossPackage from "pg-boss/package.json" with { type: "json" };
4
4
  import type { SchemaComponent } from "@shivaedev/sql/SchemaComponent.ts";
5
- import { installSchema } from "#adapters/installSchema.ts";
6
- import { type PgBossError, toPgBossError } from "#error.ts";
5
+ import { installSchema } from "#server/adapters/installSchema.ts";
6
+ import { type PgBossError, toPgBossError } from "#server/error.ts";
7
7
 
8
8
  const InstalledSchema = Schema.Array(Schema.Struct({ name: Schema.NullOr(Schema.String) }));
9
9
  const InstalledVersion = Schema.Array(Schema.Struct({ version: Schema.Number }));
10
- const InstalledResolution = Schema.Array(Schema.Struct({ installed: Schema.Boolean }));
10
+ const MissingArtifacts = Schema.Array(Schema.Struct({ name: Schema.String }));
11
11
 
12
12
  export interface PgBossSchemaOptions {
13
13
  readonly schema?: string;
@@ -40,10 +40,21 @@ export function pgBossSchema(options: PgBossSchemaOptions = {}): SchemaComponent
40
40
  return `schema ${schema}, installed version ${row?.version ?? "missing"}, required version ${required}`;
41
41
  }
42
42
  const job = sql`${sql(schema)}.${sql("job")}`;
43
- const [resolution] = yield* sql`SELECT EXISTS (
44
- SELECT 1 FROM pg_trigger WHERE tgrelid = to_regclass(${job.compile()[0]}) AND tgname = 'effect_dead_letter_resolution'
45
- ) AS installed`.withoutTransform.pipe(Effect.flatMap(Schema.decodeUnknownEffect(InstalledResolution)));
46
- return resolution?.installed ? undefined : `schema ${schema}, missing dead-letter resolution trigger`;
43
+ const deferrals = sql`${sql(schema)}.${sql("effect_job_deferral")}`;
44
+ const cleanup = sql`${sql(schema)}.${sql("effect_job_deferral_keep_until")}`;
45
+ const stately = sql`${sql(schema)}.${sql("effect_stately_deferral")}()`;
46
+ const missing = yield* sql`SELECT name FROM (VALUES
47
+ ('dead-letter resolution trigger', EXISTS (
48
+ SELECT 1 FROM pg_trigger WHERE tgrelid = to_regclass(${job.compile()[0]}) AND tgname = 'effect_dead_letter_resolution'
49
+ )),
50
+ ('effect_job_deferral', to_regclass(${deferrals.compile()[0]}) IS NOT NULL),
51
+ ('effect_job_deferral_keep_until', to_regclass(${cleanup.compile()[0]}) IS NOT NULL),
52
+ ('effect_stately_deferral()', to_regprocedure(${stately.compile()[0]}) IS NOT NULL),
53
+ ('effect_stately_deferral trigger', EXISTS (
54
+ SELECT 1 FROM pg_trigger WHERE tgrelid = to_regclass(${job.compile()[0]}) AND tgname = 'effect_stately_deferral'
55
+ ))
56
+ ) AS artifacts(name, installed) WHERE NOT installed`.withoutTransform.pipe(Effect.flatMap(Schema.decodeUnknownEffect(MissingArtifacts)));
57
+ return missing.length === 0 ? undefined : `schema ${schema}, missing ${missing.map(({ name }) => name).join(", ")}`;
47
58
  }),
48
59
  };
49
60
  }
@@ -1,20 +1,32 @@
1
- import { Context, Effect, Exit, Layer, type Option, Redacted, type Schema, Scope } from "effect";
2
- import type { ConstructorOptions, JobWithMetadata, SendOptions, StopOptions } from "pg-boss";
1
+ import { Context, Effect, Exit, Layer, type Option, type Redacted, type Schema, Scope } from "effect";
3
2
  import { defineService } from "@shivaedev/service/defineService.ts";
4
3
  import { genericMethod } from "@shivaedev/service/genericMethod.ts";
5
- import { clientErrorLogger } from "#adapters/clientErrorLogger.ts";
6
- import { clientErrorReporter } from "#adapters/clientErrorReporter.ts";
7
- import type { PgBossClientFactory } from "#client.ts";
8
- import type { JobPayloadSchema, JobRegistration, QueueDefinition, RegistrationRequirements } from "#definition.ts";
9
- import type { PgBossClientOptionsError, PgBossError, PgBossPayloadError, PgBossQueueNamesError, PgBossQueueOptionsError } from "#error.ts";
10
- import type { DeadLetteredJob, JobPage, JobPageOptions, JobsHealth, ListedJob, QueueCounts } from "#health.ts";
11
- import { logClientError, subscribeClientErrors } from "#internal/clientErrors.ts";
12
- import { acquireClient, releaseClient } from "#internal/lifecycle.ts";
13
- import { makeService } from "#internal/makeService.ts";
14
- import { registrationName } from "#internal/register.ts";
15
- import { registerReleasedJobs } from "#internal/registerReleasedJobs.ts";
16
- import { validateQueueNames } from "#internal/validateQueueNames.ts";
17
- import { PgBoss } from "#PgBoss.ts";
4
+ import { clientErrorReporter } from "#server/adapters/clientErrorReporter.ts";
5
+ import { jobEngine } from "#server/adapters/jobEngine.ts";
6
+ import { clientEngine } from "#server/adapters/lifecycle.ts";
7
+ import type { PgBossClientFactory } from "#server/client.ts";
8
+ import type { ClientOptions, StopOptions } from "#server/clientOptions.ts";
9
+ import type { JobPayloadSchema, JobRegistration, QueueDefinition, RegistrationRequirements, ScheduleDefinition } from "#server/definition.ts";
10
+ import type { EnqueueOptions } from "#server/enqueueOptions.ts";
11
+ import type {
12
+ PgBossClientOptionsError,
13
+ PgBossError,
14
+ PgBossNotFoundError,
15
+ PgBossPayloadError,
16
+ PgBossQueueNamesError,
17
+ PgBossQueueOptionsError,
18
+ } from "#server/error.ts";
19
+ import type { DeadLetteredJob, JobPage, JobPageOptions, JobsHealth, ListedJob, QueueCounts } from "#server/health.ts";
20
+ import { acquireClient } from "#server/internal/acquireClient.ts";
21
+ import { logClientError, subscribeClientErrors } from "#server/internal/clientErrors.ts";
22
+ import { JobEngine } from "#server/internal/engine.ts";
23
+ import { ClientEngine } from "#server/internal/lifecycle.ts";
24
+ import { makeService } from "#server/internal/makeService.ts";
25
+ import { registrationName } from "#server/internal/register.ts";
26
+ import { registerReleasedJobs } from "#server/internal/registerReleasedJobs.ts";
27
+ import { validateQueueNames } from "#server/internal/validateQueueNames.ts";
28
+ import type { Job } from "#server/job.ts";
29
+ import { PgBoss } from "#server/PgBoss.ts";
18
30
 
19
31
  export interface PgBossService {
20
32
  readonly counts: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<QueueCounts, PgBossError>;
@@ -22,10 +34,11 @@ export interface PgBossService {
22
34
  queue: { readonly name: TName; readonly schema: TPayload },
23
35
  options: JobPageOptions,
24
36
  ) => Effect.Effect<JobPage<DeadLetteredJob<unknown>>, PgBossError | PgBossPayloadError | Schema.SchemaError, TPayload["DecodingServices"]>;
37
+ readonly deleteQueue: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<void, PgBossError | PgBossNotFoundError>;
25
38
  readonly enqueue: <const TName extends string, const TPayload extends JobPayloadSchema, const TQueue extends QueueDefinition<TName, TPayload>>(
26
39
  queue: QueueDefinition<TName, TPayload> & TQueue,
27
40
  payload: NoInfer<Schema.Schema.Type<TPayload>>,
28
- options?: NoInfer<TQueue["key"] extends undefined ? SendOptions : Omit<SendOptions, "singletonKey"> & { readonly singletonKey?: never }>,
41
+ options?: NoInfer<TQueue["key"] extends undefined ? EnqueueOptions : Omit<EnqueueOptions, "singletonKey"> & { readonly singletonKey?: never }>,
29
42
  ) => Effect.Effect<Option.Option<string>, PgBossError | PgBossPayloadError, TPayload["EncodingServices"]>;
30
43
  readonly failedJobs: <const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(
31
44
  queue: { readonly name: TName; readonly schema: TPayload },
@@ -34,12 +47,14 @@ export interface PgBossService {
34
47
  readonly getJob: <const TName extends string, const TPayload extends JobPayloadSchema | typeof Schema.Null>(
35
48
  queue: { readonly name: TName; readonly schema: TPayload },
36
49
  id: string,
37
- ) => Effect.Effect<Option.Option<JobWithMetadata<unknown>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
50
+ ) => Effect.Effect<Option.Option<Job<unknown>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
38
51
  readonly health: (queues?: readonly Pick<QueueDefinition, "name">[]) => Effect.Effect<JobsHealth, PgBossError>;
52
+ readonly refreshQueueStats: (queue?: Pick<QueueDefinition, "name">) => Effect.Effect<void, PgBossError>;
39
53
  readonly retry: (queue: Pick<QueueDefinition, "name">, id: string) => Effect.Effect<void, PgBossError>;
54
+ readonly unschedule: (schedule: Pick<ScheduleDefinition, "name" | "scheduleOptions">) => Effect.Effect<void, PgBossError | PgBossNotFoundError>;
40
55
  }
41
56
 
42
- export type PgBossOptions = Omit<ConstructorOptions, "connectionString"> & {
57
+ export type PgBossOptions = Omit<ClientOptions, "connectionString"> & {
43
58
  readonly connectionString?: Redacted.Redacted<string>;
44
59
  readonly idleTimeoutMillis?: number;
45
60
  readonly maxLifetimeSeconds?: number;
@@ -49,31 +64,7 @@ export type PgBossOptions = Omit<ConstructorOptions, "connectionString"> & {
49
64
  };
50
65
 
51
66
  export function pgBossLayer(options: PgBossOptions): Layer.Layer<PgBoss, PgBossError | PgBossClientOptionsError> {
52
- const { connectionString, clientFactory, clientCacheKey, stop, ...settings } = options;
53
- const constructorOptions = {
54
- ...settings,
55
- idleTimeoutMillis: settings.idleTimeoutMillis ?? 60_000,
56
- maxLifetimeSeconds: settings.maxLifetimeSeconds ?? 600,
57
- ...(connectionString === undefined ? {} : { connectionString: Redacted.value(connectionString) }),
58
- };
59
- return Layer.effect(
60
- PgBoss,
61
- Effect.gen(function* () {
62
- const report = yield* clientErrorLogger();
63
- const acquired = yield* Effect.acquireRelease(
64
- acquireClient(
65
- {
66
- clientCacheKey,
67
- clientFactory,
68
- constructor: constructorOptions,
69
- },
70
- report,
71
- ),
72
- (client) => releaseClient(client, stop),
73
- );
74
- return { ...acquired, schema: settings.schema, stop };
75
- }),
76
- );
67
+ return Layer.effect(PgBoss, acquireClient(options)).pipe(Layer.provide(Layer.succeed(ClientEngine, clientEngine)));
77
68
  }
78
69
 
79
70
  export interface PgBossLayerOptions<TRegistrations extends readonly JobRegistration[], TErrorRequirements> {
@@ -93,43 +84,56 @@ export interface PgBossDefinition<TIdentifier extends string = string> extends C
93
84
  }
94
85
 
95
86
  export function makePgBoss<const TIdentifier extends string>(identifier: TIdentifier, queueNames?: readonly string[]): PgBossDefinition<TIdentifier> {
96
- function definition<R>(options: PgBossLayerOptions<readonly JobRegistration[], R>, dependencies: Context.Context<R>) {
87
+ function definition<R, E>(
88
+ options: PgBossLayerOptions<readonly JobRegistration<R>[], E>,
89
+ dependencies: Context.Context<Exclude<R, TIdentifier> | E>,
90
+ ) {
97
91
  return defineService({
98
92
  id: identifier,
99
93
  initialize: Effect.gen(function* () {
100
94
  yield* validateQueueNames(options.jobs, queueNames);
101
95
  const acquired = yield* PgBoss;
102
96
  const workerScope = yield* Scope.make();
103
- const service = makeService(acquired.client, options.jobs.map(registrationName), acquired.schema);
104
- const context = Context.add(dependencies, Service, service);
105
- const reportError = options.onError ?? logClientError;
106
- const report = yield* clientErrorReporter(reportError).pipe(Effect.provide(context));
107
- const unsubscribe = subscribeClientErrors(acquired.client, report);
108
- yield* Effect.addFinalizer(() => Scope.close(workerScope, Exit.void).pipe(Effect.ensuring(Effect.sync(unsubscribe))));
109
- yield* registerReleasedJobs(acquired.client, options.jobs, context, acquired.reused, acquired.schema, acquired.stop, options.retired).pipe(
110
- Effect.provideService(Scope.Scope, workerScope),
111
- Effect.provide(dependencies),
97
+ const service = yield* makeService(acquired.client, options.jobs.map(registrationName), acquired.schema).pipe(
98
+ Effect.provideService(JobEngine, jobEngine(acquired.client, acquired.schema)),
112
99
  );
100
+ yield* Effect.gen(function* () {
101
+ const context = yield* Effect.context<R | E>();
102
+ const reportError = options.onError ?? logClientError;
103
+ const report = yield* clientErrorReporter(reportError).pipe(Effect.provide(context));
104
+ const unsubscribe = subscribeClientErrors(acquired.client, report);
105
+ yield* Effect.addFinalizer(() => Scope.close(workerScope, Exit.void).pipe(Effect.ensuring(Effect.sync(unsubscribe))));
106
+ yield* registerReleasedJobs(acquired.client, options.jobs, context, acquired.reused, acquired.schema, acquired.stop, options.retired).pipe(
107
+ Effect.provideService(Scope.Scope, workerScope),
108
+ );
109
+ }).pipe(Effect.provideService(Service, service), Effect.provide(dependencies));
113
110
  return service;
114
111
  }),
115
112
  methods: (service) => ({
116
113
  counts: service.counts,
117
114
  deadLetteredJobs: genericMethod(service.deadLetteredJobs),
115
+ deleteQueue: service.deleteQueue,
118
116
  enqueue: genericMethod(service.enqueue),
119
117
  failedJobs: genericMethod(service.failedJobs),
120
118
  getJob: genericMethod(service.getJob),
121
119
  health: service.health,
120
+ refreshQueueStats: service.refreshQueueStats,
122
121
  retry: service.retry,
122
+ unschedule: service.unschedule,
123
123
  }),
124
124
  requires: [PgBoss],
125
125
  });
126
126
  }
127
- const Service: Context.Service<TIdentifier, PgBossService> = definition({ jobs: [] }, Context.empty());
128
- function layer<const TRegistrations extends readonly JobRegistration[], TErrorRequirements = never>(
129
- options: PgBossLayerOptions<TRegistrations, TErrorRequirements>,
130
- ) {
131
- type Requirements = Exclude<RegistrationRequirements<TRegistrations>, TIdentifier> | TErrorRequirements;
132
- return Layer.unwrap(Effect.map(Effect.context<Requirements>(), (dependencies) => definition(options, dependencies).layer));
127
+ const Service: Context.Service<TIdentifier, PgBossService> = definition<never, never>({ jobs: [] }, Context.empty());
128
+ function layer<const TRegistrations extends readonly JobRegistration[], E = never>(
129
+ options: PgBossLayerOptions<TRegistrations, E>,
130
+ ): Layer.Layer<
131
+ TIdentifier,
132
+ PgBossError | PgBossQueueNamesError | PgBossQueueOptionsError,
133
+ PgBoss | Exclude<RegistrationRequirements<TRegistrations>, TIdentifier> | E
134
+ >;
135
+ function layer<R = never, E = never>(options: PgBossLayerOptions<readonly JobRegistration<R>[], E>) {
136
+ return Layer.unwrap(Effect.map(Effect.context<Exclude<R, TIdentifier> | E>(), (dependencies) => definition(options, dependencies).layer));
133
137
  }
134
138
  return Object.assign(Service, { layer });
135
139
  }
@@ -1,19 +1,10 @@
1
- import { type DateTime, Duration, Effect, Redacted } from "effect";
2
- import type { PgBoss } from "pg-boss";
3
- import { testingDueNow } from "#adapters/testingDueNow.ts";
4
- import type { PgBossClientFactory } from "#client.ts";
5
- import { defaultClientFactory } from "#defaultClientFactory.ts";
6
- import type { JobPayloadSchema, QueueDefinition } from "#definition.ts";
7
- import { PgBossTestingError } from "#error.ts";
8
- import { type TestingFetches, testingFetches } from "#internal/adapters/testingFetches.ts";
9
- import { testingClient } from "#internal/testingClient.ts";
10
- import { testingDeferrals } from "#internal/testingDeferrals.ts";
11
- import { type TestingWork, testingIdle } from "#internal/testingIdle.ts";
12
- import { testingOperation, testingReadout } from "#internal/testingReadout.ts";
13
- import { testingSchedules } from "#internal/testingSchedules.ts";
14
- import { testingSignal } from "#internal/testingSignal.ts";
15
- import { testingSnapshot } from "#internal/testingSnapshot.ts";
16
- import { testingWaits } from "#internal/testingWaits.ts";
1
+ import { type DateTime, type Duration, Effect, type Tracer } from "effect";
2
+ import { testingController } from "#server/adapters/testingController.ts";
3
+ import type { JobPayloadSchema, QueueDefinition } from "#server/definition.ts";
4
+
5
+ export function makePgBossTesting(options: PgBossTestingOptions = {}) {
6
+ return testingController(options);
7
+ }
17
8
 
18
9
  export type SnapshotQueue = Pick<QueueDefinition<string, JobPayloadSchema>, "name" | "schema">;
19
10
 
@@ -22,7 +13,7 @@ export interface UnfinishedJob<TQueue extends SnapshotQueue> {
22
13
  readonly id: string;
23
14
  readonly queue: TQueue["name"];
24
15
  readonly startAfter: DateTime.Utc;
25
- readonly state: "active" | "created" | "failed" | "retry";
16
+ readonly state: "active" | "created" | "deferred" | "failed" | "retry";
26
17
  }
27
18
 
28
19
  export interface PgBossTestingWaitOptions {
@@ -35,97 +26,15 @@ export interface PgBossTestingOptions {
35
26
  readonly retryPolicy?: typeof testRetryPolicy;
36
27
  }
37
28
 
38
- export function makePgBossTesting(options: PgBossTestingOptions = {}) {
39
- let current: PgBoss | undefined;
40
- let fetches: TestingFetches | undefined;
41
- let schema = "pgboss";
42
- const signal = testingSignal();
43
- const work: TestingWork = { batches: new Set(), queues: new Set() };
44
- const controls = {
45
- changed: signal.changed,
46
- expirations: new Map<string, number>(),
47
- expirySeconds: new Map<string, number>(),
48
- failures: new Set<string>(),
49
- retryPolicy: options.retryPolicy ?? {},
50
- work,
51
- };
52
- function client(): PgBoss {
53
- if (current === undefined) {
54
- throw new Error("Provide the testing clientFactory to a jobs Layer first");
55
- }
56
- return current;
57
- }
58
- const clientFactory: PgBossClientFactory = (clientOptions) => {
59
- if (current !== undefined) {
60
- throw new Error("A testing controller owns one jobs client; create a controller per runtime");
61
- }
62
- schema = clientOptions.schema ?? "pgboss";
63
- current = defaultClientFactory({ ...clientOptions, "__test__enableSpies": true });
64
- fetches = testingFetches(current.getDb(), signal.changed);
65
- return testingClient(current, clientOptions.schema ?? "pgboss", controls);
66
- };
67
- return {
68
- ...testingDeferrals(client),
69
- ...testingDueNow(client, () => schema, signal.changed),
70
- ...testingSchedules(client, signal.changed),
71
- ...testingWaits(client, () => fetches, signal),
72
- checkBatchWindow: (queue: Pick<QueueDefinition, "name" | "workerOptions">, millisecondsPerJob: number) =>
73
- testingOperation(
74
- "checkBatchWindow",
75
- async () => {
76
- const stored = await client().getQueue(queue.name);
77
- if (stored === null) {
78
- throw new Error("Queue is not registered");
79
- }
80
- if (stored.expireInSeconds === undefined) {
81
- throw new Error("Queue has no expiry window");
82
- }
83
- if (!Number.isFinite(millisecondsPerJob) || millisecondsPerJob < 0) {
84
- throw new RangeError("Job duration must be nonnegative and finite");
85
- }
86
- const required = (queue.workerOptions.batchSize ?? 10) * millisecondsPerJob;
87
- if (required >= stored.expireInSeconds * 1000) {
88
- throw new Error("Sequential batch work must fit within the queue expiry window");
89
- }
90
- },
91
- queue.name,
92
- ),
93
- checkSchemaVersion: (expected: number) =>
94
- testingOperation("checkSchemaVersion", async () => {
95
- if ((await client().schemaVersion()) !== expected) {
96
- throw new Error(`Expected pg-boss schema version ${expected}`);
97
- }
98
- }),
99
- clientFactory,
100
- expireAfter: (queue: Pick<QueueDefinition, "name">, attempts: number) =>
101
- Effect.try({
102
- catch: (original) => new PgBossTestingError({ operation: "expireAfter", original: Redacted.make(original), queue: queue.name }),
103
- try: () => {
104
- if (!Number.isSafeInteger(attempts) || attempts < 1) {
105
- throw new RangeError("Attempts must be a positive integer");
106
- }
107
- controls.expirations.set(queue.name, attempts);
108
- },
109
- }),
110
- expireIn: (queue: Pick<QueueDefinition, "name">, duration: Duration.Input) =>
111
- Effect.try({
112
- catch: (original) => new PgBossTestingError({ operation: "expireIn", original: Redacted.make(original), queue: queue.name }),
113
- try: () => {
114
- const milliseconds = Duration.toMillis(Duration.fromInputUnsafe(duration));
115
- if (!Number.isFinite(milliseconds) || milliseconds < 1000) {
116
- throw new RangeError("Expiry must be finite and at least one second");
117
- }
118
- controls.expirySeconds.set(queue.name, Math.ceil(milliseconds / 1000));
119
- },
120
- }),
121
- failNextSend: (queue: Pick<QueueDefinition, "name">) => Effect.sync(() => controls.failures.add(queue.name)).pipe(Effect.asVoid),
122
- jobs: testingReadout(client),
123
- revision: signal.revision,
124
- schemaVersion: testingOperation("schemaVersion", () => client().schemaVersion()),
125
- snapshot: testingSnapshot(client, () => schema),
126
- waitForChange: signal.waitForChange,
127
- waitForIdle: testingIdle(client, () => schema, work, signal),
128
- };
29
+ export function linkedWorkerSpans(sender: Pick<Tracer.AnySpan, "spanId" | "traceId">, spans: readonly Tracer.Span[]) {
30
+ return Effect.sync(() =>
31
+ spans.filter(
32
+ (span) =>
33
+ span.kind === "consumer"
34
+ && span.attributes.get("messaging.system") === "pg-boss"
35
+ && span.links.some((link) => link.span.spanId === sender.spanId && link.span.traceId === sender.traceId),
36
+ ),
37
+ );
129
38
  }
130
39
 
131
40
  export type PgBossTesting = ReturnType<typeof makePgBossTesting>;