@shivaedev/jobs 0.30.0 → 0.32.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 (447) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +88 -24
  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/inspection.d.ts +5 -0
  39. package/dist/server/adapters/inspection.d.ts.map +1 -0
  40. package/dist/server/adapters/inspection.js +25 -0
  41. package/dist/server/adapters/inspection.js.map +1 -0
  42. package/dist/server/adapters/inspectionChanges.d.ts +7 -0
  43. package/dist/server/adapters/inspectionChanges.d.ts.map +1 -0
  44. package/dist/server/adapters/inspectionChanges.js +23 -0
  45. package/dist/server/adapters/inspectionChanges.js.map +1 -0
  46. package/dist/server/adapters/inspectionDeferrals.d.ts +10 -0
  47. package/dist/server/adapters/inspectionDeferrals.d.ts.map +1 -0
  48. package/dist/server/adapters/inspectionDeferrals.js +13 -0
  49. package/dist/server/adapters/inspectionDeferrals.js.map +1 -0
  50. package/dist/server/adapters/inspectionJobs.d.ts +50 -0
  51. package/dist/server/adapters/inspectionJobs.d.ts.map +1 -0
  52. package/dist/server/adapters/inspectionJobs.js +21 -0
  53. package/dist/server/adapters/inspectionJobs.js.map +1 -0
  54. package/dist/server/adapters/inspectionOperation.d.ts +3 -0
  55. package/dist/server/adapters/inspectionOperation.d.ts.map +1 -0
  56. package/dist/server/adapters/inspectionOperation.js +6 -0
  57. package/dist/server/adapters/inspectionOperation.js.map +1 -0
  58. package/dist/server/adapters/inspectionPlan.d.ts +3 -0
  59. package/dist/server/adapters/inspectionPlan.d.ts.map +1 -0
  60. package/dist/server/adapters/inspectionPlan.js +20 -0
  61. package/dist/server/adapters/inspectionPlan.js.map +1 -0
  62. package/dist/server/adapters/inspectionReads.d.ts +59 -0
  63. package/dist/server/adapters/inspectionReads.d.ts.map +1 -0
  64. package/dist/server/adapters/inspectionReads.js +44 -0
  65. package/dist/server/adapters/inspectionReads.js.map +1 -0
  66. package/dist/server/adapters/inspectionSnapshot.d.ts +6 -0
  67. package/dist/server/adapters/inspectionSnapshot.d.ts.map +1 -0
  68. package/dist/server/{internal/testingSnapshot.js → adapters/inspectionSnapshot.js} +10 -8
  69. package/dist/server/adapters/inspectionSnapshot.js.map +1 -0
  70. package/dist/server/adapters/installSchema.d.ts +1 -1
  71. package/dist/server/adapters/installSchema.d.ts.map +1 -1
  72. package/dist/server/adapters/installSchema.js +1 -1
  73. package/dist/server/adapters/installSchema.js.map +1 -1
  74. package/dist/server/adapters/jobEngine.d.ts +5 -0
  75. package/dist/server/adapters/jobEngine.d.ts.map +1 -0
  76. package/dist/server/adapters/jobEngine.js +46 -0
  77. package/dist/server/adapters/jobEngine.js.map +1 -0
  78. package/dist/server/adapters/lifecycle.d.ts +11 -0
  79. package/dist/server/adapters/lifecycle.d.ts.map +1 -0
  80. package/dist/server/adapters/lifecycle.js +48 -0
  81. package/dist/server/adapters/lifecycle.js.map +1 -0
  82. package/dist/server/adapters/listJobs.d.ts +5 -0
  83. package/dist/server/adapters/listJobs.d.ts.map +1 -0
  84. package/dist/server/adapters/listJobs.js +37 -0
  85. package/dist/server/adapters/listJobs.js.map +1 -0
  86. package/dist/server/adapters/payloadIdentity.d.ts +3 -0
  87. package/dist/server/adapters/payloadIdentity.d.ts.map +1 -0
  88. package/dist/server/adapters/payloadIdentity.js +14 -0
  89. package/dist/server/adapters/payloadIdentity.js.map +1 -0
  90. package/dist/server/adapters/queueAdministration.d.ts +4 -0
  91. package/dist/server/adapters/queueAdministration.d.ts.map +1 -0
  92. package/dist/server/adapters/queueAdministration.js +42 -0
  93. package/dist/server/adapters/queueAdministration.js.map +1 -0
  94. package/dist/server/{internal/testingSignal.d.ts → adapters/queueSignal.d.ts} +2 -2
  95. package/dist/server/adapters/queueSignal.d.ts.map +1 -0
  96. package/dist/server/{internal/testingSignal.js → adapters/queueSignal.js} +2 -2
  97. package/dist/server/adapters/queueSignal.js.map +1 -0
  98. package/dist/server/adapters/registerWorker.d.ts +5 -3
  99. package/dist/server/adapters/registerWorker.d.ts.map +1 -1
  100. package/dist/server/adapters/registerWorker.js +9 -6
  101. package/dist/server/adapters/registerWorker.js.map +1 -1
  102. package/dist/server/adapters/retireJobs.d.ts +3 -3
  103. package/dist/server/adapters/retireJobs.d.ts.map +1 -1
  104. package/dist/server/adapters/retireJobs.js +3 -3
  105. package/dist/server/adapters/retireJobs.js.map +1 -1
  106. package/dist/server/adapters/schemaIndexBuilds.d.ts +2 -2
  107. package/dist/server/adapters/schemaIndexBuilds.d.ts.map +1 -1
  108. package/dist/server/adapters/schemaIndexBuilds.js.map +1 -1
  109. package/dist/server/adapters/settleDeferral.d.ts +7 -0
  110. package/dist/server/adapters/settleDeferral.d.ts.map +1 -0
  111. package/dist/server/{internal → adapters}/settleDeferral.js +2 -2
  112. package/dist/server/adapters/settleDeferral.js.map +1 -0
  113. package/dist/server/adapters/testingClient.d.ts +13 -0
  114. package/dist/server/adapters/testingClient.d.ts.map +1 -0
  115. package/dist/server/{internal → adapters}/testingClient.js +27 -48
  116. package/dist/server/adapters/testingClient.js.map +1 -0
  117. package/dist/server/adapters/testingController.d.ts +79 -0
  118. package/dist/server/adapters/testingController.d.ts.map +1 -0
  119. package/dist/server/adapters/testingController.js +108 -0
  120. package/dist/server/adapters/testingController.js.map +1 -0
  121. package/dist/server/adapters/testingDueNow.d.ts +3 -3
  122. package/dist/server/adapters/testingDueNow.d.ts.map +1 -1
  123. package/dist/server/adapters/testingDueNow.js +2 -2
  124. package/dist/server/adapters/testingDueNow.js.map +1 -1
  125. package/dist/server/adapters/testingEngine.d.ts +5 -0
  126. package/dist/server/adapters/testingEngine.d.ts.map +1 -0
  127. package/dist/server/adapters/testingEngine.js +12 -0
  128. package/dist/server/adapters/testingEngine.js.map +1 -0
  129. package/dist/server/adapters/testingExpirations.d.ts +6 -4
  130. package/dist/server/adapters/testingExpirations.d.ts.map +1 -1
  131. package/dist/server/adapters/testingExpirations.js.map +1 -1
  132. package/dist/server/adapters/testingInspectionClient.d.ts +5 -0
  133. package/dist/server/adapters/testingInspectionClient.d.ts.map +1 -0
  134. package/dist/server/adapters/testingInspectionClient.js +52 -0
  135. package/dist/server/adapters/testingInspectionClient.js.map +1 -0
  136. package/dist/server/adapters/transactionDb.d.ts +2 -2
  137. package/dist/server/adapters/transactionDb.d.ts.map +1 -1
  138. package/dist/server/adapters/transactionDb.js.map +1 -1
  139. package/dist/server/client.d.ts +95 -18
  140. package/dist/server/client.d.ts.map +1 -1
  141. package/dist/server/clientOptions.d.ts +74 -0
  142. package/dist/server/clientOptions.d.ts.map +1 -0
  143. package/dist/server/clientOptions.js +2 -0
  144. package/dist/server/clientOptions.js.map +1 -0
  145. package/dist/server/defineSchedule.d.ts +1 -1
  146. package/dist/server/defineSchedule.d.ts.map +1 -1
  147. package/dist/server/defineSchedule.js +2 -1
  148. package/dist/server/defineSchedule.js.map +1 -1
  149. package/dist/server/definition.d.ts +29 -26
  150. package/dist/server/definition.d.ts.map +1 -1
  151. package/dist/server/definition.js +5 -2
  152. package/dist/server/definition.js.map +1 -1
  153. package/dist/server/engineClient.d.ts +21 -0
  154. package/dist/server/engineClient.d.ts.map +1 -0
  155. package/dist/server/engineClient.js +2 -0
  156. package/dist/server/engineClient.js.map +1 -0
  157. package/dist/server/enqueueOptions.d.ts +28 -0
  158. package/dist/server/enqueueOptions.d.ts.map +1 -0
  159. package/dist/server/enqueueOptions.js +2 -0
  160. package/dist/server/enqueueOptions.js.map +1 -0
  161. package/dist/server/error.d.ts +11 -1
  162. package/dist/server/error.d.ts.map +1 -1
  163. package/dist/server/error.js +8 -1
  164. package/dist/server/error.js.map +1 -1
  165. package/dist/server/health.d.ts +2 -2
  166. package/dist/server/health.d.ts.map +1 -1
  167. package/dist/server/inspection.d.ts +102 -0
  168. package/dist/server/inspection.d.ts.map +1 -0
  169. package/dist/server/inspection.js +30 -0
  170. package/dist/server/inspection.js.map +1 -0
  171. package/dist/server/internal/acquireClient.d.ts +11 -0
  172. package/dist/server/internal/acquireClient.d.ts.map +1 -0
  173. package/dist/server/internal/acquireClient.js +21 -0
  174. package/dist/server/internal/acquireClient.js.map +1 -0
  175. package/dist/server/internal/adapters/testingFetches.d.ts +2 -2
  176. package/dist/server/internal/adapters/testingFetches.d.ts.map +1 -1
  177. package/dist/server/internal/adapters/testingFetches.js.map +1 -1
  178. package/dist/server/internal/clientErrors.d.ts +1 -1
  179. package/dist/server/internal/clientErrors.d.ts.map +1 -1
  180. package/dist/server/internal/countsFor.d.ts +3 -3
  181. package/dist/server/internal/countsFor.d.ts.map +1 -1
  182. package/dist/server/internal/countsFor.js +2 -2
  183. package/dist/server/internal/countsFor.js.map +1 -1
  184. package/dist/server/internal/deadLetterResolutionPlan.js +1 -1
  185. package/dist/server/internal/deadLetterResolutionPlan.js.map +1 -1
  186. package/dist/server/internal/deadlineOf.d.ts +2 -2
  187. package/dist/server/internal/deadlineOf.d.ts.map +1 -1
  188. package/dist/server/internal/deadlineOf.js.map +1 -1
  189. package/dist/server/internal/deferrableAttempt.d.ts +4 -5
  190. package/dist/server/internal/deferrableAttempt.d.ts.map +1 -1
  191. package/dist/server/internal/deferrableAttempt.js +5 -14
  192. package/dist/server/internal/deferrableAttempt.js.map +1 -1
  193. package/dist/server/internal/deferral.d.ts +2 -4
  194. package/dist/server/internal/deferral.d.ts.map +1 -1
  195. package/dist/server/internal/deferral.js +0 -1
  196. package/dist/server/internal/deferral.js.map +1 -1
  197. package/dist/server/internal/deferralStorePlan.js +2 -2
  198. package/dist/server/internal/deferralStorePlan.js.map +1 -1
  199. package/dist/server/internal/definitionOptions.d.ts +7 -7
  200. package/dist/server/internal/definitionOptions.d.ts.map +1 -1
  201. package/dist/server/internal/engine.d.ts +25 -0
  202. package/dist/server/internal/engine.d.ts.map +1 -0
  203. package/dist/server/internal/engine.js +6 -0
  204. package/dist/server/internal/engine.js.map +1 -0
  205. package/dist/server/internal/enqueueFor.d.ts +2 -2
  206. package/dist/server/internal/enqueueFor.d.ts.map +1 -1
  207. package/dist/server/internal/enqueueFor.js +14 -4
  208. package/dist/server/internal/enqueueFor.js.map +1 -1
  209. package/dist/server/internal/ensureQueue.d.ts +2 -3
  210. package/dist/server/internal/ensureQueue.d.ts.map +1 -1
  211. package/dist/server/internal/ensureQueue.js +2 -2
  212. package/dist/server/internal/ensureQueue.js.map +1 -1
  213. package/dist/server/internal/healthFor.d.ts +3 -3
  214. package/dist/server/internal/healthFor.d.ts.map +1 -1
  215. package/dist/server/internal/healthFor.js +2 -2
  216. package/dist/server/internal/healthFor.js.map +1 -1
  217. package/dist/server/internal/jobControl.d.ts +9 -4
  218. package/dist/server/internal/jobControl.d.ts.map +1 -1
  219. package/dist/server/internal/jobControl.js +13 -40
  220. package/dist/server/internal/jobControl.js.map +1 -1
  221. package/dist/server/internal/jobListings.d.ts +16 -0
  222. package/dist/server/internal/jobListings.d.ts.map +1 -0
  223. package/dist/server/internal/jobListings.js +52 -0
  224. package/dist/server/internal/jobListings.js.map +1 -0
  225. package/dist/server/internal/jobStorePlans.d.ts.map +1 -1
  226. package/dist/server/internal/jobStorePlans.js +4 -3
  227. package/dist/server/internal/jobStorePlans.js.map +1 -1
  228. package/dist/server/internal/lifecycle.d.ts +11 -7
  229. package/dist/server/internal/lifecycle.d.ts.map +1 -1
  230. package/dist/server/internal/lifecycle.js +2 -49
  231. package/dist/server/internal/lifecycle.js.map +1 -1
  232. package/dist/server/internal/makeService.d.ts +5 -3
  233. package/dist/server/internal/makeService.d.ts.map +1 -1
  234. package/dist/server/internal/makeService.js +18 -13
  235. package/dist/server/internal/makeService.js.map +1 -1
  236. package/dist/server/internal/register.d.ts +5 -5
  237. package/dist/server/internal/register.d.ts.map +1 -1
  238. package/dist/server/internal/register.js +5 -9
  239. package/dist/server/internal/register.js.map +1 -1
  240. package/dist/server/internal/registerReleasedJobs.d.ts +4 -4
  241. package/dist/server/internal/registerReleasedJobs.d.ts.map +1 -1
  242. package/dist/server/internal/registerReleasedJobs.js +2 -2
  243. package/dist/server/internal/registerReleasedJobs.js.map +1 -1
  244. package/dist/server/internal/retryWake.d.ts +1 -1
  245. package/dist/server/internal/retryWake.d.ts.map +1 -1
  246. package/dist/server/internal/retryWake.js +2 -2
  247. package/dist/server/internal/retryWake.js.map +1 -1
  248. package/dist/server/internal/runQueueWorker.d.ts +4 -4
  249. package/dist/server/internal/runQueueWorker.d.ts.map +1 -1
  250. package/dist/server/internal/runQueueWorker.js +5 -5
  251. package/dist/server/internal/runQueueWorker.js.map +1 -1
  252. package/dist/server/internal/storedRows.d.ts +2 -2
  253. package/dist/server/internal/storedRows.d.ts.map +1 -1
  254. package/dist/server/internal/storedRows.js +2 -2
  255. package/dist/server/internal/storedRows.js.map +1 -1
  256. package/dist/server/internal/testingIdle.d.ts +4 -3
  257. package/dist/server/internal/testingIdle.d.ts.map +1 -1
  258. package/dist/server/internal/testingIdle.js +5 -25
  259. package/dist/server/internal/testingIdle.js.map +1 -1
  260. package/dist/server/internal/testingOperation.d.ts +5 -0
  261. package/dist/server/internal/testingOperation.d.ts.map +1 -0
  262. package/dist/server/internal/testingOperation.js +12 -0
  263. package/dist/server/internal/testingOperation.js.map +1 -0
  264. package/dist/server/internal/testingSchedules.d.ts +9 -6
  265. package/dist/server/internal/testingSchedules.d.ts.map +1 -1
  266. package/dist/server/internal/testingSchedules.js +14 -9
  267. package/dist/server/internal/testingSchedules.js.map +1 -1
  268. package/dist/server/internal/testingWaits.d.ts +12 -8
  269. package/dist/server/internal/testingWaits.d.ts.map +1 -1
  270. package/dist/server/internal/testingWaits.js +6 -7
  271. package/dist/server/internal/testingWaits.js.map +1 -1
  272. package/dist/server/internal/tracing.d.ts +2 -2
  273. package/dist/server/internal/tracing.d.ts.map +1 -1
  274. package/dist/server/internal/tracing.js.map +1 -1
  275. package/dist/server/internal/validateQueueNames.d.ts +2 -2
  276. package/dist/server/internal/validateQueueNames.d.ts.map +1 -1
  277. package/dist/server/internal/validateQueueNames.js +1 -1
  278. package/dist/server/internal/validateQueueNames.js.map +1 -1
  279. package/dist/server/internal/waitForBatchExpiry.d.ts +4 -4
  280. package/dist/server/internal/waitForBatchExpiry.d.ts.map +1 -1
  281. package/dist/server/internal/waitForBatchExpiry.js +1 -1
  282. package/dist/server/internal/waitForBatchExpiry.js.map +1 -1
  283. package/dist/server/job.d.ts +42 -0
  284. package/dist/server/job.d.ts.map +1 -0
  285. package/dist/server/job.js +2 -0
  286. package/dist/server/job.js.map +1 -0
  287. package/dist/server/jobModule.d.ts +6 -4
  288. package/dist/server/jobModule.d.ts.map +1 -1
  289. package/dist/server/jobModule.js +7 -5
  290. package/dist/server/jobModule.js.map +1 -1
  291. package/dist/server/queueOptions.d.ts +19 -0
  292. package/dist/server/queueOptions.d.ts.map +1 -0
  293. package/dist/server/queueOptions.js +2 -0
  294. package/dist/server/queueOptions.js.map +1 -0
  295. package/dist/server/readJobFailure.d.ts +5 -0
  296. package/dist/server/readJobFailure.d.ts.map +1 -0
  297. package/dist/server/readJobFailure.js +8 -0
  298. package/dist/server/readJobFailure.js.map +1 -0
  299. package/dist/server/schema.d.ts +1 -1
  300. package/dist/server/schema.d.ts.map +1 -1
  301. package/dist/server/schema.js +23 -7
  302. package/dist/server/schema.js.map +1 -1
  303. package/dist/server/service.d.ts +17 -12
  304. package/dist/server/service.d.ts.map +1 -1
  305. package/dist/server/service.js +19 -27
  306. package/dist/server/service.js.map +1 -1
  307. package/dist/server/testing.d.ts +63 -67
  308. package/dist/server/testing.d.ts.map +1 -1
  309. package/dist/server/testing.js +5 -97
  310. package/dist/server/testing.js.map +1 -1
  311. package/dist/server/workerOptions.d.ts +25 -0
  312. package/dist/server/workerOptions.d.ts.map +1 -0
  313. package/dist/server/workerOptions.js +2 -0
  314. package/dist/server/workerOptions.js.map +1 -0
  315. package/package.json +11 -16
  316. package/src/display.ts +12 -0
  317. package/src/server/ClientDatabase.ts +7 -0
  318. package/src/server/PgBoss.ts +2 -2
  319. package/src/server/adapters/batchClockOffset.ts +8 -5
  320. package/src/server/{internal → adapters}/batchHandler.ts +13 -13
  321. package/src/server/{internal → adapters}/clientCache.ts +10 -22
  322. package/src/server/adapters/clientErrorLogger.ts +1 -1
  323. package/src/server/{defaultClientFactory.ts → adapters/defaultClientFactory.ts} +4 -2
  324. package/src/server/adapters/deferralCount.ts +5 -5
  325. package/src/server/{internal → adapters}/expireAttempt.ts +4 -3
  326. package/src/server/adapters/inspection.ts +31 -0
  327. package/src/server/adapters/inspectionChanges.ts +31 -0
  328. package/src/server/adapters/inspectionDeferrals.ts +20 -0
  329. package/src/server/adapters/inspectionJobs.ts +28 -0
  330. package/src/server/adapters/inspectionOperation.ts +6 -0
  331. package/src/server/adapters/inspectionPlan.ts +21 -0
  332. package/src/server/adapters/inspectionReads.ts +55 -0
  333. package/src/server/{internal/testingSnapshot.ts → adapters/inspectionSnapshot.ts} +16 -18
  334. package/src/server/adapters/installSchema.ts +2 -2
  335. package/src/server/adapters/jobEngine.ts +55 -0
  336. package/src/server/adapters/lifecycle.ts +67 -0
  337. package/src/server/adapters/listJobs.ts +43 -0
  338. package/src/server/adapters/payloadIdentity.ts +15 -0
  339. package/src/server/adapters/queueAdministration.ts +47 -0
  340. package/src/server/{internal/testingSignal.ts → adapters/queueSignal.ts} +1 -1
  341. package/src/server/adapters/registerWorker.ts +17 -12
  342. package/src/server/adapters/retireJobs.ts +5 -5
  343. package/src/server/adapters/schemaIndexBuilds.ts +2 -2
  344. package/src/server/{internal → adapters}/settleDeferral.ts +5 -5
  345. package/src/server/{internal → adapters}/testingClient.ts +24 -40
  346. package/src/server/adapters/testingController.ts +125 -0
  347. package/src/server/adapters/testingDueNow.ts +5 -5
  348. package/src/server/adapters/testingEngine.ts +15 -0
  349. package/src/server/adapters/testingExpirations.ts +6 -4
  350. package/src/server/adapters/testingInspectionClient.ts +70 -0
  351. package/src/server/adapters/transactionDb.ts +2 -2
  352. package/src/server/client.ts +86 -30
  353. package/src/server/clientOptions.ts +80 -0
  354. package/src/server/defineSchedule.ts +3 -2
  355. package/src/server/definition.ts +38 -29
  356. package/src/server/engineClient.ts +22 -0
  357. package/src/server/enqueueOptions.ts +25 -0
  358. package/src/server/error.ts +18 -2
  359. package/src/server/health.ts +2 -2
  360. package/src/server/inspection.ts +50 -0
  361. package/src/server/internal/acquireClient.ts +26 -0
  362. package/src/server/internal/adapters/testingFetches.ts +2 -2
  363. package/src/server/internal/clientErrors.ts +1 -1
  364. package/src/server/internal/countsFor.ts +5 -5
  365. package/src/server/internal/deadLetterResolutionPlan.ts +1 -1
  366. package/src/server/internal/deadlineOf.ts +2 -2
  367. package/src/server/internal/deferrableAttempt.ts +5 -22
  368. package/src/server/internal/deferral.ts +2 -4
  369. package/src/server/internal/deferralStorePlan.ts +2 -2
  370. package/src/server/internal/definitionOptions.ts +1 -1
  371. package/src/server/internal/engine.ts +35 -0
  372. package/src/server/internal/enqueueFor.ts +19 -6
  373. package/src/server/internal/ensureQueue.ts +5 -6
  374. package/src/server/internal/healthFor.ts +4 -4
  375. package/src/server/internal/jobControl.ts +15 -50
  376. package/src/server/internal/jobListings.ts +85 -0
  377. package/src/server/internal/jobStorePlans.ts +4 -3
  378. package/src/server/internal/lifecycle.ts +14 -55
  379. package/src/server/internal/makeService.ts +24 -15
  380. package/src/server/internal/register.ts +8 -12
  381. package/src/server/internal/registerReleasedJobs.ts +5 -5
  382. package/src/server/internal/retryWake.ts +3 -3
  383. package/src/server/internal/runQueueWorker.ts +8 -8
  384. package/src/server/internal/storedRows.ts +3 -3
  385. package/src/server/internal/testingIdle.ts +8 -31
  386. package/src/server/internal/testingOperation.ts +18 -0
  387. package/src/server/internal/testingSchedules.ts +29 -17
  388. package/src/server/internal/testingWaits.ts +16 -16
  389. package/src/server/internal/tracing.ts +2 -2
  390. package/src/server/internal/validateQueueNames.ts +2 -2
  391. package/src/server/internal/waitForBatchExpiry.ts +4 -4
  392. package/src/server/job.ts +42 -0
  393. package/src/server/jobModule.ts +19 -7
  394. package/src/server/queueOptions.ts +20 -0
  395. package/src/server/readJobFailure.ts +12 -0
  396. package/src/server/schema.ts +23 -7
  397. package/src/server/service.ts +43 -44
  398. package/src/server/testing.ts +4 -117
  399. package/src/server/workerOptions.ts +28 -0
  400. package/dist/server/defaultClientFactory.d.ts +0 -3
  401. package/dist/server/defaultClientFactory.d.ts.map +0 -1
  402. package/dist/server/defaultClientFactory.js.map +0 -1
  403. package/dist/server/internal/batchHandler.d.ts +0 -5
  404. package/dist/server/internal/batchHandler.d.ts.map +0 -1
  405. package/dist/server/internal/batchHandler.js.map +0 -1
  406. package/dist/server/internal/clientCache.d.ts +0 -8
  407. package/dist/server/internal/clientCache.d.ts.map +0 -1
  408. package/dist/server/internal/clientCache.js.map +0 -1
  409. package/dist/server/internal/expireAttempt.d.ts +0 -3
  410. package/dist/server/internal/expireAttempt.d.ts.map +0 -1
  411. package/dist/server/internal/listJobs.d.ts +0 -5
  412. package/dist/server/internal/listJobs.d.ts.map +0 -1
  413. package/dist/server/internal/listJobs.js +0 -75
  414. package/dist/server/internal/listJobs.js.map +0 -1
  415. package/dist/server/internal/observeTestingSettlements.d.ts +0 -6
  416. package/dist/server/internal/observeTestingSettlements.d.ts.map +0 -1
  417. package/dist/server/internal/observeTestingSettlements.js +0 -35
  418. package/dist/server/internal/observeTestingSettlements.js.map +0 -1
  419. package/dist/server/internal/settleDeferral.d.ts +0 -7
  420. package/dist/server/internal/settleDeferral.d.ts.map +0 -1
  421. package/dist/server/internal/settleDeferral.js.map +0 -1
  422. package/dist/server/internal/testingClient.d.ts +0 -13
  423. package/dist/server/internal/testingClient.d.ts.map +0 -1
  424. package/dist/server/internal/testingClient.js.map +0 -1
  425. package/dist/server/internal/testingDeferrals.d.ts +0 -10
  426. package/dist/server/internal/testingDeferrals.d.ts.map +0 -1
  427. package/dist/server/internal/testingDeferrals.js +0 -15
  428. package/dist/server/internal/testingDeferrals.js.map +0 -1
  429. package/dist/server/internal/testingReadout.d.ts +0 -44
  430. package/dist/server/internal/testingReadout.d.ts.map +0 -1
  431. package/dist/server/internal/testingReadout.js +0 -13
  432. package/dist/server/internal/testingReadout.js.map +0 -1
  433. package/dist/server/internal/testingRegistrations.d.ts +0 -4
  434. package/dist/server/internal/testingRegistrations.d.ts.map +0 -1
  435. package/dist/server/internal/testingRegistrations.js +0 -8
  436. package/dist/server/internal/testingRegistrations.js.map +0 -1
  437. package/dist/server/internal/testingSignal.d.ts.map +0 -1
  438. package/dist/server/internal/testingSignal.js.map +0 -1
  439. package/dist/server/internal/testingSnapshot.d.ts +0 -6
  440. package/dist/server/internal/testingSnapshot.d.ts.map +0 -1
  441. package/dist/server/internal/testingSnapshot.js.map +0 -1
  442. package/src/server/internal/listJobs.ts +0 -116
  443. package/src/server/internal/observeTestingSettlements.ts +0 -36
  444. package/src/server/internal/testingDeferrals.ts +0 -22
  445. package/src/server/internal/testingReadout.ts +0 -19
  446. package/src/server/internal/testingRegistrations.ts +0 -10
  447. /package/dist/server/{defaultClientFactory.js → adapters/defaultClientFactory.js} +0 -0
