@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,11 +1,11 @@
1
1
  import { isDeepStrictEqual } from "node:util";
2
- import type { ConstructorOptions } from "pg-boss";
3
- import type { PgBossClient } from "#client.ts";
4
- import { PgBossClientOptionsError } from "#error.ts";
2
+ import type { ClientOptions } from "#server/clientOptions.ts";
3
+ import { PgBossClientOptionsError } from "#server/error.ts";
4
+ import type { StartingClient } from "./lifecycle.ts";
5
5
 
6
6
  interface CachedClient {
7
- readonly client: Promise<PgBossClient>;
8
- readonly constructorOptions: ConstructorOptions;
7
+ readonly client: StartingClient;
8
+ readonly constructorOptions: ClientOptions;
9
9
  references: number;
10
10
  }
11
11
 
@@ -23,13 +23,13 @@ function isCachedClient(value: unknown): value is CachedClient {
23
23
  return (
24
24
  typeof value === "object"
25
25
  && value !== null
26
- && Reflect.get(value, "client") instanceof Promise
26
+ && typeof Reflect.get(value, "client") === "object"
27
27
  && typeof Reflect.get(value, "constructorOptions") === "object"
28
28
  && typeof Reflect.get(value, "references") === "number"
29
29
  );
30
30
  }
31
31
 
