@shivaedev/effect-pg-boss 0.14.0 → 0.15.1

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 (79) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +6 -2
  3. package/dist/server/client.d.ts +1 -2
  4. package/dist/server/client.d.ts.map +1 -1
  5. package/dist/server/client.js +2 -2
  6. package/dist/server/client.js.map +1 -1
  7. package/dist/server/internal/countsFor.d.ts.map +1 -1
  8. package/dist/server/internal/countsFor.js +3 -2
  9. package/dist/server/internal/countsFor.js.map +1 -1
  10. package/dist/server/internal/deferralStorePlan.d.ts.map +1 -1
  11. package/dist/server/internal/deferralStorePlan.js +3 -2
  12. package/dist/server/internal/deferralStorePlan.js.map +1 -1
  13. package/dist/server/internal/expireAttempt.d.ts.map +1 -1
  14. package/dist/server/internal/expireAttempt.js +2 -1
  15. package/dist/server/internal/expireAttempt.js.map +1 -1
  16. package/dist/server/internal/jobControl.d.ts.map +1 -1
  17. package/dist/server/internal/jobControl.js +4 -4
  18. package/dist/server/internal/jobControl.js.map +1 -1
  19. package/dist/server/internal/listJobs.js +6 -6
  20. package/dist/server/internal/listJobs.js.map +1 -1
  21. package/dist/server/internal/nativeClient.d.ts +3 -0
  22. package/dist/server/internal/nativeClient.d.ts.map +1 -0
  23. package/dist/server/internal/nativeClient.js +28 -0
  24. package/dist/server/internal/nativeClient.js.map +1 -0
  25. package/dist/server/internal/observeTestingSettlements.d.ts +1 -1
  26. package/dist/server/internal/observeTestingSettlements.d.ts.map +1 -1
  27. package/dist/server/internal/observeTestingSettlements.js +2 -2
  28. package/dist/server/internal/observeTestingSettlements.js.map +1 -1
  29. package/dist/server/internal/settleDeferral.d.ts.map +1 -1
  30. package/dist/server/internal/settleDeferral.js +3 -2
  31. package/dist/server/internal/settleDeferral.js.map +1 -1
  32. package/dist/server/internal/storedRows.d.ts +6 -0
  33. package/dist/server/internal/storedRows.d.ts.map +1 -0
  34. package/dist/server/internal/storedRows.js +10 -0
  35. package/dist/server/internal/storedRows.js.map +1 -0
  36. package/dist/server/internal/testingClient.d.ts +2 -0
  37. package/dist/server/internal/testingClient.d.ts.map +1 -1
  38. package/dist/server/internal/testingClient.js +12 -1
  39. package/dist/server/internal/testingClient.js.map +1 -1
  40. package/dist/server/internal/testingDeferrals.d.ts.map +1 -1
  41. package/dist/server/internal/testingDeferrals.js +3 -2
  42. package/dist/server/internal/testingDeferrals.js.map +1 -1
  43. package/dist/server/internal/testingIdle.d.ts +16 -0
  44. package/dist/server/internal/testingIdle.d.ts.map +1 -0
  45. package/dist/server/internal/testingIdle.js +31 -0
  46. package/dist/server/internal/testingIdle.js.map +1 -0
  47. package/dist/server/internal/testingReadout.d.ts +2 -2
  48. package/dist/server/internal/testingReadout.d.ts.map +1 -1
  49. package/dist/server/internal/testingReadout.js +4 -4
  50. package/dist/server/internal/testingReadout.js.map +1 -1
  51. package/dist/server/internal/testingSignal.d.ts.map +1 -1
  52. package/dist/server/internal/testingSignal.js +4 -2
  53. package/dist/server/internal/testingSignal.js.map +1 -1
  54. package/dist/server/internal/testingSnapshot.d.ts +6 -0
  55. package/dist/server/internal/testingSnapshot.d.ts.map +1 -0
  56. package/dist/server/internal/testingSnapshot.js +32 -0
  57. package/dist/server/internal/testingSnapshot.js.map +1 -0
  58. package/dist/server/testing.d.ts +14 -4
  59. package/dist/server/testing.d.ts.map +1 -1
  60. package/dist/server/testing.js +8 -2
  61. package/dist/server/testing.js.map +1 -1
  62. package/package.json +4 -4
  63. package/src/server/client.ts +3 -2
  64. package/src/server/internal/countsFor.ts +3 -2
  65. package/src/server/internal/deferralStorePlan.ts +3 -2
  66. package/src/server/internal/expireAttempt.ts +2 -1
  67. package/src/server/internal/jobControl.ts +4 -7
  68. package/src/server/internal/listJobs.ts +6 -7
  69. package/src/server/internal/nativeClient.ts +30 -0
  70. package/src/server/internal/observeTestingSettlements.ts +2 -2
  71. package/src/server/internal/settleDeferral.ts +3 -2
  72. package/src/server/internal/storedRows.ts +17 -0
  73. package/src/server/internal/testingClient.ts +14 -1
  74. package/src/server/internal/testingDeferrals.ts +3 -2
  75. package/src/server/internal/testingIdle.ts +52 -0
  76. package/src/server/internal/testingReadout.ts +4 -11
  77. package/src/server/internal/testingSignal.ts +4 -2
  78. package/src/server/internal/testingSnapshot.ts +53 -0
  79. package/src/server/testing.ts +21 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testingIdle.js","sourceRoot":"","sources":["../../../src/server/internal/testingIdle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAY/D,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;AAErD,MAAM,UAAU,WAAW,CAC1B,MAAoB,EACpB,MAAoB,EACpB,IAAiB,EACjB,MAAsH;IAEtH,MAAM,IAAI,GAAG,gBAAgB,CAAC,aAAa,EAAE,KAAK,IAAI,EAAE;QACvD,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;QACtC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,EAAE;aAC7B,KAAK,EAAE;aACP,UAAU,CACV;qBACiB,MAAM;;6DAEkC,MAAM;;;cAGrD,EACV,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAClB,CAAC;QACH,OAAO,CAAC,MAAM,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChE,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC1B,OAAO,IAAI,EAAE,CAAC;YACb,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;YACxC,oGAAoG;YACpG,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACpE,IAAI,IAAI,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;gBAC7D,OAAO;YACR,CAAC;YACD,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import { Effect } from "effect";