@@ -1,17 +1,21 @@
1
1
  import { Effect, Fiber, Scope } from "effect";
2
- import type { Job, StopOptions, WorkOptions } from "pg-boss";
3
- import type { PgBossClient } from "#client.ts";
4
- import { toPgBossError } from "#error.ts";
5
- import { batchHandler } from "#internal/batchHandler.ts";
6
- import { deferrableAttempt } from "#internal/deferrableAttempt.ts";
7
- import { retryWake } from "#internal/retryWake.ts";
8
- import { traceJob } from "#internal/tracing.ts";
2
+ import { batchHandler } from "#server/adapters/batchHandler.ts";
3
+ import type { PgBossClient } from "#server/client.ts";
4
+ import type { StopOptions } from "#server/clientOptions.ts";
5
+ import { toPgBossError } from "#server/error.ts";
6
+ import { deferrableAttempt } from "#server/internal/deferrableAttempt.ts";
7
+ import { JobEngine } from "#server/internal/engine.ts";
8
+ import { retryWake } from "#server/internal/retryWake.ts";
9
+ import { traceJob } from "#server/internal/tracing.ts";
10
+ import type { WorkerJob } from "#server/job.ts";
11
+ import type { WorkerOptions } from "#server/workerOptions.ts";
12
+ import { jobEngine } from "./jobEngine.ts";
9
13
 