32
- export async function acquireCachedClient(key: string | symbol, constructorOptions: ConstructorOptions, start: () => Promise<PgBossClient>) {
32
+ export function acquireCachedClient(key: string | symbol, constructorOptions: ClientOptions, start: () => StartingClient) {
33
33
  const existing = entryFor(key);
34
34
  if (existing !== undefined) {
35
35
  const options = [...new Set([...Object.keys(existing.constructorOptions), ...Object.keys(constructorOptions)])]
@@ -39,27 +39,15 @@ export async function acquireCachedClient(key: string | symbol, constructorOptio
39
39
  throw new PgBossClientOptionsError({ key, options });
40
40
  }
41
41
  existing.references += 1;
42
- try {
43
- return { client: await existing.client, reused: true };
44
- } catch (error) {
45
- existing.references -= 1;
46
- throw error;
47
- }
42
+ return { ...existing.client, reused: true };
48
43
  }
49
44
  const settings = { ...constructorOptions };
50
45
  const entry: CachedClient = { client: start(), constructorOptions: settings, references: 1 };
51
46
  clients.set(key, entry);
52
- try {
53
- return { client: await entry.client, reused: false };
54
- } catch (error) {
55
- if (clients.get(key) === entry) {
56
- clients.delete(key);
57
- }
58
- throw error;
59
- }
47
+ return { ...entry.client, reused: false };
60
48
  }
61
49
 
62
- export function releaseCachedClient(key: string | symbol): Promise<PgBossClient> | undefined {
50
+ export function releaseCachedClient(key: string | symbol): StartingClient | undefined {
63
51
  const entry = entryFor(key);
64
52
  if (entry === undefined) {
65
53
  return;
@@ -1,5 +1,5 @@
1
1
  import { Effect } from "effect";
2
- import { logClientError } from "#internal/clientErrors.ts";
2
+ import { logClientError } from "#server/internal/clientErrors.ts";
3
3
 
4
4
  export const clientErrorLogger = Effect.fnUntraced(function* () {
5
5
  const run = Effect.runForkWith(yield* Effect.context<never>());
@@ -1,7 +1,9 @@
1
1
  import { Socket } from "node:net";
2
- import { type ConstructorOptions, PgBoss } from "pg-boss";
2
+ import { PgBoss } from "pg-boss";
3
+ import type { ClientOptions } from "#server/clientOptions.ts";
4
+ import type { EngineClient } from "#server/engineClient.ts";
3
5
 
4
- export function defaultClientFactory(options: ConstructorOptions) {
6
+ export function defaultClientFactory(options: ClientOptions): EngineClient {
5
7
  const disconnected = new Set<Promise<void>>();
6
8
  const config = {
7
9
  ...options,
@@ -1,12 +1,12 @@
1
1
  import { Effect, Schema } from "effect";
2
- import type { Job } from "pg-boss";
3
- import type { PgBossClient } from "#client.ts";
4
- import { toPgBossError } from "#error.ts";
5
- import { quotedSchema } from "#internal/storedRows.ts";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import { toPgBossError } from "#server/error.ts";
4
+ import { quotedSchema } from "#server/internal/storedRows.ts";
5
+ import type { WorkerJob } from "#server/job.ts";
6
6
 
7
7
  const Count = Schema.Struct({ count: Schema.NumberFromString });
8
8
 
9
- export const deferralCount = Effect.fnUntraced(function* (client: PgBossClient, schema: string, job: Job<unknown>) {
9
+ export const deferralCount = Effect.fnUntraced(function* (client: PgBossClient, schema: string, job: WorkerJob<unknown>) {
10
10
  const quoted = quotedSchema(schema);
11
11
  return yield* Effect.tryPromise({
12
12
  catch: (error) => toPgBossError("settle", error, job.name),
@@ -1,7 +1,8 @@
1
- import type { Job, PgBoss } from "pg-boss";
2
- import { quotedSchema } from "#internal/storedRows.ts";
1
+ import type { EngineClient } from "#server/engineClient.ts";
2
+ import type { JobAttempt } from "#server/internal/engine.ts";
3
+ import { quotedSchema } from "#server/internal/storedRows.ts";
3
4
 
4
- export async function expireAttempt(client: PgBoss, schema: string, job: Job<unknown>, cause: "expiry" | "heartbeat" = "expiry"): Promise<void> {
5
+ export async function expireAttempt(client: EngineClient, schema: string, job: JobAttempt, cause: "expiry" | "heartbeat" = "expiry"): Promise<void> {
5
6
  if ((await client.schemaVersion()) !== 46) {
6
7
  throw new Error("Testing expiry requires pg-boss schema version 46");
7
8
  }
@@ -0,0 +1,31 @@
1
+ import { Effect } from "effect";
2
+ import { jobEngine } from "#server/adapters/jobEngine.ts";
3
+ import type { PgBossClient } from "#server/client.ts";
4
+ import type { PgBossInspectionService } from "#server/inspection.ts";
5
+ import { countsFor } from "#server/internal/countsFor.ts";
6
+ import { JobEngine } from "#server/internal/engine.ts";
7
+ import { healthFor } from "#server/internal/healthFor.ts";
8
+ import { jobControl } from "#server/internal/jobControl.ts";
9
+ import { jobListings } from "#server/internal/jobListings.ts";
10
+ import { inspectionChanges } from "./inspectionChanges.ts";
11
+ import { inspectionReads } from "./inspectionReads.ts";
12
+
13
+ export function inspection(client: PgBossClient, schema = "pgboss"): Effect.Effect<PgBossInspectionService> {
14
+ const engine = jobEngine(client, schema);
15
+ return Effect.gen(function* () {
16
+ const listings = yield* jobListings;
17
+ const { getJob } = yield* jobControl;
18
+ return {
19
+ ...inspectionReads(client, schema),
20
+ ...listings,
21
+ changes: (queue?: { readonly name: string }) => inspectionChanges(client, schema, queue?.name),
22
+ counts: (queue: { readonly name: string }) => countsFor(client, schema, queue.name),
23
+ getJob,
24
+ health: (queues: readonly { readonly name: string }[]) =>
25
+ healthFor(
26
+ client,
27
+ queues.map((queue) => queue.name),
28
+ ),
29
+ };
30
+ }).pipe(Effect.provideService(JobEngine, engine));
31
+ }
@@ -0,0 +1,31 @@
1
+ import { Effect } from "effect";
2
+ import { inspectionChannel } from "#server/adapters/inspectionPlan.ts";
3
+ import type { PgBossClient } from "#server/client.ts";
4
+ import { toPgBossError } from "#server/error.ts";
5
+ import { queueSignal } from "./queueSignal.ts";
6
+
7
+ export const inspectionChanges = Effect.fnUntraced(function* (client: PgBossClient, schema: string, queue?: string) {
8
+ const signal = queueSignal();
9
+ yield* Effect.acquireRelease(
10
+ Effect.tryPromise({
11
+ catch: (error) => toPgBossError("inspect", error, queue),
12
+ try: () => {
13
+ const db = client.getDb?.();
14
+ if (db?.listen === undefined) {
15
+ throw new TypeError("This pg-boss client does not support listen");
16
+ }
17
+ return db.listen(
18
+ inspectionChannel(schema),
19
+ (name) => {
20
+ if (queue === undefined || name === queue) {
21
+ signal.changed();
22
+ }
23
+ },
24
+ signal.changed,
25
+ );
26
+ },
27
+ }),
28
+ (listener) => Effect.promise(() => listener.close()),
29
+ );
30
+ return { revision: signal.revision, waitForChange: signal.waitForChange };
31
+ });
@@ -0,0 +1,20 @@
1
+ import { DateTime, Effect } from "effect";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import type { QueueDefinition } from "#server/definition.ts";
4
+ import { deferralOf } from "#server/internal/deferral.ts";
5
+ import { inspectionJobs } from "./inspectionJobs.ts";
6
+
7
+ export function inspectionDeferrals(client: PgBossClient) {
8
+ const { storedJobs } = inspectionJobs(client);
9
+ return {
10
+ deferred: (queue: Pick<QueueDefinition, "name">) =>
11
+ storedJobs(queue).pipe(
12
+ Effect.map((jobs) =>
13
+ jobs.flatMap((job) => {
14
+ const deferral = job.state === "retry" && job.startedOn === null ? deferralOf(job) : undefined;
15
+ return deferral === undefined ? [] : [{ at: DateTime.makeUnsafe(job.startAfter), reason: deferral.reason }];
16
+ }),
17
+ ),
18
+ ),
19
+ };
20
+ }
@@ -0,0 +1,28 @@
1
+ import { Effect, type Schema } from "effect";
2
+ import type { JobReadOptions, PgBossClient } from "#server/client.ts";
3
+ import type { JobPayloadSchema } from "#server/definition.ts";
4
+ import { toPgBossError } from "#server/error.ts";
5
+ import { decodeStoredData } from "#server/internal/storedRows.ts";
6
+
7
+ export function inspectionJobs(client: PgBossClient) {
8
+ function storedJobs(queue: { readonly name: string }, options?: JobReadOptions) {
9
+ return Effect.tryPromise({
10
+ catch: (error) => toPgBossError("inspect", error, queue.name),
11
+ try: () => {
12
+ if (client.findJobs === undefined) {
13
+ throw new TypeError("This pg-boss client does not support findJobs");
14
+ }
15
+ return client.findJobs(queue.name, options);
16
+ },
17
+ });
18
+ }
19
+ function jobs<TName extends string, TPayload extends JobPayloadSchema | typeof Schema.Null>(
20
+ queue: { readonly name: TName; readonly schema: TPayload },
21
+ options?: JobReadOptions,
22
+ ) {
23
+ return storedJobs(queue, options).pipe(
24
+ Effect.flatMap((rows) => Effect.forEach(rows, (job) => decodeStoredData(queue, job.data).pipe(Effect.map((data) => ({ ...job, data }))))),
25
+ );
26
+ }
27
+ return { jobs, storedJobs };
28
+ }
@@ -0,0 +1,6 @@
1
+ import { Effect } from "effect";
2
+ import { toPgBossError } from "#server/error.ts";
3
+
4
+ export function inspectionOperation<A>(run: () => Promise<A>, queue?: string) {
5
+ return Effect.tryPromise({ catch: (error) => toPgBossError("inspect", error, queue), try: run });
6
+ }
@@ -0,0 +1,21 @@
1
+ import { quotedSchema } from "#server/internal/storedRows.ts";
2
+
3
+ export function inspectionChannel(schema: string): string {
4
+ return `jobs:${schema}`;
5
+ }
6
+
7
+ export function inspectionPlan(schema: string): string {
8
+ const quoted = quotedSchema(schema);
9
+ const channel = inspectionChannel(schema).replaceAll("'", "''");
10
+ const body = `BEGIN
11
+ CREATE OR REPLACE FUNCTION ${quoted}.effect_job_changed() RETURNS trigger LANGUAGE plpgsql AS $body$
12
+ BEGIN
13
+ PERFORM pg_notify('${channel}', COALESCE(NEW.name, OLD.name));
14
+ RETURN NULL;
15
+ END
16
+ $body$;
17
+ CREATE OR REPLACE TRIGGER effect_job_changed AFTER INSERT OR UPDATE OR DELETE ON ${quoted}.job
18
+ FOR EACH ROW EXECUTE FUNCTION ${quoted}.effect_job_changed();
19
+ END`;
20
+ return `DO '${body.replaceAll("'", "''")}'`;
21
+ }
@@ -0,0 +1,55 @@
1
+ import { Schema } from "effect";
2
+ import { inspectionDeferrals } from "#server/adapters/inspectionDeferrals.ts";
3
+ import { inspectionJobs } from "#server/adapters/inspectionJobs.ts";
4
+ import { inspectionOperation } from "#server/adapters/inspectionOperation.ts";
5
+ import { inspectionSnapshot } from "#server/adapters/inspectionSnapshot.ts";
6
+ import type { PgBossClient } from "#server/client.ts";
7
+ import type { QueueDefinition } from "#server/definition.ts";
8
+ import { quotedSchema } from "#server/internal/storedRows.ts";
9
+
10
+ const Busy = Schema.Struct({ busy: Schema.Boolean });
11
+ export function inspectionReads(client: PgBossClient, schema: string) {
12
+ const quoted = quotedSchema(schema);
13
+ function query(text: string, values?: unknown[]) {
14
+ const db = client.getDb?.();
15
+ if (db === undefined) {
16
+ throw new TypeError("This pg-boss client does not support getDb");
17
+ }
18
+ return db.executeSql(text, values);
19
+ }
20
+ return {
21
+ ...inspectionDeferrals(client),
22
+ busy: (queues: readonly Pick<QueueDefinition, "name">[]) =>
23
+ inspectionOperation(async () => {
24
+ const { rows } = await query(
25
+ `/* jobs inspection busy */ SELECT EXISTS (
26
+ SELECT 1 FROM ${quoted}.job WHERE name = ANY($1::text[]) AND (
27
+ (state < 'active' AND NOT blocked AND start_after <= ${quoted}.job_now()) OR state = 'active'
28
+ )
29
+ ) AS busy`,
30
+ [queues.map(({ name }) => name)],
31
+ );
32
+ return Schema.decodeUnknownSync(Busy)(rows[0]).busy;
33
+ }),
34
+ ...inspectionJobs(client),
35
+ queue: (queue: Pick<QueueDefinition, "name">) => inspectionOperation(() => client.getQueue(queue.name), queue.name),
36
+ schedules: (name?: string, key?: string) =>
37
+ inspectionOperation(() => {
38
+ if (client.getSchedules === undefined) {
39
+ throw new TypeError("This pg-boss client does not support getSchedules");
40
+ }
41
+ return client.getSchedules(name, key);
42
+ }),
43
+ schemaVersion: () =>
44
+ inspectionOperation(() => {
45
+ if (client.schemaVersion === undefined) {
46
+ throw new TypeError("This pg-boss client does not support schemaVersion");
47
+ }
48
+ return client.schemaVersion();
49
+ }),
50
+ snapshot: inspectionSnapshot(
51
+ () => client,
52
+ () => schema,
53
+ ),
54
+ };
55
+ }
@@ -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 { inspectionOperation } from "#server/adapters/inspectionOperation.ts";
3
+ import type { PgBossClient } from "#server/client.ts";
4
+ import type { PgBossError, PgBossPayloadError } from "#server/error.ts";
5
+ import type { SnapshotQueue, UnfinishedJob } from "#server/inspection.ts";
6
+ import { decodeStoredData, quotedSchema } from "#server/internal/storedRows.ts";
7
7
 
8
8
  const Rows = Schema.Array(
9
9
  Schema.Struct({
@@ -15,29 +15,27 @@ const Rows = Schema.Array(
15
15
  }),
16
16
  );
17
17
 
18
- export function testingSnapshot(client: () => PgBoss, schema: () => string) {
18
+ export function inspectionSnapshot(client: () => PgBossClient, schema: () => string) {
19
19
  return <const TQueues extends readonly SnapshotQueue[]>(
20
20
  queues: TQueues,
21
- ): Effect.Effect<
22
- readonly UnfinishedJob<TQueues[number]>[],
23
- PgBossPayloadError | PgBossTestingError,
24
- TQueues[number]["schema"]["DecodingServices"]
25
- > => {
21
+ ): Effect.Effect<readonly UnfinishedJob<TQueues[number]>[], PgBossPayloadError | PgBossError, TQueues[number]["schema"]["DecodingServices"]> => {
26
22
  const byName = new Map<string, TQueues[number]>(queues.map((queue) => [queue.name, queue]));
27
- return testingOperation("snapshot", async () => {
23
+ return inspectionOperation(async () => {
28
24
  const quoted = quotedSchema(schema());
29
- const { rows } = await client()
30
- .getDb()
31
- .executeSql(
32
- `SELECT id, name AS queue, data, start_after AS "startAfter",
25
+ const db = client().getDb?.();
26
+ if (db === undefined) {
27
+ throw new TypeError("This pg-boss client does not support getDb");
28
+ }
29
+ const { rows } = await db.executeSql(
30
+ `SELECT id, name AS queue, data, start_after AS "startAfter",
33
31
  CASE WHEN state = 'retry' AND started_on IS NULL AND start_after > ${quoted}.job_now()
34
32
  AND output ? 'jobDeferral'
35
33
  THEN 'deferred' ELSE state::text END AS state
36
34
  FROM ${quoted}.job
37
35
  WHERE name = ANY($1::text[]) AND state IN ('created', 'retry', 'active', 'failed')
38
36
  ORDER BY created_on, id`,
39
- [[...byName.keys()]],
40
- );
37
+ [[...byName.keys()]],
38
+ );
41
39
  return Schema.decodeUnknownPromise(Rows)(rows);
42
40
  }).pipe(
43
41
  Effect.flatMap((rows) =>
@@ -3,8 +3,8 @@ import { SqlClient } from "effect/sql";
3
3
  import type { Connection } from "effect/sql/SqlConnection";
4
4
  import { getConstructionPlans, getMigrationPlans, PgBoss } from "pg-boss";
5
5
  import pgBossPackage from "pg-boss/package.json" with { type: "json" };
6
- import { jobStorePlans } from "#internal/jobStorePlans.ts";
7
- import type { PgBossSchemaOptions } from "#schema.ts";
6
+ import { jobStorePlans } from "#server/internal/jobStorePlans.ts";
7
+ import type { PgBossSchemaOptions } from "#server/schema.ts";
8
8
  import { runSchemaPlan } from "./runSchemaPlan.ts";
9
9
  import { resumeSchemaIndexes } from "./schemaIndexBuilds.ts";
10
10
 
@@ -0,0 +1,55 @@
1
+ import { type Context, Effect } from "effect";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import { toPgBossError } from "#server/error.ts";
4
+ import type { JobEngine } from "#server/internal/engine.ts";
5
+ import { listJobs } from "./listJobs.ts";
6
+ import { queueAdministration } from "./queueAdministration.ts";
7
+ import { settleDeferral } from "./settleDeferral.ts";
8
+
9
+ export function jobEngine(client: PgBossClient, schema = "pgboss"): Context.Service.Shape<typeof JobEngine> {
10
+ return {
11
+ ...queueAdministration(client),
12
+ getJob: (queue, id) =>
13
+ Effect.tryPromise({
14
+ catch: (error) => toPgBossError("getJob", error, queue),
15
+ try: async () => {
16
+ if (client.findJobs === undefined) {
17
+ throw new TypeError("This pg-boss client does not support findJobs");
18
+ }
19
+ return (await client.findJobs(queue, { id }))[0];
20
+ },
21
+ }),
22
+ listJobs: listJobs(client, schema),
23
+ retry: (queue, id) =>
24
+ Effect.tryPromise({
25
+ catch: (error) => toPgBossError("retry", error, queue),
26
+ try: async () => {
27
+ if (client.findJobs === undefined || client.retry === undefined || client.update === undefined) {
28
+ throw new TypeError("This pg-boss client does not support findJobs, retry and update");
29
+ }
30
+ const job = (await client.findJobs(queue, { id }))[0];
31
+ if (job?.state !== "failed" && job?.state !== "retry") {
32
+ return;
33
+ }
34
+ if (job.state === "failed") {
35
+ await client.retry(queue, id);
36
+ }
37
+ await client.update(queue, undefined, { id, startAfter: 0 });
38
+ },
39
+ }),
40
+ settleDeferral: (job, at, reason, maxDeferrals) =>
41
+ Effect.tryPromise({
42
+ catch: (error) => toPgBossError("settle", error, job.name),
43
+ try: () => settleDeferral(client, schema, job, at, reason, maxDeferrals),
44
+ }).pipe(
45
+ Effect.tap((settled) =>
46
+ Effect.sync(() => {
47
+ if (!settled.claimed || settled.deferred) {
48
+ // Native batch settlement must not match a sibling's new claim at the unchanged retry count.
49
+ job.retryCount = Number.MAX_SAFE_INTEGER;
50
+ }
51
+ }),
52
+ ),
53
+ ),
54
+ };
55
+ }
@@ -0,0 +1,67 @@
1
+ import { type Context, Effect, Exit, Scope } from "effect";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import type { StopOptions } from "#server/clientOptions.ts";
4
+ import { PgBossClientOptionsError, toPgBossError } from "#server/error.ts";
5
+ import { observeClientErrors } from "#server/internal/clientErrors.ts";
6
+ import { jobStorePlans } from "#server/internal/jobStorePlans.ts";
7
+ import type { AcquireClientOptions, ClientEngine } from "#server/internal/lifecycle.ts";
8
+ import { acquireCachedClient, releaseCachedClient } from "./clientCache.ts";
9
+ import { defaultClientFactory } from "./defaultClientFactory.ts";
10
+
11
+ export interface StartingClient {
12
+ readonly client: PgBossClient;
13
+ readonly ready: Promise<void>;
14
+ readonly stop: (options?: StopOptions) => Promise<void>;
15
+ }
16
+
17
+ function startClient(options: AcquireClientOptions, report: (error: Error) => void): StartingClient {
18
+ const client = (options.clientFactory ?? defaultClientFactory)(options.constructor);
19
+ observeClientErrors(client, report);
20
+ let closing = false;
21
+ const ready = (async () => {
22
+ await client.start();
23
+ if (!closing && options.constructor.migrate !== false && client.getDb !== undefined) {
24
+ for (const plan of jobStorePlans(options.constructor.schema ?? "pgboss")) {
25
+ await client.getDb().executeSql(plan);
26
+ }
27
+ }
28
+ })();
29
+ return {
30
+ client,
31
+ ready,
32
+ stop: (settings) => {
33
+ closing = true;
34
+ return client.stop(settings);
35
+ },
36
+ };
37
+ }
38
+
39
+ const acquire = Effect.fnUntraced(function* (options: AcquireClientOptions, report: (error: Error) => void, stop?: StopOptions) {
40
+ const scope = yield* Scope.fork(yield* Scope.Scope);
41
+ return yield* Effect.gen(function* () {
42
+ const lease = yield* Effect.acquireRelease(
43
+ Effect.try({
44
+ catch: (error) => (error instanceof PgBossClientOptionsError ? error : toPgBossError("start", error)),
45
+ try: () =>
46
+ options.clientCacheKey === undefined
47
+ ? { ...startClient(options, report), reused: false }
48
+ : acquireCachedClient(options.clientCacheKey, options.constructor, () => startClient(options, report)),
49
+ }),
50
+ (acquired) =>
51
+ Effect.tryPromise({
52
+ catch: (error) => toPgBossError("stop", error),
53
+ try: async () => {
54
+ const client = options.clientCacheKey === undefined ? acquired : releaseCachedClient(options.clientCacheKey);
55
+ await client?.stop(stop);
56
+ },
57
+ }).pipe(Effect.catch(Effect.logError)),
58
+ );
59
+ yield* Effect.tryPromise({ catch: (error) => toPgBossError("start", error), try: () => lease.ready });
60
+ return { ...(options.clientCacheKey === undefined ? {} : { cacheKey: options.clientCacheKey }), client: lease.client, reused: lease.reused };
61
+ }).pipe(
62
+ Effect.provideService(Scope.Scope, scope),
63
+ Effect.onError((cause) => Scope.close(scope, Exit.failCause(cause))),
64
+ );
65
+ });
66
+
67
+ export const clientEngine: Context.Service.Shape<typeof ClientEngine> = { acquire };
@@ -0,0 +1,43 @@
1
+ import { type Context, Effect } from "effect";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import { toPgBossError } from "#server/error.ts";
4
+ import { deadLetterQueueName } from "#server/health.ts";
5
+ import type { JobEngine } from "#server/internal/engine.ts";
6
+ import { quotedSchema } from "#server/internal/storedRows.ts";
7
+
8
+ export function listJobs(client: PgBossClient, schema: string): Context.Service.Shape<typeof JobEngine>["listJobs"] {
9
+ return (listing, queue, after, limit) =>
10
+ Effect.tryPromise({
11
+ catch: (error) => toPgBossError(listing, error, queue),
12
+ try: async () => {
13
+ if (client.getDb === undefined) {
14
+ throw new TypeError("This pg-boss client does not support getDb");
15
+ }
16
+ const quoted = quotedSchema(schema);
17
+ const { rows: storedRows } = await client.getDb().executeSql(
18
+ `SELECT
19
+ id,
20
+ name AS queue,
21
+ state,
22
+ retry_count AS "retryCount",
23
+ retry_limit AS "retryLimit",
24
+ created_on AS "createdOn",
25
+ started_on AS "startedOn",
26
+ completed_on AS "completedOn",
27
+ output,
28
+ data,
29
+ source_id AS "sourceId",
30
+ source_output AS "sourceOutput",
31
+ to_json(created_on) #>> '{}' AS "cursorAt"
32
+ FROM ${quoted}.job
33
+ WHERE name = $1
34
+ ${listing === "failedJobs" ? "AND state = 'failed'" : ""}
35
+ AND ($2::timestamptz IS NULL OR (created_on, id) < ($2::timestamptz, $3::uuid))
36
+ ORDER BY created_on DESC, id DESC
37
+ LIMIT $4`,
38
+ [listing === "failedJobs" ? queue : deadLetterQueueName(queue), after?.[0] ?? null, after?.[1] ?? null, limit + 1],
39
+ );
40
+ return storedRows;
41
+ },
42
+ });
43
+ }
@@ -0,0 +1,15 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ export function payloadKey(parts: readonly string[], payload: object): string {
4
+ return JSON.stringify(parts.map((part) => [part, typeof Reflect.get(payload, part), String(Reflect.get(payload, part))]));
5
+ }
6
+
7
+ export function payloadJobId(queue: string, parts: readonly string[], payload: object): string {
8
+ const bytes = createHash("sha256")
9
+ .update(JSON.stringify([queue, payloadKey(parts, payload)]))
10
+ .digest();
11
+ bytes.writeUInt8((bytes.readUInt8(6) & 0x0f) | 0x80, 6);
12
+ bytes.writeUInt8((bytes.readUInt8(8) & 0x3f) | 0x80, 8);
13
+ const hex = bytes.subarray(0, 16).toString("hex");
14
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
15
+ }
@@ -0,0 +1,47 @@
1
+ import { Effect } from "effect";
2
+ import type { PgBossClient } from "#server/client.ts";
3
+ import { PgBossNotFoundError, toPgBossError } from "#server/error.ts";
4
+ import type { PgBossService } from "#server/service.ts";
5
+
6
+ export function queueAdministration(client: PgBossClient): Pick<PgBossService, "deleteQueue" | "refreshQueueStats" | "unschedule"> {
7
+ return {
8
+ deleteQueue: (queue) =>
9
+ Effect.tryPromise({
10
+ catch: (error) => (error instanceof PgBossNotFoundError ? error : toPgBossError("deleteQueue", error, queue.name)),
11
+ try: async () => {
12
+ if (client.deleteQueue === undefined) {
13
+ throw new TypeError("This pg-boss client does not support deleteQueue");
14
+ }
15
+ if ((await client.getQueue(queue.name)) === null) {
16
+ throw new PgBossNotFoundError({ operation: "deleteQueue", queue: queue.name });
17
+ }
18
+ await client.offWork(queue.name);
19
+ await client.deleteQueue(queue.name);
20
+ },
21
+ }),
22
+ refreshQueueStats: (queue) =>
23
+ Effect.tryPromise({
24
+ catch: (error) => toPgBossError("refreshQueueStats", error, queue?.name),
25
+ try: async () => {
26
+ if (client.supervise === undefined) {
27
+ throw new TypeError("This pg-boss client does not support supervise");
28
+ }
29
+ await client.supervise(queue?.name);
30
+ },
31
+ }),
32
+ unschedule: (schedule) =>
33
+ Effect.tryPromise({
34
+ catch: (error) => (error instanceof PgBossNotFoundError ? error : toPgBossError("unschedule", error, schedule.name)),
35
+ try: async () => {
36
+ if (client.getSchedule === undefined || client.unschedule === undefined) {
37
+ throw new TypeError("This pg-boss client does not support getSchedule and unschedule");
38
+ }
39
+ const key = schedule.scheduleOptions.key ?? "";
40
+ if ((await client.getSchedule(schedule.name, key)) === null) {
41
+ throw new PgBossNotFoundError({ key, operation: "unschedule", queue: schedule.name });
42
+ }
43
+ await client.unschedule(schedule.name, key);
44
+ },
45
+ }),
46
+ };
47
+ }
@@ -1,6 +1,6 @@
1
1
  import { Effect } from "effect";
2
2
 
3
- export function testingSignal() {
3
+ export function queueSignal() {
4
4
  let revision = 0;
5
5
  const listeners = new Set<(revision: number) => void>();
6
6
  return {