2
2
  import type { FindJobsOptions, PgBoss } from "pg-boss";
3
3
  import type { JobPayloadSchema, QueueDefinition } from "#definition.ts";
4
- import { PgBossPayloadError, PgBossTestingError } from "#error.ts";
4
+ import { PgBossTestingError } from "#error.ts";
5
5
  export declare function testingOperation<A>(operation: string, run: () => Promise<A>, queue?: string): Effect.Effect<A, PgBossTestingError, never>;
6
6
  export declare function testingReadout(client: () => PgBoss): <TName extends string, TPayload extends JobPayloadSchema>(queue: QueueDefinition<TName, TPayload>, options?: FindJobsOptions) => Effect.Effect<{
7
7
  id: string;
@@ -40,5 +40,5 @@ export declare function testingReadout(client: () => PgBoss): <TName extends str
40
40
  sourceOutput: object | null;
41
41
  sourceRootId: string | null;
42
42
  data: TPayload["Type"];
43
- }[], PgBossPayloadError | PgBossTestingError, TPayload["DecodingServices"]>;
43
+ }[], import("#error.ts").PgBossPayloadError | PgBossTestingError, TPayload["DecodingServices"]>;
44
44
  //# sourceMappingURL=testingReadout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testingReadout.d.ts","sourceRoot":"","sources":["../../../src/server/internal/testingReadout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAoB,MAAM,QAAQ,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAGnE,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,+CAK3F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,MAAM,IAC1C,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,gBAAgB,SAAS,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,YAAY,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4EAWnI"}
1
+ {"version":3,"file":"testingReadout.d.ts","sourceRoot":"","sources":["../../../src/server/internal/testingReadout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,MAAM,QAAQ,CAAC;AAC1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAG/C,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,+CAK3F;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,MAAM,IAC1C,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,gBAAgB,SAAS,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,YAAY,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gGAInI"}
@@ -1,6 +1,6 @@
1
- import { Effect, Redacted, Schema } from "effect";
2
- import { PgBossPayloadError, PgBossTestingError } from "#error.ts";
3
- import { payloadOf } from "#internal/tracing.ts";
1
+ import { Effect, Redacted } from "effect";
2
+ import { PgBossTestingError } from "#error.ts";
3
+ import { decodeStoredData } from "#internal/storedRows.ts";
4
4
  export function testingOperation(operation, run, queue) {
5
5
  return Effect.tryPromise({
6
6
  catch: (original) => new PgBossTestingError({ operation, original: Redacted.make(original), queue }),
@@ -8,6 +8,6 @@ export function testingOperation(operation, run, queue) {
8
8
  });
9
9
  }
10
10
  export function testingReadout(client) {
11
- return (queue, options) => testingOperation("jobs", () => client().findJobs(queue.name, options), queue.name).pipe(Effect.flatMap((jobs) => Effect.forEach(jobs, (job) => Schema.decodeUnknownEffect(queue.schema)(payloadOf(job.data)).pipe(Effect.mapError((original) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(original), queue: queue.name })), Effect.map((data) => ({ ...job, data }))))));
11
+ return (queue, options) => testingOperation("jobs", () => client().findJobs(queue.name, options), queue.name).pipe(Effect.flatMap((jobs) => Effect.forEach(jobs, (job) => decodeStoredData(queue, job.data).pipe(Effect.map((data) => ({ ...job, data }))))));
12
12
  }
13
13
  //# sourceMappingURL=testingReadout.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"testingReadout.js","sourceRoot":"","sources":["../../../src/server/internal/testingReadout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGlD,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjD,MAAM,UAAU,gBAAgB,CAAI,SAAiB,EAAE,GAAqB,EAAE,KAAc;IAC3F,OAAO,MAAM,CAAC,UAAU,CAAC;QACxB,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;QACpG,GAAG,EAAE,GAAG;KACR,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAoB;IAClD,OAAO,CAA0D,KAAuC,EAAE,OAAyB,EAAE,EAAE,CACtI,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAU,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAC/F,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACvB,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAC5B,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CACjE,MAAM,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,EACpI,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CACxC,CACD,CACD,CACD,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"testingReadout.js","sourceRoot":"","sources":["../../../src/server/internal/testingReadout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAG1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAE3D,MAAM,UAAU,gBAAgB,CAAI,SAAiB,EAAE,GAAqB,EAAE,KAAc;IAC3F,OAAO,MAAM,CAAC,UAAU,CAAC;QACxB,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC;QACpG,GAAG,EAAE,GAAG;KACR,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAoB;IAClD,OAAO,CAA0D,KAAuC,EAAE,OAAyB,EAAE,EAAE,CACtI,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAU,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAC/F,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CACzI,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"testingSignal.d.ts","sourceRoot":"","sources":["../../../src/server/internal/testingSignal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,wBAAgB,aAAa;IAI3B,OAAO;IAOP,QAAQ;IACR,aAAa,UAAU,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;EAatD"}