10
14
  export const registerWorker = Effect.fnUntraced(function* <R>(
11
15
  client: PgBossClient,
12
16
  name: string,
13
- options: WorkOptions,
14
- run: (job: Job<unknown>, deadline: number) => Effect.Effect<unknown, unknown, R>,
17
+ options: WorkerOptions,
18
+ run: (job: WorkerJob<unknown>, deadline: number) => Effect.Effect<unknown, unknown, R>,
15
19
  scope: Scope.Scope,
16
20
  schema: string,
17
21
  maxDeferrals: number,
@@ -20,10 +24,11 @@ export const registerWorker = Effect.fnUntraced(function* <R>(
20
24
  const execute = Effect.runPromiseWith(yield* Effect.context<R>());
21
25
  const workerScope = yield* Scope.fork(scope);
22
26
  const fibers = yield* Scope.fork(workerScope);
23
- function runJob(job: Job<unknown>, deadline: number) {
24
- return traceJob(deferrableAttempt(run(job, deadline), client, schema, job, maxDeferrals), job, name);
27
+ const engine = jobEngine(client, schema);
28
+ function runJob(job: WorkerJob<unknown>, deadline: number) {
29
+ return traceJob(deferrableAttempt(run(job, deadline), job, maxDeferrals).pipe(Effect.provideService(JobEngine, engine)), job, name);
25
30
  }
26
- function afterRetry(attempt: Job<unknown>) {
31
+ function afterRetry(attempt: WorkerJob<unknown>) {
27
32
  return retryWake(client, schema, name, attempt.id, registration).pipe(Effect.forkIn(fibers), Effect.asVoid);
28
33
  }
29
34
  const handle = yield* Effect.try({
@@ -1,9 +1,9 @@
1
1
  import { Effect } from "effect";
2
- import type { PgBossClient } from "#client.ts";
3
- import type { JobRegistration } from "#definition.ts";
4
- import { toPgBossError } from "#error.ts";
5
- import { deadLetterQueueName } from "#health.ts";
6
- import { registrationNames } from "#internal/register.ts";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import type { JobRegistration } from "#server/definition.ts";
4
+ import { toPgBossError } from "#server/error.ts";
5
+ import { deadLetterQueueName } from "#server/health.ts";
6
+ import { registrationNames } from "#server/internal/register.ts";
7
7
 
8
8
  export const retireJobs = Effect.fnUntraced(function* (client: PgBossClient, jobs: readonly JobRegistration[], retired: readonly string[]) {
9
9
  yield* Effect.try({
@@ -1,5 +1,5 @@
1
1
  import { Schema } from "effect";
2
- import type { PgBoss } from "pg-boss";
2
+ import type { EngineClient } from "#server/engineClient.ts";
3
3
 
4
4
  const IndexBuilds = Schema.Array(Schema.Struct({ command: Schema.String, id: Schema.String }));
5
5
  const IndexValidity = Schema.Array(Schema.Struct({ invalid: Schema.Boolean }));
@@ -28,7 +28,7 @@ export function pendingIndexInserts(schema: string, version: number, commands: r
28
28
  .join("\n");
29
29
  }
30
30
 
31
- export async function resumeSchemaIndexes(client: PgBoss, schema: string): Promise<void> {
31
+ export async function resumeSchemaIndexes(client: EngineClient, schema: string): Promise<void> {
32
32
  const db = client.getDb();
33
33
  const { rows } = await db.executeSql(
34
34
  `SELECT id, command FROM ${schema}.bam WHERE starts_with(name, $1) AND status <> 'completed' ORDER BY created_on, name`,
@@ -1,12 +1,12 @@
1
1
  import { Schema } from "effect";
2
- import type { Job } from "pg-boss";
3
- import type { PgBossClient } from "#client.ts";
4
- import { STATELY_DEFERRAL_POLICY } from "#internal/deferral.ts";
5
- import { quotedSchema } from "#internal/storedRows.ts";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import { STATELY_DEFERRAL_POLICY } from "#server/internal/deferral.ts";
4
+ import type { JobAttempt } from "#server/internal/engine.ts";
5
+ import { quotedSchema } from "#server/internal/storedRows.ts";
6
6
 
7
7
  const Settlement = Schema.Struct({ claimed: Schema.Boolean, deferred: Schema.Boolean });
8
8
 
9
- export async function settleDeferral(client: PgBossClient, schema: string, job: Job<unknown>, at: string, reason: string, maxDeferrals: number) {
9
+ export async function settleDeferral(client: PgBossClient, schema: string, job: JobAttempt, at: string, reason: string, maxDeferrals: number) {
10
10
  if (client.getDb === undefined) {
11
11
  throw new TypeError("This pg-boss client does not support getDb for RetryAt");
12
12
  }
@@ -1,34 +1,28 @@
1
- import type { Job, PgBoss, SendOptions, UpdateOptions, UpdateRequest, UpdateResponse } from "pg-boss";
2
- import { testingExpirations } from "#adapters/testingExpirations.ts";
3
- import type { PgBossClient } from "#client.ts";
4
- import { deferralObservers } from "#internal/deferral.ts";
5
- import { expireAttempt } from "#internal/expireAttempt.ts";
6
- import { observeTestingSettlements } from "#internal/observeTestingSettlements.ts";
7
- import type { TestingBatch, TestingWork } from "#internal/testingIdle.ts";
8
- import { testingRegistration } from "#internal/testingRegistrations.ts";
1
+ import { Effect } from "effect";
2
+ import { testingEngine } from "#server/adapters/testingEngine.ts";
3
+ import { testingExpirations } from "#server/adapters/testingExpirations.ts";
4
+ import type { ClientUpdateOptions, ClientUpdateRequest, ClientUpdateResult, PgBossClient } from "#server/client.ts";
5
+ import type { EngineClient } from "#server/engineClient.ts";
6
+ import type { EnqueueOptions } from "#server/enqueueOptions.ts";
7
+ import type { TestingBatch, TestingWork } from "#server/internal/testingIdle.ts";
8
+ import type { WorkerJob } from "#server/job.ts";
9
9
 
10
10
  export interface TestingControls {
11
11
  readonly changed: () => void;
12
12
  readonly expirations: Map<string, number>;
13
13
  readonly expirySeconds: Map<string, number>;
14
14
  readonly failures: Set<string>;
15
- readonly retryPolicy: Pick<SendOptions, "retryBackoff" | "retryDelay">;
15
+ readonly retryPolicy: Pick<EnqueueOptions, "retryBackoff" | "retryDelay">;
16
16
  readonly work: TestingWork;
17
17
  }
18
18
 
19
- export function testingClient(client: PgBoss, schema: string, controls: TestingControls): PgBossClient {
20
- const settlements = observeTestingSettlements(client, (name) => {
21
- for (const batch of controls.work.batches) {
22
- if (batch.name === name) {
23
- batch.settled = true;
24
- }
25
- }
26
- controls.changed();
27
- });
19
+ export function testingClient(client: EngineClient, schema: string, controls: TestingControls): EngineClient {
20
+ const engine = testingEngine(client, schema);
21
+
28
22
  const expirations = testingExpirations(client);
29
- function update(request: UpdateRequest): Promise<UpdateResponse>;
30
- function update(name: string, data: object | null | undefined, options?: UpdateOptions): Promise<UpdateResponse>;
31
- async function update(request: string | UpdateRequest, data?: object | null, options?: UpdateOptions): Promise<UpdateResponse> {
23
+ function update(request: ClientUpdateRequest): Promise<ClientUpdateResult>;
24
+ function update(name: string, data: object | null | undefined, options?: ClientUpdateOptions): Promise<ClientUpdateResult>;
25
+ async function update(request: string | ClientUpdateRequest, data?: object | null, options?: ClientUpdateOptions): Promise<ClientUpdateResult> {
32
26
  const result = typeof request === "string" ? await client.update(request, data, options) : await client.update(request);
33
27
  controls.changed();
34
28
  return result;
@@ -40,6 +34,9 @@ export function testingClient(client: PgBoss, schema: string, controls: TestingC
40
34
  return result;
41
35
  },
42
36
  createQueue: (name, options) => {
37
+ if (options?.deadLetter !== undefined) {
38
+ controls.work.queues.add(name);
39
+ }
43
40
  const { retryDelayMax, ...rest } = options ?? {};
44
41
  return client.createQueue(name, {
45
42
  ...rest,
@@ -79,13 +76,6 @@ export function testingClient(client: PgBoss, schema: string, controls: TestingC
79
76
  controls.changed();
80
77
  return id;
81
78
  },
82
- stop: async (options) => {
83
- try {
84
- await client.stop(options);
85
- } finally {
86
- settlements.close();
87
- }
88
- },
89
79
  update,
90
80
  updateQueue: (name, options) =>
91
81
  client.updateQueue(name, {
@@ -93,18 +83,17 @@ export function testingClient(client: PgBoss, schema: string, controls: TestingC
93
83
  ...controls.retryPolicy,
94
84
  ...(controls.retryPolicy.retryBackoff === false ? { retryDelayMax: null } : {}),
95
85
  }),
96
- work: (name, options, handler) => {
97
- settlements.watch(name);
98
- return client.work(name, options, async (jobs: Job<unknown>[]) => {
99
- const batch: TestingBatch = { name, settled: false };
86
+ work: async (name, options, handler) =>
87
+ client.work(name, options, async (jobs: readonly WorkerJob<unknown>[]) => {
88
+ const batch: TestingBatch = { jobs: new Map(jobs.map((job) => [job.id, job.retryCount])), name, settled: false };
100
89
  controls.work.batches.add(batch);
101
90
  controls.changed();
102
91
  try {
103
- const ready: Job<unknown>[] = [];
92
+ const ready: WorkerJob<unknown>[] = [];
104
93
  for (const job of jobs) {
105
94
  const attempts = await expirations.attemptsFor(job);
106
95
  if (attempts !== undefined && job.retryCount + 1 >= attempts) {
107
- await expireAttempt(client, schema, job);
96
+ await Effect.runPromise(engine.expireAttempt(job));
108
97
  } else {
109
98
  ready.push(job);
110
99
  }
@@ -116,14 +105,10 @@ export function testingClient(client: PgBoss, schema: string, controls: TestingC
116
105
  controls.work.batches.delete(batch);
117
106
  controls.changed();
118
107
  }
119
- });
120
- },
108
+ }),
121
109
  };
122
110
  const wrapped = new Proxy(client, {
123
111
  get(target, property) {
124
- if (property === testingRegistration) {
125
- return (name: string) => controls.work.queues.add(name);
126
- }
127
112
  if (Object.hasOwn(overrides, property)) {
128
113
  const override: unknown = Reflect.get(overrides, property);
129
114
  return override;
@@ -132,6 +117,5 @@ export function testingClient(client: PgBoss, schema: string, controls: TestingC
132
117
  return typeof value === "function" ? value.bind(target) : value;
133
118
  },
134
119
  });
135
- deferralObservers.set(wrapped, controls.changed);
136
120
  return wrapped;
137
121
  }
@@ -0,0 +1,125 @@
1
+ import { Duration, Effect, Redacted, type Schema } from "effect";
2
+ import { defaultClientFactory } from "#server/adapters/defaultClientFactory.ts";
3
+ import { testingClient } from "#server/adapters/testingClient.ts";
4
+ import { testingDueNow } from "#server/adapters/testingDueNow.ts";
5
+ import type { JobReadOptions, PgBossClientFactory } from "#server/client.ts";
6
+ import type { JobPayloadSchema, QueueDefinition } from "#server/definition.ts";
7
+ import type { EngineClient } from "#server/engineClient.ts";
8
+ import { PgBossTestingError } from "#server/error.ts";
9
+ import type { PgBossInspectionService, SnapshotQueue } from "#server/inspection.ts";
10
+ import { type TestingFetches, testingFetches } from "#server/internal/adapters/testingFetches.ts";
11
+ import { type TestingWork, testingIdle } from "#server/internal/testingIdle.ts";
12
+ import { testingInspection, testingOperation } from "#server/internal/testingOperation.ts";
13
+ import { testingSchedules } from "#server/internal/testingSchedules.ts";
14
+ import { testingWaits } from "#server/internal/testingWaits.ts";
15
+ import type { PgBossTestingOptions } from "#server/testing.ts";
16
+ import { queueSignal } from "./queueSignal.ts";
17
+ import { testingInspectionClient } from "./testingInspectionClient.ts";
18
+ export function testingController(settings: PgBossTestingOptions = {}) {
19
+ let current: EngineClient | undefined;
20
+ let fetches: TestingFetches | undefined;
21
+ let schema = "pgboss";
22
+ const signal = queueSignal();
23
+ let observed: PgBossInspectionService | undefined;
24
+ const work: TestingWork = { batches: new Set(), queues: new Set() };
25
+ const controls = {
26
+ changed: signal.changed,
27
+ expirations: new Map<string, number>(),
28
+ expirySeconds: new Map<string, number>(),
29
+ failures: new Set<string>(),
30
+ retryPolicy: settings.retryPolicy ?? {},
31
+ work,
32
+ };
33
+ function client(): EngineClient {
34
+ if (current === undefined) {
35
+ throw new Error("Provide the testing clientFactory to a jobs Layer first");
36
+ }
37
+ return current;
38
+ }
39
+ function inspection(): PgBossInspectionService {
40
+ if (observed === undefined) {
41
+ throw new Error("Provide the testing clientFactory to a jobs Layer first");
42
+ }
43
+ return observed;
44
+ }
45
+ const clientFactory: PgBossClientFactory = (clientOptions) => {
46
+ if (current !== undefined) {
47
+ throw new Error("A testing controller owns one jobs client; create a controller per runtime");
48
+ }
49
+ schema = clientOptions.schema ?? "pgboss";
50
+ current = defaultClientFactory(clientOptions);
51
+ fetches = testingFetches(current.getDb(), signal.changed);
52
+ current = testingClient(current, schema, controls);
53
+ return testingInspectionClient(current, schema, work, signal.changed, (reads) => {
54
+ observed = reads;
55
+ });
56
+ };
57
+ return {
58
+ deferred: (queue: Pick<QueueDefinition, "name">) => Effect.suspend(() => testingInspection("deferred", inspection().deferred(queue), queue.name)),
59
+ ...testingDueNow(client, () => schema, signal.changed),
60
+ ...testingSchedules(client, inspection),
61
+ ...testingWaits(inspection, () => fetches, signal),
62
+ checkBatchWindow: (queue: Pick<QueueDefinition, "name" | "workerOptions">, millisecondsPerJob: number) =>
63
+ testingOperation(
64
+ "checkBatchWindow",
65
+ async () => {
66
+ const stored = await Effect.runPromise(inspection().queue(queue));
67
+ if (stored === null) {
68
+ throw new Error("Queue is not registered");
69
+ }
70
+ if (stored.expireInSeconds === undefined) {
71
+ throw new Error("Queue has no expiry window");
72
+ }
73
+ if (!Number.isFinite(millisecondsPerJob) || millisecondsPerJob < 0) {
74
+ throw new RangeError("Job duration must be nonnegative and finite");
75
+ }
76
+ const required = (queue.workerOptions.batchSize ?? 10) * millisecondsPerJob;
77
+ if (required >= stored.expireInSeconds * 1000) {
78
+ throw new Error("Sequential batch work must fit within the queue expiry window");
79
+ }
80
+ },
81
+ queue.name,
82
+ ),
83
+ checkSchemaVersion: (expected: number) =>
84
+ testingOperation("checkSchemaVersion", async () => {
85
+ if ((await Effect.runPromise(inspection().schemaVersion())) !== expected) {
86
+ throw new Error(`Expected pg-boss schema version ${expected}`);
87
+ }
88
+ }),
89
+ clientFactory,
90
+ expireAfter: (queue: Pick<QueueDefinition, "name">, attempts: number) =>
91
+ Effect.try({
92
+ catch: (original) => new PgBossTestingError({ operation: "expireAfter", original: Redacted.make(original), queue: queue.name }),
93
+ try: () => {
94
+ if (!Number.isSafeInteger(attempts) || attempts < 1) {
95
+ throw new RangeError("Attempts must be a positive integer");
96
+ }
97
+ controls.expirations.set(queue.name, attempts);
98
+ },
99
+ }),
100
+ expireIn: (queue: Pick<QueueDefinition, "name">, duration: Duration.Input) =>
101
+ Effect.try({
102
+ catch: (original) => new PgBossTestingError({ operation: "expireIn", original: Redacted.make(original), queue: queue.name }),
103
+ try: () => {
104
+ const milliseconds = Duration.toMillis(Duration.fromInputUnsafe(duration));
105
+ if (!Number.isFinite(milliseconds) || milliseconds < 1000) {
106
+ throw new RangeError("Expiry must be finite and at least one second");
107
+ }
108
+ controls.expirySeconds.set(queue.name, Math.ceil(milliseconds / 1000));
109
+ },
110
+ }),
111
+ failNextSend: (queue: Pick<QueueDefinition, "name">) => Effect.sync(() => controls.failures.add(queue.name)).pipe(Effect.asVoid),
112
+ jobs: <TName extends string, TPayload extends JobPayloadSchema | typeof Schema.Null>(
113
+ queue: { readonly name: TName; readonly schema: TPayload },
114
+ readOptions?: JobReadOptions,
115
+ ) => Effect.suspend(() => testingInspection("jobs", inspection().jobs(queue, readOptions), queue.name)),
116
+ refreshQueueStats: (queue?: Pick<QueueDefinition, "name">) =>
117
+ testingOperation("refreshQueueStats", () => client().supervise(queue?.name), queue?.name),
118
+ revision: signal.revision,
119
+ schemaVersion: Effect.suspend(() => testingInspection("schemaVersion", inspection().schemaVersion())),
120
+ snapshot: <const TQueues extends readonly SnapshotQueue[]>(queues: TQueues) =>
121
+ Effect.suspend(() => testingInspection("snapshot", inspection().snapshot(queues))),
122
+ waitForChange: signal.waitForChange,
123
+ waitForIdle: testingIdle(inspection, work, signal),
124
+ };
125
+ }
@@ -1,9 +1,9 @@
1
- import type { PgBoss } from "pg-boss";
2
- import type { QueueDefinition } from "#definition.ts";
3
- import { quotedSchema } from "#internal/storedRows.ts";
4
- import { testingOperation } from "#internal/testingReadout.ts";
1
+ import type { QueueDefinition } from "#server/definition.ts";
2
+ import type { EngineClient } from "#server/engineClient.ts";
3
+ import { quotedSchema } from "#server/internal/storedRows.ts";
4
+ import { testingOperation } from "#server/internal/testingOperation.ts";
5
5
 
6
- export function testingDueNow(client: () => PgBoss, schema: () => string, changed: () => void) {
6
+ export function testingDueNow(client: () => EngineClient, schema: () => string, changed: () => void) {
7
7
  function makeDue(queue: Pick<QueueDefinition, "name">, deferredOnly: boolean) {
8
8
  return testingOperation(
9
9
  deferredOnly ? "runDeferredNow" : "runDueNow",
@@ -0,0 +1,15 @@
1
+ import { type Context, Effect, Redacted } from "effect";
2
+ import type { EngineClient } from "#server/engineClient.ts";
3
+ import { PgBossTestingError } from "#server/error.ts";
4
+ import type { TestingEngine } from "#server/internal/engine.ts";
5
+ import { expireAttempt } from "./expireAttempt.ts";
6
+
7
+ export function testingEngine(client: EngineClient, schema: string): Context.Service.Shape<typeof TestingEngine> {
8
+ return {
9
+ expireAttempt: (job, cause) =>
10
+ Effect.tryPromise({
11
+ catch: (original) => new PgBossTestingError({ operation: "expireAttempt", original: Redacted.make(original), queue: job.name }),
12
+ try: () => expireAttempt(client, schema, job, cause),
13
+ }),
14
+ };
15
+ }
@@ -1,10 +1,12 @@
1
- import type { Job, PgBoss, SendOptions } from "pg-boss";
1
+ import type { EngineClient } from "#server/engineClient.ts";
2
+ import type { EnqueueOptions } from "#server/enqueueOptions.ts";
3
+ import type { WorkerJob } from "#server/job.ts";
2
4
 
3
- export function testingExpirations(client: PgBoss) {
5
+ export function testingExpirations(client: EngineClient) {
4
6
  const snapshots = new Map<string, Promise<number | undefined>>();
5
7
  return {
6
- attemptsFor: (job: Job<unknown>) => snapshots.get(`${job.name}:${job.id}`),
7
- send(name: string, data: object | null | undefined, options: SendOptions, attempts: number | undefined) {
8
+ attemptsFor: (job: WorkerJob<unknown>) => snapshots.get(`${job.name}:${job.id}`),
9
+ send(name: string, data: object | null | undefined, options: EnqueueOptions, attempts: number | undefined) {
8
10
  if (attempts === undefined && options.id === undefined) {
9
11
  return client.send(name, data, options);
10
12
  }
@@ -0,0 +1,70 @@
1
+ import { Context, Effect, Exit, Layer, Scope } from "effect";
2
+ import type { EngineClient } from "#server/engineClient.ts";
3
+ import { PgBossInspection, type PgBossInspectionService } from "#server/inspection.ts";
4
+ import type { TestingWork } from "#server/internal/testingIdle.ts";
5
+ import { PgBoss } from "#server/PgBoss.ts";
6
+
7
+ const settleBatches = Effect.fnUntraced(function* (inspection: PgBossInspectionService, work: TestingWork) {
8
+ for (const batch of work.batches) {
9
+ if (batch.settled) {
10
+ continue;
11
+ }
12
+ const stored = yield* inspection.storedJobs({ name: batch.name });
13
+ batch.settled = !stored.some((job) => job.state === "active" && batch.jobs.get(job.id) === job.retryCount);
14
+ }
15
+ });
16
+
17
+ export function testingInspectionClient(
18
+ source: EngineClient,
19
+ schema: string,
20
+ work: TestingWork,
21
+ changed: () => void,
22
+ observe: (inspection: PgBossInspectionService) => void,
23
+ ): EngineClient {
24
+ const scope = Effect.runSync(Scope.make());
25
+ const start = source.start.bind(source);
26
+ const stop = source.stop.bind(source);
27
+ async function startObserved() {
28
+ const result = await start();
29
+ const context = await Effect.runPromise(
30
+ Layer.buildWithScope(
31
+ PgBossInspection.layer.pipe(Layer.provide(Layer.succeed(PgBoss, { client: source, reused: false, schema, stop: undefined }))),
32
+ scope,
33
+ ),
34
+ );
35
+ const inspection = Context.get(context, PgBossInspection);
36
+ observe(inspection);
37
+ await Effect.runPromise(
38
+ Effect.gen(function* () {
39
+ const changes = yield* inspection.changes();
40
+ const from = yield* changes.revision;
41
+ yield* Effect.forkScoped(
42
+ Effect.gen(function* () {
43
+ let revision = from;
44
+ while (true) {
45
+ revision = yield* changes.waitForChange(revision);
46
+ yield* settleBatches(inspection, work);
47
+ changed();
48
+ }
49
+ }),
50
+ );
51
+ }).pipe(Effect.provideService(Scope.Scope, scope)),
52
+ );
53
+ return result;
54
+ }
55
+ const stopObserved: EngineClient["stop"] = async (options) => {
56
+ await Promise.all([Effect.runPromise(Scope.close(scope, Exit.void)), stop(options)]);
57
+ };
58
+ return new Proxy(source, {
59
+ get(target, property) {
60
+ if (property === "start") {
61
+ return startObserved;
62
+ }
63
+ if (property === "stop") {
64
+ return stopObserved;
65
+ }
66
+ const value: unknown = Reflect.get(target, property);
67
+ return typeof value === "function" ? value.bind(target) : value;
68
+ },
69
+ });
70
+ }
@@ -1,8 +1,8 @@
1
1
  import { Effect, Option } from "effect";
2
2
  import { SqlClient } from "effect/sql";
3
- import type { SendOptions } from "pg-boss";
3
+ import type { EnqueueOptions } from "#server/enqueueOptions.ts";
4
4
 
5
- export const transactionDb: Effect.Effect<SendOptions["db"]> = Effect.gen(function* () {
5
+ export const transactionDb: Effect.Effect<EnqueueOptions["db"]> = Effect.gen(function* () {
6
6
  const sql = yield* Effect.serviceOption(SqlClient.SqlClient);
7
7
  if (Option.isNone(sql)) {
8
8
  return undefined;
@@ -1,39 +1,95 @@
1
- import type {
2
- ConstructorOptions,
3
- FindJobsOptions,
4
- Job,
5
- JobWithMetadata,
6
- PgBoss,
7
- Queue,
8
- QueueResult,
9
- ScheduleOptions,
10
- SendOptions,
11
- StopOptions,
12
- WorkOptions,
13
- } from "pg-boss";
1
+ import type { ClientDatabase } from "#server/ClientDatabase.ts";
2
+ import type { ClientOptions, StopOptions } from "#server/clientOptions.ts";
3
+ import type { EngineSchedule } from "#server/engineClient.ts";
4
+ import type { EnqueueOptions, ScheduleOptions } from "#server/enqueueOptions.ts";
5
+ import type { Job, WorkerJob } from "#server/job.ts";
6
+ import type { QueueOptions } from "#server/queueOptions.ts";
7
+ import type { WorkerOptions } from "#server/workerOptions.ts";
8
+
9
+ export interface JobReadOptions {
10
+ readonly after?: string;
11
+ readonly data?: object;
12
+ readonly db?: ClientDatabase;
13
+ readonly id?: string;
14
+ readonly key?: string;
15
+ readonly limit?: number;
16
+ readonly queued?: boolean;
17
+ }
18
+
19
+ export interface ClientQueueOptions extends Omit<QueueOptions, "maxDeferrals" | "policy"> {
20
+ readonly deadLetter?: string;
21
+ readonly policy?: string;
22
+ }
23
+
24
+ export interface ClientQueue extends ClientQueueOptions {
25
+ readonly activeCount: number;
26
+ readonly blockedCount: number;
27
+ readonly deferredCount: number;
28
+ readonly failedCount: number;
29
+ readonly name: string;
30
+ readonly queuedCount: number;
31
+ readonly readyCount: number;
32
+ readonly totalCount: number;
33
+ }
34
+
35
+ export type JobTarget = string | string[] | { id: string; retryCount: number } | { id: string; retryCount: number }[];
36
+ export interface ClientConnectionOptions {
37
+ readonly db?: ClientDatabase;
38
+ }
39
+ export interface ClientUpdateOptions extends Omit<EnqueueOptions, "singletonSeconds" | "singletonNextSlot"> {
40
+ readonly match?: "newest" | "oldest" | "all";
41
+ }
42
+ export interface ClientUpdateRequest {
43
+ data?: object | null;
44
+ name: string;
45
+ options?: ClientUpdateOptions;
46
+ }
47
+ export interface ClientUpdateResult {
48
+ jobs: string[];
49
+ updated: number;
50
+ }
14
51
 
15
52
  export interface PgBossClient {
16
- readonly complete?: PgBoss["complete"];
17
- readonly createQueue: (name: string, options?: Omit<Queue, "name">) => Promise<void>;
18
- readonly deleteQueue?: PgBoss["deleteQueue"];
19
- readonly fail?: PgBoss["fail"];
20
- readonly findJobs?: (name: string, options?: FindJobsOptions) => Promise<readonly JobWithMetadata<unknown>[]>;
21
- readonly getDb?: PgBoss["getDb"];
22
- readonly getQueue: (name: string) => Promise<QueueResult | null>;
23
- readonly getWipData?: PgBoss["getWipData"];
24
- readonly notifyWorker?: PgBoss["notifyWorker"];
53
+ readonly complete?: (
54
+ name: string,
55
+ id: JobTarget,
56
+ data?: object | null,
57
+ options?: ClientConnectionOptions & { includeQueued?: boolean },
58
+ ) => Promise<object>;
59
+ readonly createQueue: (name: string, options?: ClientQueueOptions) => Promise<void>;
60
+ readonly deleteQueue?: (name: string) => Promise<void>;
61
+ readonly fail?: (name: string, id: JobTarget, data?: object | null, options?: ClientConnectionOptions) => Promise<object>;
62
+ readonly findJobs?: (name: string, options?: JobReadOptions) => Promise<readonly Job<unknown>[]>;
63
+ readonly getDb?: () => ClientDatabase;
64
+ readonly getQueue: (name: string) => Promise<ClientQueue | null>;
65
+ readonly getSchedule?: (name: string, key?: string) => Promise<{ readonly name: string; readonly key: string } | null>;
66
+ readonly getSchedules?: (name?: string, key?: string) => Promise<EngineSchedule[]>;
67
+ readonly getWipData?: (options?: { includeInternal?: boolean }) => { id: string; workId: string; name: string; count: number }[];
68
+ readonly notifyWorker?: (workerId: string) => void;
25
69
  readonly off: (event: "error", listener: (error: Error) => void) => unknown;
26
- readonly offWork: PgBoss["offWork"];
70
+ readonly offWork: (name: string, options?: { id?: string; wait?: boolean }) => Promise<void>;
27
71
  readonly on: (event: "error", listener: (error: Error) => void) => unknown;
28
- readonly retry?: PgBoss["retry"];
72
+ readonly retry?: (name: string, id: string | string[], options?: ClientConnectionOptions) => Promise<object>;
29
73
  readonly schedule: (name: string, cron: string, data?: object | null, options?: ScheduleOptions) => Promise<void>;
30
- readonly send: (name: string, data?: object | null, options?: SendOptions) => Promise<string | null>;
74
+ readonly schemaVersion?: () => Promise<number | null>;
75
+ readonly send: (name: string, data?: object | null, options?: EnqueueOptions) => Promise<string | null>;
31
76
  readonly start: () => Promise<unknown>;
32
77
  readonly stop: (options?: StopOptions) => Promise<void>;
33
- readonly unschedule?: PgBoss["unschedule"];
34
- readonly update?: PgBoss["update"];
35
- readonly updateQueue?: PgBoss["updateQueue"];
36
- readonly work: (name: string, options: WorkOptions, handler: (jobs: readonly Job<unknown>[]) => Promise<unknown>) => Promise<string>;
78
+ readonly supervise?: (name?: string) => Promise<void>;
79
+ readonly unschedule?: (name: string, key?: string, options?: ClientConnectionOptions) => Promise<void>;
80
+ readonly update?: {
81
+ (request: ClientUpdateRequest): Promise<ClientUpdateResult>;
82
+ (name: string, data: object | null | undefined, options?: ClientUpdateOptions): Promise<ClientUpdateResult>;
83
+ };
84
+ readonly updateQueue?: (
85
+ name: string,
86
+ options: Omit<QueueOptions, "policy" | "partition" | "maxDeferrals" | "heartbeatSeconds" | "retryDelayMax"> & {
87
+ deadLetter?: string | null;
88
+ heartbeatSeconds?: number | null;
89
+ retryDelayMax?: number | null;
90
+ },
91
+ ) => Promise<void>;
92
+ readonly work: (name: string, options: WorkerOptions, handler: (jobs: readonly WorkerJob<unknown>[]) => Promise<unknown>) => Promise<string>;
37
93
  }
38
94
 
39
- export type PgBossClientFactory = (options: ConstructorOptions) => PgBossClient;
95
+ export type PgBossClientFactory = (options: ClientOptions) => PgBossClient;