1
+ {"version":3,"file":"testingSignal.d.ts","sourceRoot":"","sources":["../../../src/server/internal/testingSignal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,wBAAgB,aAAa;IAI3B,OAAO;IASP,QAAQ;IACR,aAAa,UAAU,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;EAatD"}
@@ -5,10 +5,12 @@ export function testingSignal() {
5
5
  return {
6
6
  changed() {
7
7
  revision += 1;
8
- for (const listener of listeners) {
8
+ // A resumed waiter can wait again synchronously; it must wait for the next change, not this one.
9
+ const waiting = [...listeners];
10
+ listeners.clear();
11
+ for (const listener of waiting) {
9
12
  listener(revision);
10
13
  }
11
- listeners.clear();
12
14
  },
13
15
  revision: Effect.sync(() => revision),
14
16
  waitForChange: (after) => Effect.callback((resume) => {
@@ -1 +1 @@
1
- {"version":3,"file":"testingSignal.js","sourceRoot":"","sources":["../../../src/server/internal/testingSignal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,UAAU,aAAa;IAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,SAAS,GAAG,IAAI,GAAG,EAA8B,CAAC;IACxD,OAAO;QACN,OAAO;YACN,QAAQ,IAAI,CAAC,CAAC;YACd,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBAClC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpB,CAAC;YACD,SAAS,CAAC,KAAK,EAAE,CAAC;QACnB,CAAC;QACD,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;QACrC,aAAa,EAAE,CAAC,KAAa,EAAyB,EAAE,CACvD,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gBACxB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACjC,OAAO;YACR,CAAC;YACD,SAAS,QAAQ,CAAC,OAAe;gBAChC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;YACjC,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC;KACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"testingSignal.js","sourceRoot":"","sources":["../../../src/server/internal/testingSignal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,UAAU,aAAa;IAC5B,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,MAAM,SAAS,GAAG,IAAI,GAAG,EAA8B,CAAC;IACxD,OAAO;QACN,OAAO;YACN,QAAQ,IAAI,CAAC,CAAC;YACd,iGAAiG;YACjG,MAAM,OAAO,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;YAC/B,SAAS,CAAC,KAAK,EAAE,CAAC;YAClB,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;gBAChC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACpB,CAAC;QACF,CAAC;QACD,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;QACrC,aAAa,EAAE,CAAC,KAAa,EAAyB,EAAE,CACvD,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE;YAC1B,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;gBACxB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACjC,OAAO;YACR,CAAC;YACD,SAAS,QAAQ,CAAC,OAAe;gBAChC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;YACjC,CAAC;YACD,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YACxB,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC;QACtD,CAAC,CAAC;KACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { Effect } from "effect";
2
+ import type { PgBoss } from "pg-boss";
3
+ import type { PgBossPayloadError, PgBossTestingError } from "#error.ts";
4
+ import type { SnapshotQueue, UnfinishedJob } from "#testing.ts";
5
+ export declare function testingSnapshot(client: () => PgBoss, schema: () => string): <const TQueues extends readonly SnapshotQueue[]>(queues: TQueues) => Effect.Effect<readonly UnfinishedJob<TQueues[number]>[], PgBossPayloadError | PgBossTestingError, TQueues[number]["schema"]["DecodingServices"]>;
6
+ //# sourceMappingURL=testingSnapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testingSnapshot.d.ts","sourceRoot":"","sources":["../../../src/server/internal/testingSnapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAGxE,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAYhE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,MAAM,EAAE,MAAM,EAAE,MAAM,MAAM,IACjE,KAAK,CAAC,OAAO,SAAS,SAAS,aAAa,EAAE,UAC7C,OAAO,KACb,MAAM,CAAC,MAAM,CACf,SAAS,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,EACzC,kBAAkB,GAAG,kBAAkB,EACvC,OAAO,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,kBAAkB,CAAC,CAC7C,CA4BD"}
@@ -0,0 +1,32 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { decodeStoredData, quotedSchema } from "#internal/storedRows.ts";
3
+ import { testingOperation } from "#internal/testingReadout.ts";
4
+ const Rows = Schema.Array(Schema.Struct({
5
+ data: Schema.Unknown,
6
+ id: Schema.String,
7
+ queue: Schema.String,
8
+ startAfter: Schema.DateTimeUtcFromDate,
9
+ state: Schema.Literals(["created", "retry", "active", "failed"]),
10
+ }));
11
+ export function testingSnapshot(client, schema) {
12
+ return (queues) => {
13
+ const byName = new Map(queues.map((queue) => [queue.name, queue]));
14
+ return testingOperation("snapshot", async () => {
15
+ const quoted = quotedSchema(schema());
16
+ const { rows } = await client()
17
+ .getDb()
18
+ .executeSql(`SELECT id, name AS queue, state, data, start_after AS "startAfter"
19
+ FROM ${quoted}.job
20
+ WHERE name = ANY($1::text[]) AND state IN ('created', 'retry', 'active', 'failed')
21
+ ORDER BY created_on, id`, [[...byName.keys()]]);
22
+ return Schema.decodeUnknownPromise(Rows)(rows);
23
+ }).pipe(Effect.flatMap((rows) => Effect.forEach(rows, ({ data, queue: name, ...row }) => {
24
+ const queue = byName.get(name);
25
+ if (queue === undefined) {
26
+ return Effect.die(new Error(`The snapshot returned a job of an unrequested queue ${name}`));
27
+ }
28
+ return decodeStoredData(queue, data).pipe(Effect.map((decoded) => ({ ...row, data: decoded, queue: queue.name })));
29
+ })));
30
+ };
31
+ }
32
+ //# sourceMappingURL=testingSnapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testingSnapshot.js","sourceRoot":"","sources":["../../../src/server/internal/testingSnapshot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxC,OAAO,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAG/D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CACxB,MAAM,CAAC,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC,OAAO;IACpB,EAAE,EAAE,MAAM,CAAC,MAAM;IACjB,KAAK,EAAE,MAAM,CAAC,MAAM;IACpB,UAAU,EAAE,MAAM,CAAC,mBAAmB;IACtC,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;CAChE,CAAC,CACF,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,MAAoB,EAAE,MAAoB;IACzE,OAAO,CACN,MAAe,EAKd,EAAE;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAA0B,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;QAC5F,OAAO,gBAAgB,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;YACtC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,EAAE;iBAC7B,KAAK,EAAE;iBACP,UAAU,CACV;YACO,MAAM;;6BAEW,EACxB,CAAC,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CACpB,CAAC;YACH,OAAO,MAAM,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC,IAAI,CACN,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACvB,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE;YACtD,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC/B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,uDAAuD,IAAI,EAAE,CAAC,CAAC,CAAC;YAC7F,CAAC;YACD,OAAO,gBAAgB,CAAqD,KAAK,EAAE,IAAI,CAAC,CAAC,IAAI,CAC5F,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,EAAkC,EAAE,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CACvG,CAAC;QACH,CAAC,CAAC,CACF,CACD,CAAC;IACH,CAAC,CAAC;AACH,CAAC"}
@@ -1,7 +1,15 @@
1
- import { Effect } from "effect";
1
+ import { type DateTime, Effect } from "effect";
2
2
  import type { PgBossClientFactory } from "#client.ts";
3
- import type { QueueDefinition } from "#definition.ts";
3
+ import type { JobPayloadSchema, QueueDefinition } from "#definition.ts";
4
4
  import { PgBossTestingError } from "#error.ts";
5
+ export type SnapshotQueue = Pick<QueueDefinition<string, JobPayloadSchema>, "name" | "schema">;
6
+ export interface UnfinishedJob<TQueue extends SnapshotQueue> {
7
+ readonly data: TQueue["schema"]["Type"];
8
+ readonly id: string;
9
+ readonly queue: TQueue["name"];
10
+ readonly startAfter: DateTime.Utc;
11
+ readonly state: "active" | "created" | "failed" | "retry";
12
+ }
5
13
  export declare const testRetryPolicy: Readonly<{
6
14
  retryBackoff: false;
7
15
  retryDelay: 0;
@@ -11,7 +19,7 @@ export interface PgBossTestingOptions {
11
19
  }
12
20
  export declare function makePgBossTesting(options?: PgBossTestingOptions): {
13
21
  deferred: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<{
14
- at: import("effect/DateTime").Utc;
22
+ at: DateTime.Utc;
15
23
  reason: string;
16
24
  }[], PgBossTestingError, never>;
17
25
  runDeferredNow: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<void, PgBossTestingError, never>;
@@ -20,7 +28,7 @@ export declare function makePgBossTesting(options?: PgBossTestingOptions): {
20
28
  clientFactory: PgBossClientFactory;
21
29
  expireAfter: (queue: Pick<QueueDefinition, "name">, attempts: number) => Effect.Effect<void, PgBossTestingError, never>;
22
30
  failNextSend: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<void, never, never>;
23
- jobs: <TName extends string, TPayload extends import("#definition.ts").JobPayloadSchema>(queue: QueueDefinition<TName, TPayload>, options?: import("pg-boss").FindJobsOptions) => Effect.Effect<{
31
+ jobs: <TName extends string, TPayload extends JobPayloadSchema>(queue: QueueDefinition<TName, TPayload>, options?: import("pg-boss").FindJobsOptions) => Effect.Effect<{
24
32
  id: string;
25
33
  name: string;
26
34
  retryCount: number;
@@ -60,7 +68,9 @@ export declare function makePgBossTesting(options?: PgBossTestingOptions): {
60
68
  }[], import("#error.ts").PgBossPayloadError | PgBossTestingError, TPayload["DecodingServices"]>;
61
69
  revision: Effect.Effect<number, never, never>;
62
70
  schemaVersion: Effect.Effect<number | null, PgBossTestingError, never>;
71
+ snapshot: <const TQueues extends readonly SnapshotQueue[]>(queues: TQueues) => Effect.Effect<readonly UnfinishedJob<TQueues[number]>[], import("#error.ts").PgBossPayloadError | PgBossTestingError, TQueues[number]["schema"]["DecodingServices"]>;
63
72
  waitForChange: (after: number) => Effect.Effect<number>;
73
+ waitForIdle: Effect.Effect<void, PgBossTestingError, never>;
64
74
  };
65
75
  export type PgBossTesting = ReturnType<typeof makePgBossTesting>;
66
76
  //# sourceMappingURL=testing.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/server/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAY,MAAM,QAAQ,CAAC;AAE1C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAM/C,eAAO,MAAM,eAAe;;;EAAwD,CAAC;AAErF,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,eAAe,CAAC;CAC9C;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,oBAAyB;;;;;;8BA0BxC,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,eAAe,CAAC,sBAAsB,MAAM;mCAqBtE,MAAM;;yBAOhB,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,YAAY,MAAM;0BAU9C,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMpD;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
1
+ {"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/server/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,EAAY,MAAM,QAAQ,CAAC;AAEzD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACxE,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAS/C,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC,CAAC;AAE/F,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,aAAa;IAC1D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC;IACxC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,OAAO,CAAC;CAC1D;AAED,eAAO,MAAM,eAAe;;;EAAwD,CAAC;AAErF,MAAM,WAAW,oBAAoB;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,eAAe,CAAC;CAC9C;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,oBAAyB;;;;;;8BA4BxC,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,eAAe,CAAC,sBAAsB,MAAM;mCAqBtE,MAAM;;yBAOhB,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,YAAY,MAAM;0BAU9C,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQpD;AAED,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
@@ -1,20 +1,24 @@
1
1
  import { Effect, Redacted } from "effect";
2
- import { PgBoss } from "pg-boss";
3
2
  import { PgBossTestingError } from "#error.ts";
3
+ import { nativeClient } from "#internal/nativeClient.ts";
4
4
  import { testingClient } from "#internal/testingClient.ts";
5
5
  import { testingDeferrals } from "#internal/testingDeferrals.ts";
6
+ import { testingIdle } from "#internal/testingIdle.ts";
6
7
  import { testingOperation, testingReadout } from "#internal/testingReadout.ts";
7
8
  import { testingSignal } from "#internal/testingSignal.ts";
9
+ import { testingSnapshot } from "#internal/testingSnapshot.ts";
8
10
  export const testRetryPolicy = Object.freeze({ retryBackoff: false, retryDelay: 0 });
9
11
  export function makePgBossTesting(options = {}) {
10
12
  let current;
11
13
  let schema = "pgboss";
12
14
  const signal = testingSignal();
15
+ const work = { batches: new Set(), queues: new Set() };
13
16
  const controls = {
14
17
  changed: signal.changed,
15
18
  expirations: new Map(),
16
19
  failures: new Set(),
17
20
  retryPolicy: options.retryPolicy ?? {},
21
+ work,
18
22
  };
19
23
  function client() {
20
24
  if (current === undefined) {
@@ -27,7 +31,7 @@ export function makePgBossTesting(options = {}) {
27
31
  throw new Error("A testing controller owns one jobs client; create a controller per runtime");
28
32
  }
29
33
  schema = clientOptions.schema ?? "pgboss";
30
- current = new PgBoss({ ...clientOptions, "__test__enableSpies": true });
34
+ current = nativeClient({ ...clientOptions, "__test__enableSpies": true });
31
35
  return testingClient(current, clientOptions.schema ?? "pgboss", controls);
32
36
  };
33
37
  return {
@@ -67,7 +71,9 @@ export function makePgBossTesting(options = {}) {
67
71
  jobs: testingReadout(client),
68
72
  revision: signal.revision,
69
73
  schemaVersion: testingOperation("schemaVersion", () => client().schemaVersion()),
74
+ snapshot: testingSnapshot(client, () => schema),
70
75
  waitForChange: signal.waitForChange,
76
+ waitForIdle: testingIdle(client, () => schema, work, signal),
71
77
  };
72
78
  }
73
79
  //# sourceMappingURL=testing.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"testing.js","sourceRoot":"","sources":["../../src/server/testing.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"testing.js","sourceRoot":"","sources":["../../src/server/testing.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/effect-pg-boss",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "description": "Effect-native jobs and lifecycle management for pg-boss",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-pg-boss#readme",
6
6
  "bugs": {
@@ -42,14 +42,14 @@
42
42
  ],
43
43
  "devDependencies": {
44
44
  "@shivaedev/effect-test": "0.7.1",
45
- "@shivaedev/effect-test-sql": "0.8.1",
46
- "@shivaedev/quality": "0.31.0",
45
+ "@shivaedev/effect-test-sql": "0.8.2",
46
+ "@shivaedev/quality": "0.32.0",
47
47
  "@shivaedev/test-story": "0.17.0",
48
48
  "@types/node": "24.19.2",
49
49
  "effect": "4.0.4",
50
50
  "pg-boss": "12.37.1",
51
51
  "typescript": "7.0.2",
52
- "vitest": "5.0.3"
52
+ "vitest": "5.0.4"
53
53
  },
54
54
  "peerDependencies": {
55
55
  "effect": "4.0.4",
@@ -3,6 +3,7 @@ import type {
3
3
  FindJobsOptions,
4
4
  Job,
5
5
  JobWithMetadata,
6
+ PgBoss,
6
7
  Queue,
7
8
  QueueResult,
8
9
  ScheduleOptions,
@@ -10,7 +11,7 @@ import type {
10
11
  StopOptions,
11
12
  WorkOptions,
12
13
  } from "pg-boss";
13
- import { PgBoss } from "pg-boss";
14
+ import { nativeClient } from "#internal/nativeClient.ts";
14
15
 
15
16
  export interface PgBossClient {
16
17
  readonly complete?: PgBoss["complete"];
@@ -36,4 +37,4 @@ export interface PgBossClient {
36
37
 
37
38
  export type PgBossClientFactory = (options: ConstructorOptions) => PgBossClient;
38
39
 
39
- export const defaultClientFactory: PgBossClientFactory = (options) => new PgBoss(options);
40
+ export const defaultClientFactory: PgBossClientFactory = nativeClient;
@@ -2,6 +2,7 @@ import { Effect, Schema } from "effect";
2
2
  import type { PgBossClient } from "#client.ts";
3
3
  import { toPgBossError } from "#error.ts";
4
4
  import type { QueueCounts } from "#health.ts";
5
+ import { quotedSchema } from "#internal/storedRows.ts";
5
6
 
6
7
  const Counts = Schema.Struct({
7
8
  activeCount: Schema.Number,
@@ -17,14 +18,14 @@ export function countsFor(client: PgBossClient, schema: string, name: string): E
17
18
  if (client.getDb === undefined) {
18
19
  throw new TypeError("This pg-boss client does not support getDb");
19
20
  }
20
- const quotedSchema = `"${schema.replaceAll('"', '""')}"`;
21
+ const quoted = quotedSchema(schema);
21
22
  const { rows } = await client.getDb().executeSql(
22
23
  `SELECT
23
24
  count(*) FILTER (WHERE state = 'active')::int AS "activeCount",
24
25
  count(*) FILTER (WHERE state = 'failed')::int AS "failedCount",
25
26
  count(*) FILTER (WHERE state IN ('created', 'retry'))::int AS "queuedCount",
26
27
  count(*)::int AS "totalCount"
27
- FROM ${quotedSchema}.job WHERE name = $1`,
28
+ FROM ${quoted}.job WHERE name = $1`,
28
29
  [name],
29
30
  );
30
31
  return Schema.decodeUnknownPromise(Counts)(rows[0]);
@@ -1,7 +1,8 @@
1
- import { STATELY_DEFERRAL_POLICY } from "./deferral.ts";
1
+ import { STATELY_DEFERRAL_POLICY } from "#internal/deferral.ts";
2
+ import { quotedSchema } from "#internal/storedRows.ts";
2
3
 
3
4
  export function deferralStorePlan(schema: string): string {
4
- const quoted = `"${schema.replaceAll('"', '""')}"`;
5
+ const quoted = quotedSchema(schema);
5
6
  const jobTable = `${quoted}.job`.replaceAll("'", "''");
6
7
  const key = `${schema}.effect_job_deferral`.replaceAll("'", "''");
7
8
  const body = `BEGIN
@@ -1,10 +1,11 @@
1
1
  import type { Job, PgBoss } from "pg-boss";
2
+ import { quotedSchema } from "#internal/storedRows.ts";
2
3
 
3
4
  export async function expireAttempt(client: PgBoss, schema: string, job: Job<unknown>, cause: "expiry" | "heartbeat" = "expiry"): Promise<void> {
4
5
  if ((await client.schemaVersion()) !== 45) {
5
6
  throw new Error("Testing expiry requires pg-boss schema version 45");
6
7
  }
7
- const quoted = `"${schema.replaceAll('"', '""')}"`;
8
+ const quoted = quotedSchema(schema);
8
9
  const timestamp = cause === "expiry" ? "started_on" : "heartbeat_on";
9
10
  const seconds = cause === "expiry" ? "expire_seconds" : "heartbeat_seconds";
10
11
  await client.getDb().executeSql(
@@ -1,7 +1,7 @@
1
- import { Effect, Option, Redacted, Schema } from "effect";
1
+ import { Effect, Option } from "effect";
2
2
  import type { PgBossClient } from "#client.ts";
3
- import { PgBossPayloadError, toPgBossError } from "#error.ts";
4
- import { payloadOf } from "#internal/tracing.ts";
3
+ import { toPgBossError } from "#error.ts";
4
+ import { decodeStoredData } from "#internal/storedRows.ts";
5
5
  import type { PgBossService } from "#service.ts";
6
6
 
7
7
  export function getJobFor(client: PgBossClient): PgBossService["getJob"] {
@@ -18,10 +18,7 @@ export function getJobFor(client: PgBossClient): PgBossService["getJob"] {
18
18
  Effect.flatMap((job) =>
19
19
  job === undefined
20
20
  ? Effect.succeed(Option.none())
21
- : Schema.decodeUnknownEffect(queue.schema)(payloadOf(job.data)).pipe(
22
- Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue: queue.name })),
23
- Effect.map((data) => Option.some({ ...job, data })),
24
- ),
21
+ : decodeStoredData(queue, job.data).pipe(Effect.map((data) => Option.some({ ...job, data }))),
25
22
  ),
26
23
  );
27
24
  }
@@ -1,9 +1,9 @@
1
- import { Effect, Option, Redacted, Schema } from "effect";
1
+ import { Effect, Option, Schema } from "effect";
2
2
  import type { PgBossClient } from "#client.ts";
3
3
  import type { JobPayloadSchema, QueueDefinition } from "#definition.ts";
4
- import { type PgBossError, PgBossPayloadError, toPgBossError } from "#error.ts";
4
+ import { type PgBossError, type PgBossPayloadError, toPgBossError } from "#error.ts";
5
5
  import { type DeadLetteredJob, deadLetterQueueName, type JobPage, type JobPageOptions } from "#health.ts";
6
- import { payloadOf } from "#internal/tracing.ts";
6
+ import { decodeStoredData, quotedSchema } from "#internal/storedRows.ts";
7
7
  import type { PgBossService } from "#service.ts";
8
8
 
9
9
  const Cursor = Schema.StringFromBase64Url.pipe(Schema.decodeTo(Schema.fromJsonString(Schema.Tuple([Schema.String, Schema.String]))));
@@ -56,7 +56,7 @@ function listJobs<const TName extends string, const TPayload extends JobPayloadS
56
56
  throw new RangeError("The page limit must be a positive integer");
57
57
  }
58
58
  const after = options.cursor === undefined ? undefined : await Schema.decodeUnknownPromise(Cursor)(options.cursor);
59
- const quotedSchema = `"${schema.replaceAll('"', '""')}"`;
59
+ const quoted = quotedSchema(schema);
60
60
  const { rows } = await client.getDb().executeSql(
61
61
  `SELECT
62
62
  id,
@@ -72,7 +72,7 @@ function listJobs<const TName extends string, const TPayload extends JobPayloadS
72
72
  source_id AS "sourceId",
73
73
  source_output AS "sourceOutput",
74
74
  to_json(created_on) #>> '{}' AS "cursorAt"
75
- FROM ${quotedSchema}.job
75
+ FROM ${quoted}.job
76
76
  WHERE name = $1
77
77
  ${listing === "failedJobs" ? "AND state = 'failed'" : ""}
78
78
  AND ($2::timestamptz IS NULL OR (created_on, id) < ($2::timestamptz, $3::uuid))
@@ -89,8 +89,7 @@ function listJobs<const TName extends string, const TPayload extends JobPayloadS
89
89
  const next =
90
90
  rows.length > options.limit && last !== undefined ? Option.some(Schema.encodeSync(Cursor)([last.cursorAt, last.id])) : Option.none();
91
91
  return Effect.forEach(page, ({ cursorAt: _, data, ...row }) =>
92
- Schema.decodeUnknownEffect(queue.schema)(payloadOf(data)).pipe(
93
- Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue: queue.name })),
92
+ decodeStoredData(queue, data).pipe(
94
93
  Effect.map((decoded) => ({ ...row, attempt: Option.isSome(row.startedOn) ? row.retryCount + 1 : 0, data: decoded })),
95
94
  ),
96
95
  ).pipe(Effect.map((jobs) => ({ jobs, next })));
@@ -0,0 +1,30 @@
1
+ import { Socket } from "node:net";
2
+ import { type ConstructorOptions, PgBoss } from "pg-boss";
3
+
4
+ export function nativeClient(options: ConstructorOptions) {
5
+ const disconnected = new Set<Promise<void>>();
6
+ const config = {
7
+ ...options,
8
+ stream: () => {
9
+ const socket = new Socket();
10
+ const closed = new Promise<void>((resolve) =>
11
+ socket.once("close", () => {
12
+ disconnected.delete(closed);
13
+ resolve();
14
+ }),
15
+ );
16
+ disconnected.add(closed);
17
+ return socket;
18
+ },
19
+ };
20
+ const client = new PgBoss(config);
21
+ const stop = client.stop.bind(client);
22
+ client.stop = async (stopOptions) => {
23
+ await stop(stopOptions);
24
+ // pg-boss's pool shutdown does not wait for its transports to disconnect.
25
+ if (stopOptions?.close !== false) {
26
+ await Promise.all([...disconnected]);
27
+ }
28
+ };
29
+ return client;
30
+ }
@@ -1,6 +1,6 @@
1
1
  import type { PgBoss } from "pg-boss";
2
2
 
3
- export function observeTestingSettlements(client: PgBoss, changed: () => void) {
3
+ export function observeTestingSettlements(client: PgBoss, settled: (name: string) => void) {
4
4
  const observers = new Map<string, () => void>();
5
5
  return {
6
6
  close() {
@@ -23,7 +23,7 @@ export function observeTestingSettlements(client: PgBoss, changed: () => void) {
23
23
  }
24
24
  // This controller owns the spy; clear history and the losing wait before rearming both outcomes.
25
25
  spy.clear();
26
- changed();
26
+ settled(name);
27
27
  }
28
28
  }
29
29
  observers.set(name, () => {
@@ -1,7 +1,8 @@
1
1
  import { Schema } from "effect";
2
2
  import type { Job } from "pg-boss";
3
3
  import type { PgBossClient } from "#client.ts";
4
- import { STATELY_DEFERRAL_POLICY } from "./deferral.ts";
4
+ import { STATELY_DEFERRAL_POLICY } from "#internal/deferral.ts";
5
+ import { quotedSchema } from "#internal/storedRows.ts";
5
6
 
6
7
  const Settlement = Schema.Struct({ claimed: Schema.Boolean, deferred: Schema.Boolean });
7
8
 
@@ -9,7 +10,7 @@ export async function settleDeferral(client: PgBossClient, schema: string, job:
9
10
  if (client.getDb === undefined) {
10
11
  throw new TypeError("This pg-boss client does not support getDb for RetryAt");
11
12
  }
12
- const quoted = `"${schema.replaceAll('"', '""')}"`;
13
+ const quoted = quotedSchema(schema);
13
14
  // Native failure settlement deletes and reinserts jobs, so a cascading job foreign key would erase the counter.
14
15
  const { rows } = await client.getDb().executeSql(
15
16
  `WITH claimed AS MATERIALIZED (
@@ -0,0 +1,17 @@
1
+ import { Effect, Redacted, Schema } from "effect";
2
+ import type { JobPayloadSchema, QueueDefinition } from "#definition.ts";
3
+ import { PgBossPayloadError } from "#error.ts";
4
+ import { payloadOf } from "#internal/tracing.ts";
5
+
6
+ export function quotedSchema(schema: string): string {
7
+ return `"${schema.replaceAll('"', '""')}"`;
8
+ }
9
+
10
+ export function decodeStoredData<const TName extends string, const TPayload extends JobPayloadSchema>(
11
+ queue: Pick<QueueDefinition<TName, TPayload>, "name" | "schema">,
12
+ data: unknown,
13
+ ): Effect.Effect<TPayload["Type"], PgBossPayloadError, TPayload["DecodingServices"]> {
14
+ return Schema.decodeUnknownEffect(queue.schema)(payloadOf(data)).pipe(
15
+ Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue: queue.name })),
16
+ );
17
+ }
@@ -4,16 +4,25 @@ import { deferralObservers } from "#internal/deferral.ts";
4
4
  import { expireAttempt } from "#internal/expireAttempt.ts";
5
5
  import { observeTestingSettlements } from "#internal/observeTestingSettlements.ts";
6
6
  import { testingExpirations } from "#internal/testingExpirations.ts";
7
+ import type { TestingBatch, TestingWork } from "#internal/testingIdle.ts";
7
8
 
8
9
  export interface TestingControls {
9
10
  readonly changed: () => void;
10
11
  readonly expirations: Map<string, number>;
11
12
  readonly failures: Set<string>;
12
13
  readonly retryPolicy: Pick<SendOptions, "retryBackoff" | "retryDelay">;
14
+ readonly work: TestingWork;
13
15
  }
14
16
 
15
17
  export function testingClient(client: PgBoss, schema: string, controls: TestingControls): PgBossClient {
16
- const settlements = observeTestingSettlements(client, controls.changed);
18
+ const settlements = observeTestingSettlements(client, (name) => {
19
+ for (const batch of controls.work.batches) {
20
+ if (batch.name === name) {
21
+ batch.settled = true;
22
+ }
23
+ }
24
+ controls.changed();
25
+ });
17
26
  const expirations = testingExpirations(client);
18
27
  function update(request: UpdateRequest): Promise<UpdateResponse>;
19
28
  function update(name: string, data: object | null | undefined, options?: UpdateOptions): Promise<UpdateResponse>;
@@ -82,7 +91,10 @@ export function testingClient(client: PgBoss, schema: string, controls: TestingC
82
91
  }),
83
92
  work: (name, options, handler) => {
84
93
  settlements.watch(name);
94
+ controls.work.queues.add(name);
85
95
  return client.work(name, options, async (jobs: Job<unknown>[]) => {
96
+ const batch: TestingBatch = { name, settled: false };
97
+ controls.work.batches.add(batch);
86
98
  controls.changed();
87
99
  try {
88
100
  const ready: Job<unknown>[] = [];
@@ -98,6 +110,7 @@ export function testingClient(client: PgBoss, schema: string, controls: TestingC
98
110
  await handler(ready);
99
111
  }
100
112
  } finally {
113
+ controls.work.batches.delete(batch);
101
114
  controls.changed();
102
115
  }
103
116
  });
@@ -2,6 +2,7 @@ import { DateTime } from "effect";
2
2
  import type { PgBoss } from "pg-boss";
3
3
  import type { QueueDefinition } from "#definition.ts";
4
4
  import { deferralOf } from "#internal/deferral.ts";
5
+ import { quotedSchema } from "#internal/storedRows.ts";
5
6
  import { testingOperation } from "#internal/testingReadout.ts";
6
7
 
7
8
  export function testingDeferrals(client: () => PgBoss, schema: () => string, changed: () => void) {
@@ -22,11 +23,11 @@ export function testingDeferrals(client: () => PgBoss, schema: () => string, cha
22
23
  testingOperation(
23
24
  "runDeferredNow",
24
25
  async () => {
25
- const quotedSchema = `"${schema().replaceAll('"', '""')}"`;
26
+ const quoted = quotedSchema(schema());
26
27
  await client()
27
28
  .getDb()
28
29
  .executeSql(
29
- `UPDATE ${quotedSchema}.job SET start_after = ${quotedSchema}.job_now()
30
+ `UPDATE ${quoted}.job SET start_after = ${quoted}.job_now()
30
31
  WHERE name = $1 AND state = 'retry' AND output ? 'jobDeferral' AND started_on IS NULL`,
31
32
  [queue.name],
32
33
  );