@shivaedev/jobs 0.35.1 → 0.37.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 (109) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +5 -85
  3. package/dist/server/adapters/inspectionChanges.d.ts.map +1 -1
  4. package/dist/server/adapters/inspectionChanges.js +17 -2
  5. package/dist/server/adapters/inspectionChanges.js.map +1 -1
  6. package/dist/server/adapters/listJobs.d.ts.map +1 -1
  7. package/dist/server/adapters/listJobs.js +17 -7
  8. package/dist/server/adapters/listJobs.js.map +1 -1
  9. package/dist/server/adapters/localInspectionChanges.d.ts +3 -0
  10. package/dist/server/adapters/localInspectionChanges.d.ts.map +1 -0
  11. package/dist/server/adapters/localInspectionChanges.js +2 -0
  12. package/dist/server/adapters/localInspectionChanges.js.map +1 -0
  13. package/dist/server/adapters/settleDeferral.d.ts.map +1 -1
  14. package/dist/server/adapters/settleDeferral.js +4 -2
  15. package/dist/server/adapters/settleDeferral.js.map +1 -1
  16. package/dist/server/error.d.ts +1 -20
  17. package/dist/server/error.d.ts.map +1 -1
  18. package/dist/server/error.js +1 -8
  19. package/dist/server/error.js.map +1 -1
  20. package/dist/server/internal/engine.d.ts +3 -7
  21. package/dist/server/internal/engine.d.ts.map +1 -1
  22. package/dist/server/internal/engine.js +0 -2
  23. package/dist/server/internal/engine.js.map +1 -1
  24. package/dist/server/internal/jobListings.d.ts.map +1 -1
  25. package/dist/server/internal/jobListings.js +13 -7
  26. package/dist/server/internal/jobListings.js.map +1 -1
  27. package/package.json +13 -10
  28. package/src/server/adapters/inspectionChanges.ts +17 -2
  29. package/src/server/adapters/listJobs.ts +18 -10
  30. package/src/server/adapters/localInspectionChanges.ts +3 -0
  31. package/src/server/adapters/settleDeferral.ts +4 -2
  32. package/src/server/error.ts +1 -17
  33. package/src/server/internal/engine.ts +3 -14
  34. package/src/server/internal/jobListings.ts +20 -9
  35. package/dist/server/adapters/expireAttempt.d.ts +0 -4
  36. package/dist/server/adapters/expireAttempt.d.ts.map +0 -1
  37. package/dist/server/adapters/expireAttempt.js +0 -17
  38. package/dist/server/adapters/expireAttempt.js.map +0 -1
  39. package/dist/server/adapters/testingClient.d.ts +0 -13
  40. package/dist/server/adapters/testingClient.d.ts.map +0 -1
  41. package/dist/server/adapters/testingClient.js +0 -101
  42. package/dist/server/adapters/testingClient.js.map +0 -1
  43. package/dist/server/adapters/testingController.d.ts +0 -80
  44. package/dist/server/adapters/testingController.d.ts.map +0 -1
  45. package/dist/server/adapters/testingController.js +0 -120
  46. package/dist/server/adapters/testingController.js.map +0 -1
  47. package/dist/server/adapters/testingDueNow.d.ts +0 -7
  48. package/dist/server/adapters/testingDueNow.d.ts.map +0 -1
  49. package/dist/server/adapters/testingDueNow.js +0 -26
  50. package/dist/server/adapters/testingDueNow.js.map +0 -1
  51. package/dist/server/adapters/testingEngine.d.ts +0 -5
  52. package/dist/server/adapters/testingEngine.d.ts.map +0 -1
  53. package/dist/server/adapters/testingEngine.js +0 -12
  54. package/dist/server/adapters/testingEngine.js.map +0 -1
  55. package/dist/server/adapters/testingExpirations.d.ts +0 -8
  56. package/dist/server/adapters/testingExpirations.d.ts.map +0 -1
  57. package/dist/server/adapters/testingExpirations.js +0 -27
  58. package/dist/server/adapters/testingExpirations.js.map +0 -1
  59. package/dist/server/adapters/testingInspectionClient.d.ts +0 -5
  60. package/dist/server/adapters/testingInspectionClient.d.ts.map +0 -1
  61. package/dist/server/adapters/testingInspectionClient.js +0 -52
  62. package/dist/server/adapters/testingInspectionClient.js.map +0 -1
  63. package/dist/server/adapters/testingTime.d.ts +0 -10
  64. package/dist/server/adapters/testingTime.d.ts.map +0 -1
  65. package/dist/server/adapters/testingTime.js +0 -18
  66. package/dist/server/adapters/testingTime.js.map +0 -1
  67. package/dist/server/internal/adapters/deferralChanges.d.ts +0 -3
  68. package/dist/server/internal/adapters/deferralChanges.d.ts.map +0 -1
  69. package/dist/server/internal/adapters/deferralChanges.js +0 -2
  70. package/dist/server/internal/adapters/deferralChanges.js.map +0 -1
  71. package/dist/server/internal/adapters/testingFetches.d.ts +0 -7
  72. package/dist/server/internal/adapters/testingFetches.d.ts.map +0 -1
  73. package/dist/server/internal/adapters/testingFetches.js +0 -30
  74. package/dist/server/internal/adapters/testingFetches.js.map +0 -1
  75. package/dist/server/internal/testingIdle.d.ts +0 -17
  76. package/dist/server/internal/testingIdle.d.ts.map +0 -1
  77. package/dist/server/internal/testingIdle.js +0 -18
  78. package/dist/server/internal/testingIdle.js.map +0 -1
  79. package/dist/server/internal/testingOperation.d.ts +0 -5
  80. package/dist/server/internal/testingOperation.d.ts.map +0 -1
  81. package/dist/server/internal/testingOperation.js +0 -12
  82. package/dist/server/internal/testingOperation.js.map +0 -1
  83. package/dist/server/internal/testingSchedules.d.ts +0 -14
  84. package/dist/server/internal/testingSchedules.d.ts.map +0 -1
  85. package/dist/server/internal/testingSchedules.js +0 -20
  86. package/dist/server/internal/testingSchedules.js.map +0 -1
  87. package/dist/server/internal/testingWaits.d.ts +0 -20
  88. package/dist/server/internal/testingWaits.d.ts.map +0 -1
  89. package/dist/server/internal/testingWaits.js +0 -53
  90. package/dist/server/internal/testingWaits.js.map +0 -1
  91. package/dist/server/testing.d.ts +0 -89
  92. package/dist/server/testing.d.ts.map +0 -1
  93. package/dist/server/testing.js +0 -12
  94. package/dist/server/testing.js.map +0 -1
  95. package/src/server/adapters/expireAttempt.ts +0 -22
  96. package/src/server/adapters/testingClient.ts +0 -123
  97. package/src/server/adapters/testingController.ts +0 -137
  98. package/src/server/adapters/testingDueNow.ts +0 -32
  99. package/src/server/adapters/testingEngine.ts +0 -15
  100. package/src/server/adapters/testingExpirations.ts +0 -33
  101. package/src/server/adapters/testingInspectionClient.ts +0 -70
  102. package/src/server/adapters/testingTime.ts +0 -25
  103. package/src/server/internal/adapters/deferralChanges.ts +0 -3
  104. package/src/server/internal/adapters/testingFetches.ts +0 -36
  105. package/src/server/internal/testingIdle.ts +0 -36
  106. package/src/server/internal/testingOperation.ts +0 -18
  107. package/src/server/internal/testingSchedules.ts +0 -35
  108. package/src/server/internal/testingWaits.ts +0 -94
  109. package/src/server/testing.ts +0 -31
@@ -2,6 +2,7 @@ import { Effect } from "effect";
2
2
  import { inspectionChannel } from "#server/adapters/inspectionPlan.ts";
3
3
  import type { PgBossClient } from "#server/client.ts";
4
4
  import { toPgBossError } from "#server/error.ts";
5
+ import { localInspectionChanges } from "./localInspectionChanges.ts";
5
6
  import { queueSignal } from "./queueSignal.ts";
6
7
 
7
8
  export const inspectionChanges = Effect.fnUntraced(function* (client: PgBossClient, schema: string, queue?: string) {
@@ -9,12 +10,12 @@ export const inspectionChanges = Effect.fnUntraced(function* (client: PgBossClie
9
10
  yield* Effect.acquireRelease(
10
11
  Effect.tryPromise({
11
12
  catch: (error) => toPgBossError("inspect", error, queue),
12
- try: () => {
13
+ try: async () => {
13
14
  const db = client.getDb?.();
14
15
  if (db?.listen === undefined) {
15
16
  throw new TypeError("This pg-boss client does not support listen");
16
17
  }
17
- return db.listen(
18
+ const listener = await db.listen(
18
19
  inspectionChannel(schema),
19
20
  (name) => {
20
21
  if (queue === undefined || name === queue) {
@@ -23,6 +24,20 @@ export const inspectionChanges = Effect.fnUntraced(function* (client: PgBossClie
23
24
  },
24
25
  signal.changed,
25
26
  );
27
+ const local = localInspectionChanges.get(db) ?? new Set<(schema: string, queue: string) => void>();
28
+ localInspectionChanges.set(db, local);
29
+ function changed(changedSchema: string, name: string) {
30
+ if (changedSchema === schema && (queue === undefined || name === queue)) {
31
+ signal.changed();
32
+ }
33
+ }
34
+ local.add(changed);
35
+ return {
36
+ close: async () => {
37
+ local.delete(changed);
38
+ await listener.close();
39
+ },
40
+ };
26
41
  },
27
42
  }),
28
43
  (listener) => Effect.promise(() => listener.close()),
@@ -1,12 +1,16 @@
1
+ import { makeCompiler } from "@effect/sql-pg/PgClient";
1
2
  import { type Context, Effect } from "effect";
3
+ import * as Statement from "effect/sql/Statement";
2
4
  import type { PgBossClient } from "#server/client.ts";
3
5
  import { toPgBossError } from "#server/error.ts";
4
6
  import { deadLetterQueueName } from "#server/health.ts";
5
7
  import type { JobEngine } from "#server/internal/engine.ts";
6
8
  import { quotedSchema } from "#server/internal/storedRows.ts";
7
9
 
10
+ const compiler = makeCompiler();
11
+
8
12
  export function listJobs(client: PgBossClient, schema: string): Context.Service.Shape<typeof JobEngine>["listJobs"] {
9
- return (listing, queue, after, limit) =>
13
+ return (listing, queue, { limit, orderBy, seek }) =>
10
14
  Effect.tryPromise({
11
15
  catch: (error) => toPgBossError(listing, error, queue),
12
16
  try: async () => {
@@ -14,8 +18,8 @@ export function listJobs(client: PgBossClient, schema: string): Context.Service.
14
18
  throw new TypeError("This pg-boss client does not support getDb");
15
19
  }
16
20
  const quoted = quotedSchema(schema);
17
- const { rows: storedRows } = await client.getDb().executeSql(
18
- `SELECT
21
+ const query = Statement.fragment([
22
+ Statement.literal(`SELECT
19
23
  id,
20
24
  name AS queue,
21
25
  state,
@@ -30,13 +34,17 @@ export function listJobs(client: PgBossClient, schema: string): Context.Service.
30
34
  source_output AS "sourceOutput",
31
35
  to_json(created_on) #>> '{}' AS "cursorAt"
32
36
  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
- );
37
+ WHERE name = `),
38
+ Statement.parameter(listing === "failedJobs" ? queue : deadLetterQueueName(queue)),
39
+ Statement.literal(listing === "failedJobs" ? " AND state = 'failed' AND " : " AND "),
40
+ ...seek.segments,
41
+ Statement.literal(" ORDER BY "),
42
+ ...orderBy.segments,
43
+ Statement.literal(" LIMIT "),
44
+ Statement.parameter(limit),
45
+ ]);
46
+ const [text, parameters] = compiler.compile(query, false);
47
+ const { rows: storedRows } = await client.getDb().executeSql(text, [...parameters]);
40
48
  return storedRows;
41
49
  },
42
50
  });
@@ -0,0 +1,3 @@
1
+ import type { ClientDatabase } from "#server/ClientDatabase.ts";
2
+
3
+ export const localInspectionChanges = new WeakMap<ClientDatabase, Set<(schema: string, queue: string) => void>>();
@@ -1,9 +1,9 @@
1
1
  import { Schema } from "effect";
2
2
  import type { PgBossClient } from "#server/client.ts";
3
- import { deferralChanges } from "#server/internal/adapters/deferralChanges.ts";
4
3
  import { STATELY_DEFERRAL_POLICY } from "#server/internal/deferral.ts";
5
4
  import type { JobAttempt } from "#server/internal/engine.ts";
6
5
  import { quotedSchema } from "#server/internal/storedRows.ts";
6
+ import { localInspectionChanges } from "./localInspectionChanges.ts";
7
7
 
8
8
  const Settlement = Schema.Struct({ claimed: Schema.Boolean, deferred: Schema.Boolean });
9
9
 
@@ -54,7 +54,9 @@ export async function settleDeferral(client: PgBossClient, schema: string, job:
54
54
  );
55
55
  const settled = Schema.decodeUnknownSync(Settlement)(rows[0]);
56
56
  if (settled.deferred) {
57
- deferralChanges.get(db)?.();
57
+ for (const changed of localInspectionChanges.get(db) ?? []) {
58
+ changed(schema, job.name);
59
+ }
58
60
  }
59
61
  return settled;
60
62
  }
@@ -1,4 +1,4 @@
1
- import { Cause, Data, Duration, Redacted } from "effect";
1
+ import { Cause, Data, Redacted } from "effect";
2
2
  import { failureOutput } from "#server/internal/failureOutput.ts";
3
3
 
4
4
  export type PgBossOperation =
@@ -86,22 +86,6 @@ export class PgBossPayloadError extends Data.TaggedError("PgBossPayloadError")<{
86
86
  readonly original: Redacted.Redacted<unknown>;
87
87
  }> {}
88
88
 
89
- export class PgBossTestingError extends Data.TaggedError("PgBossTestingError")<{
90
- readonly operation: string;
91
- readonly original: Redacted.Redacted<unknown>;
92
- readonly queue?: string | undefined;
93
- }> {}
94
-
95
- export class PgBossWaitError extends Data.TaggedError("PgBossWaitError")<{
96
- readonly lastSeen: string;
97
- readonly waitingFor: string;
98
- readonly within: Duration.Duration;
99
- }> {
100
- override get message(): string {
101
- return `Gave up after ${Duration.format(this.within)} waiting until ${this.waitingFor}; last seen: ${this.lastSeen}`;
102
- }
103
- }
104
-
105
89
  export function toPgBossError(operation: PgBossOperation, error: unknown, queue?: string): PgBossError {
106
90
  return new PgBossError({
107
91
  operation,
@@ -1,6 +1,7 @@
1
1
  import { Context, type Effect } from "effect";
2
+ import type { KeysetPageQuery } from "@shivaedev/sql/keysetPage.ts";
2
3
  import type { PgBossClient } from "#server/client.ts";
3
- import type { PgBossError, PgBossTestingError } from "#server/error.ts";
4
+ import type { PgBossError } from "#server/error.ts";
4
5
  import type { PgBossService } from "#server/service.ts";
5
6
 
6
7
  export type StoredJob = Awaited<ReturnType<NonNullable<PgBossClient["findJobs"]>>>[number];
@@ -12,12 +13,7 @@ export class JobEngine extends Context.Service<
12
13
  Pick<PgBossService, "deleteQueue" | "refreshQueueStats" | "unschedule"> & {
13
14
  readonly getJob: (queue: string, id: string) => Effect.Effect<StoredJob | undefined, PgBossError>;
14
15
  readonly retry: (queue: string, id: string) => Effect.Effect<void, PgBossError>;
15
- readonly listJobs: (
16
- listing: Listing,
17
- queue: string,
18
- after: readonly [string, string] | undefined,
19
- limit: number,
20
- ) => Effect.Effect<readonly unknown[], PgBossError>;
16
+ readonly listJobs: (listing: Listing, queue: string, query: KeysetPageQuery) => Effect.Effect<readonly unknown[], PgBossError>;
21
17
  readonly settleDeferral: (
22
18
  job: JobAttempt,
23
19
  at: string,
@@ -26,10 +22,3 @@ export class JobEngine extends Context.Service<
26
22
  ) => Effect.Effect<{ readonly claimed: boolean; readonly deferred: boolean }, PgBossError>;
27
23
  }
28
24
  >()("@shivaedev/jobs/JobEngine") {}
29
-
30
- export class TestingEngine extends Context.Service<
31
- TestingEngine,
32
- {
33
- readonly expireAttempt: (job: JobAttempt, cause?: "expiry" | "heartbeat") => Effect.Effect<void, PgBossTestingError>;
34
- }
35
- >()("@shivaedev/jobs/TestingEngine") {}
@@ -1,5 +1,6 @@
1
1
  import { type Context, Effect, Option, Redacted, Schema } from "effect";
2
2
  import { redact } from "@shivaedev/errors/redact.ts";
3
+ import { keysetPage } from "@shivaedev/sql/keysetPage.ts";
3
4
  import type { JobPayloadSchema } from "#server/definition.ts";
4
5
  import { type PgBossError, PgBossPayloadError } from "#server/error.ts";
5
6
  import type { DeadLetteredJob, JobPage, JobPageOptions } from "#server/health.ts";
@@ -65,15 +66,25 @@ const listJobs = Effect.fnUntraced(function* <const TName extends string, const
65
66
  TPayload["DecodingServices"]
66
67
  > {
67
68
  const { cursor: after, limit } = yield* Schema.decodeUnknownEffect(PageOptions)(options);
68
- const rows = yield* engine.listJobs(listing, queue.name, after, limit);
69
- const decodedRows = yield* Schema.decodeUnknownEffect(Rows)(rows).pipe(
70
- Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue: queue.name })),
71
- );
72
- const page = decodedRows.slice(0, limit);
73
- const last = page.at(-1);
74
- const next = decodedRows.length > limit && last !== undefined ? Option.some(Schema.encodeSync(Cursor)([last.cursorAt, last.id])) : Option.none();
69
+ const page = yield* keysetPage({
70
+ after,
71
+ cursorFor: (row: typeof Row.Type) => [row.cursorAt, row.id] as const,
72
+ limit,
73
+ orderBy: [{ column: "created_on", direction: "desc", value: (cursor) => cursor[0] }],
74
+ read: (query) =>
75
+ engine
76
+ .listJobs(listing, queue.name, query)
77
+ .pipe(
78
+ Effect.flatMap((rows) =>
79
+ Schema.decodeUnknownEffect(Rows)(rows).pipe(
80
+ Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue: queue.name })),
81
+ ),
82
+ ),
83
+ ),
84
+ tieBreaker: { column: "id", direction: "desc", value: (cursor) => cursor[1] },
85
+ });
75
86
  const jobs = yield* Effect.forEach(
76
- page,
87
+ page.rows,
77
88
  Effect.fnUntraced(function* ({ cursorAt: _, data, ...row }) {
78
89
  const decoded = yield* decodeStoredData(queue, data);
79
90
  const output = yield* readJobFailure(queue.name, row.output);
@@ -81,5 +92,5 @@ const listJobs = Effect.fnUntraced(function* <const TName extends string, const
81
92
  return { ...row, attempt: Option.isSome(row.startedOn) ? row.retryCount + 1 : 0, data: redact(decoded), output, sourceOutput };
82
93
  }),
83
94
  );
84
- return { jobs, next };
95
+ return { jobs, next: Option.map(page.next, Schema.encodeSync(Cursor)) };
85
96
  });
@@ -1,4 +0,0 @@
1
- import type { EngineClient } from "#server/engineClient.ts";
2
- import type { JobAttempt } from "#server/internal/engine.ts";
3
- export declare function expireAttempt(client: EngineClient, schema: string, job: JobAttempt, cause?: "expiry" | "heartbeat"): Promise<void>;
4
- //# sourceMappingURL=expireAttempt.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"expireAttempt.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/expireAttempt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAG7D,wBAAsB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,GAAE,QAAQ,GAAG,WAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBlJ"}
@@ -1,17 +0,0 @@
1
- import { quotedSchema } from "#server/internal/storedRows.ts";
2
- export async function expireAttempt(client, schema, job, cause = "expiry") {
3
- if ((await client.schemaVersion()) !== 46) {
4
- throw new Error("Testing expiry requires pg-boss schema version 46");
5
- }
6
- const quoted = quotedSchema(schema);
7
- const timestamp = cause === "expiry" ? "started_on" : "heartbeat_on";
8
- const seconds = cause === "expiry" ? "expire_seconds" : "heartbeat_seconds";
9
- await client.getDb().executeSql(`UPDATE ${quoted}.job SET ${timestamp} = ${quoted}.job_now() - (${seconds} + 1) * interval '1 second'
10
- WHERE name = $1 AND id = $2 AND retry_count = $3 AND state = 'active'`, [job.name, job.id, job.retryCount]);
11
- // Supervision owns expiry and dead lettering; make its claim due with the job's deadline.
12
- await client
13
- .getDb()
14
- .executeSql(`UPDATE ${quoted}.queue SET monitor_claim_on = ${quoted}.job_now() - interval '1 week' WHERE name = $1`, [job.name]);
15
- await client.supervise(job.name);
16
- }
17
- //# sourceMappingURL=expireAttempt.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"expireAttempt.js","sourceRoot":"","sources":["../../../src/server/adapters/expireAttempt.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAE9D,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAAoB,EAAE,MAAc,EAAE,GAAe,EAAE,KAAK,GAA2B,QAAQ;IAClI,IAAI,CAAC,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC;QAC3C,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACtE,CAAC;IACD,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC;IACrE,MAAM,OAAO,GAAG,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,mBAAmB,CAAC;IAC5E,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,UAAU,CAC9B,UAAU,MAAM,YAAY,SAAS,MAAM,MAAM,iBAAiB,OAAO;wEACH,EACtE,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,UAAU,CAAC,CAClC,CAAC;IACF,0FAA0F;IAC1F,MAAM,MAAM;SACV,KAAK,EAAE;SACP,UAAU,CAAC,UAAU,MAAM,iCAAiC,MAAM,gDAAgD,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAClI,MAAM,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC"}
@@ -1,13 +0,0 @@
1
- import type { EngineClient } from "#server/engineClient.ts";
2
- import type { EnqueueOptions } from "#server/enqueueOptions.ts";
3
- import type { TestingWork } from "#server/internal/testingIdle.ts";
4
- export interface TestingControls {
5
- readonly changed: () => void;
6
- readonly expirations: Map<string, number>;
7
- readonly expirySeconds: Map<string, number>;
8
- readonly failures: Set<string>;
9
- readonly retryPolicy: Pick<EnqueueOptions, "retryBackoff" | "retryDelay">;
10
- readonly work: TestingWork;
11
- }
12
- export declare function testingClient(client: EngineClient, schema: string, controls: TestingControls): EngineClient;
13
- //# sourceMappingURL=testingClient.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"testingClient.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/testingClient.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAGjF,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC,cAAc,EAAE,cAAc,GAAG,YAAY,CAAC,CAAC;IAC1E,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;CAC3B;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,YAAY,CAuG3G"}
@@ -1,101 +0,0 @@
1
- import { Effect } from "effect";
2
- import { testingEngine } from "#server/adapters/testingEngine.ts";
3
- import { testingExpirations } from "#server/adapters/testingExpirations.ts";
4
- import { deferralChanges } from "#server/internal/adapters/deferralChanges.ts";
5
- export function testingClient(client, schema, controls) {
6
- const engine = testingEngine(client, schema);
7
- deferralChanges.set(client.getDb(), controls.changed);
8
- const expirations = testingExpirations(client);
9
- async function update(request, data, options) {
10
- const result = typeof request === "string" ? await client.update(request, data, options) : await client.update(request);
11
- controls.changed();
12
- return result;
13
- }
14
- const overrides = {
15
- complete: async (...args) => {
16
- const result = await client.complete(...args);
17
- controls.changed();
18
- return result;
19
- },
20
- createQueue: (name, options) => {
21
- if (options?.deadLetter !== undefined) {
22
- controls.work.queues.add(name);
23
- }
24
- const { retryDelayMax, ...rest } = options ?? {};
25
- return client.createQueue(name, {
26
- ...rest,
27
- ...(controls.retryPolicy.retryBackoff === false || retryDelayMax === undefined ? {} : { retryDelayMax }),
28
- ...controls.retryPolicy,
29
- });
30
- },
31
- fail: async (...args) => {
32
- const result = await client.fail(...args);
33
- controls.changed();
34
- return result;
35
- },
36
- retry: async (...args) => {
37
- const result = await client.retry(...args);
38
- controls.changed();
39
- return result;
40
- },
41
- send: async (name, data, options) => {
42
- if (controls.failures.delete(name)) {
43
- throw new Error("Injected pg-boss send failure");
44
- }
45
- const attempts = controls.expirations.get(name);
46
- const expireInSeconds = controls.expirySeconds.get(name);
47
- const { retryDelayMax, ...rest } = options ?? {};
48
- const id = await expirations.send(name, data, {
49
- ...rest,
50
- ...(controls.retryPolicy.retryBackoff === false || retryDelayMax === undefined ? {} : { retryDelayMax }),
51
- ...controls.retryPolicy,
52
- ...(attempts === undefined ? {} : { retryLimit: attempts - 1 }),
53
- ...(expireInSeconds === undefined ? {} : { expireInSeconds }),
54
- }, attempts);
55
- controls.changed();
56
- return id;
57
- },
58
- update,
59
- updateQueue: (name, options) => client.updateQueue(name, {
60
- ...options,
61
- ...controls.retryPolicy,
62
- ...(controls.retryPolicy.retryBackoff === false ? { retryDelayMax: null } : {}),
63
- }),
64
- work: async (name, options, handler) => client.work(name, options, async (jobs) => {
65
- const batch = { jobs: new Map(jobs.map((job) => [job.id, job.retryCount])), name, settled: false };
66
- controls.work.batches.add(batch);
67
- controls.changed();
68
- try {
69
- const ready = [];
70
- for (const job of jobs) {
71
- const attempts = await expirations.attemptsFor(job);
72
- if (attempts !== undefined && job.retryCount + 1 >= attempts) {
73
- await Effect.runPromise(engine.expireAttempt(job));
74
- }
75
- else {
76
- ready.push(job);
77
- }
78
- }
79
- if (ready.length > 0) {
80
- await handler(ready);
81
- }
82
- }
83
- finally {
84
- controls.work.batches.delete(batch);
85
- controls.changed();
86
- }
87
- }),
88
- };
89
- const wrapped = new Proxy(client, {
90
- get(target, property) {
91
- if (Object.hasOwn(overrides, property)) {
92
- const override = Reflect.get(overrides, property);
93
- return override;
94
- }
95
- const value = Reflect.get(target, property);
96
- return typeof value === "function" ? value.bind(target) : value;
97
- },
98
- });
99
- return wrapped;
100
- }
101
- //# sourceMappingURL=testingClient.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"testingClient.js","sourceRoot":"","sources":["../../../src/server/adapters/testingClient.ts"],"names":[],"mappings":"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"}
@@ -1,80 +0,0 @@
1
- import { Duration, Effect, type Schema } from "effect";
2
- import type { JobReadOptions, PgBossClientFactory } from "#server/client.ts";
3
- import type { JobPayloadSchema, QueueDefinition } from "#server/definition.ts";
4
- import { PgBossTestingError } from "#server/error.ts";
5
- import type { SnapshotQueue } from "#server/inspection.ts";
6
- import type { PgBossTestingOptions } from "#server/testing.ts";
7
- export declare function testingController(settings?: PgBossTestingOptions): {
8
- runDeferredNow: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<void, PgBossTestingError, never>;
9
- runDueNow: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<void, PgBossTestingError, never>;
10
- timePasses: (duration: Duration.Input) => Effect.Effect<undefined, PgBossTestingError, never>;
11
- schedules: () => Effect.Effect<{
12
- cron: string;
13
- name: string;
14
- timezone: string;
15
- }[], PgBossTestingError, never>;
16
- trigger: (schedule: Pick<import("#server/definition.ts").ScheduleDefinition, "name" | "scheduleOptions">) => Effect.Effect<string | null, PgBossTestingError, never>;
17
- fetchesPass: (queue: Pick<QueueDefinition, "name">, count: number, options?: import("#server/testing.ts").PgBossTestingWaitOptions) => Effect.Effect<unknown, PgBossTestingError | import("#server/error.ts").PgBossWaitError, never>;
18
- untilJob: <TName extends string, TPayload extends JobPayloadSchema | typeof Schema.Null>(queue: {
19
- readonly name: TName;
20
- readonly schema: TPayload;
21
- }, id: string, state: import("../job.ts").JobState, options?: import("#server/testing.ts").PgBossTestingWaitOptions) => Effect.Effect<import("../job.ts").Job<TPayload["Type"]>, import("#server/error.ts").PgBossPayloadError | PgBossTestingError | import("#server/error.ts").PgBossWaitError, TPayload["DecodingServices"]>;
22
- deferred: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<{
23
- at: import("effect/DateTime").Utc;
24
- reason: string;
25
- }[], PgBossTestingError, never>;
26
- checkBatchWindow: (queue: Pick<QueueDefinition, "name" | "workerOptions">, millisecondsPerJob: number) => Effect.Effect<void, PgBossTestingError, never>;
27
- checkSchemaVersion: (expected: number) => Effect.Effect<void, PgBossTestingError, never>;
28
- clientFactory: PgBossClientFactory;
29
- expireAfter: (queue: Pick<QueueDefinition, "name">, attempts: number) => Effect.Effect<void, PgBossTestingError, never>;
30
- expireIn: (queue: Pick<QueueDefinition, "name">, duration: Duration.Input) => Effect.Effect<void, PgBossTestingError, never>;
31
- failNextSend: (queue: Pick<QueueDefinition, "name">) => Effect.Effect<void, never, never>;
32
- jobs: <TName extends string, TPayload extends JobPayloadSchema | typeof Schema.Null>(queue: {
33
- readonly name: TName;
34
- readonly schema: TPayload;
35
- }, readOptions?: JobReadOptions) => Effect.Effect<{
36
- expireInSeconds: number;
37
- groupId?: string | null;
38
- groupTier?: string | null;
39
- heartbeatSeconds: number | null;
40
- id: string;
41
- name: string;
42
- retryCount: number;
43
- signal: AbortSignal;
44
- blocked: boolean;
45
- blocking: boolean;
46
- completedOn: Date | null;
47
- createdOn: Date;
48
- deadLetter: string;
49
- deleteAfterSeconds: number;
50
- heartbeatOn: Date | null;
51
- keepUntil: Date;
52
- output: object | null;
53
- pendingDependencies: number;
54
- policy: string;
55
- priority: number;
56
- retryBackoff: boolean;
57
- retryDelay: number;
58
- retryDelayMax?: number;
59
- retryLimit: number;
60
- singletonKey: string | null;
61
- singletonOn: Date | null;
62
- sourceCreatedOn: Date | null;
63
- sourceId: string | null;
64
- sourceName: string | null;
65
- sourceOutput: object | null;
66
- sourceRetryCount: number | null;
67
- sourceRootId: string | null;
68
- startAfter: Date;
69
- startedOn: Date | null;
70
- state: import("../job.ts").JobState;
71
- data: TPayload["Type"];
72
- }[], import("#server/error.ts").PgBossPayloadError | PgBossTestingError, TPayload["DecodingServices"]>;
73
- refreshQueueStats: (queue?: Pick<QueueDefinition, "name">) => Effect.Effect<void, PgBossTestingError, never>;
74
- revision: Effect.Effect<number, never, never>;
75
- schemaVersion: Effect.Effect<number | null, PgBossTestingError, never>;
76
- snapshot: <const TQueues extends readonly SnapshotQueue[]>(queues: TQueues) => Effect.Effect<readonly import("#server/inspection.ts").UnfinishedJob<TQueues[number]>[], import("#server/error.ts").PgBossPayloadError | PgBossTestingError, TQueues[number]["schema"]["DecodingServices"]>;
77
- waitForChange: (after: number) => Effect.Effect<number>;
78
- waitForIdle: Effect.Effect<void, PgBossTestingError, never>;
79
- };
80
- //# sourceMappingURL=testingController.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"testingController.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/testingController.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAY,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAMjE,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,KAAK,EAA2B,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAMpF,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAG/D,wBAAgB,iBAAiB,CAAC,QAAQ,GAAE,oBAAyB;;;;;;;;;;;;;;;sBAiDjD,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;;;;8BAIrB,IAAI,CAAC,eAAe,EAAE,MAAM,GAAG,eAAe,CAAC,sBAAsB,MAAM;mCAqBtE,MAAM;;yBAOhB,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,YAAY,MAAM;sBAUlD,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC,YAAY,QAAQ,CAAC,KAAK;0BAWnD,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;WAC5C,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,gBAAgB,GAAG,OAAO,MAAM,CAAC,IAAI,SAC3E;QAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAA;KAAE,gBAC5C,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAED,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;;;eAI9C,KAAK,CAAC,OAAO,SAAS,SAAS,aAAa,EAAE,UAAU,OAAO;;;EAM3E"}
@@ -1,120 +0,0 @@
1
- import { Duration, Effect, Redacted } from "effect";
2
- import { TestClock as PgBossTestClock } from "pg-boss";
3
- import { defaultClientFactory } from "#server/adapters/defaultClientFactory.ts";
4
- import { testingClient } from "#server/adapters/testingClient.ts";
5
- import { testingDueNow } from "#server/adapters/testingDueNow.ts";
6
- import { testingTime } from "#server/adapters/testingTime.ts";
7
- import { PgBossTestingError } from "#server/error.ts";
8
- import { testingFetches } from "#server/internal/adapters/testingFetches.ts";
9
- import { testingIdle } from "#server/internal/testingIdle.ts";
10
- import { testingInspection, testingOperation } from "#server/internal/testingOperation.ts";
11
- import { testingSchedules } from "#server/internal/testingSchedules.ts";
12
- import { testingWaits } from "#server/internal/testingWaits.ts";
13
- import { queueSignal } from "./queueSignal.js";
14
- import { testingInspectionClient } from "./testingInspectionClient.js";
15
- export function testingController(settings = {}) {
16
- const clock = settings.clock === undefined ? undefined : new PgBossTestClock(settings.clock.currentTimeMillisUnsafe());
17
- let current;
18
- let fetches;
19
- let schema = "pgboss";
20
- const signal = queueSignal();
21
- let observed;
22
- const work = { batches: new Set(), queues: new Set() };
23
- const controls = {
24
- changed: signal.changed,
25
- expirations: new Map(),
26
- expirySeconds: new Map(),
27
- failures: new Set(),
28
- retryPolicy: settings.retryPolicy ?? {},
29
- work,
30
- };
31
- function client() {
32
- if (current === undefined) {
33
- throw new Error("Provide the testing clientFactory to a jobs Layer first");
34
- }
35
- return current;
36
- }
37
- function inspection() {
38
- if (observed === undefined) {
39
- throw new Error("Provide the testing clientFactory to a jobs Layer first");
40
- }
41
- return observed;
42
- }
43
- const clientFactory = (clientOptions) => {
44
- if (current !== undefined) {
45
- throw new Error("A testing controller owns one jobs client; create a controller per runtime");
46
- }
47
- schema = clientOptions.schema ?? "pgboss";
48
- current = defaultClientFactory({ ...clientOptions, ...(clock === undefined ? {} : { clock }) });
49
- fetches = testingFetches(current.getDb(), signal.changed);
50
- current = testingClient(current, schema, controls);
51
- return testingInspectionClient(current, schema, work, signal.changed, (reads) => {
52
- observed = reads;
53
- });
54
- };
55
- const wake = Effect.sync(() => {
56
- if (clock !== undefined) {
57
- for (const worker of client().getWipData()) {
58
- client().notifyWorker(worker.id);
59
- }
60
- }
61
- });
62
- const idle = testingIdle(inspection, work, signal, wake);
63
- return {
64
- deferred: (queue) => Effect.suspend(() => testingInspection("deferred", inspection().deferred(queue), queue.name)),
65
- ...testingDueNow(client, () => schema, signal.changed),
66
- ...testingSchedules(client, inspection),
67
- ...testingWaits(inspection, () => fetches, signal),
68
- checkBatchWindow: (queue, millisecondsPerJob) => testingOperation("checkBatchWindow", async () => {
69
- const stored = await Effect.runPromise(inspection().queue(queue));
70
- if (stored === null) {
71
- throw new Error("Queue is not registered");
72
- }
73
- if (stored.expireInSeconds === undefined) {
74
- throw new Error("Queue has no expiry window");
75
- }
76
- if (!Number.isFinite(millisecondsPerJob) || millisecondsPerJob < 0) {
77
- throw new RangeError("Job duration must be nonnegative and finite");
78
- }
79
- const required = (queue.workerOptions.batchSize ?? 10) * millisecondsPerJob;
80
- if (required >= stored.expireInSeconds * 1000) {
81
- throw new Error("Sequential batch work must fit within the queue expiry window");
82
- }
83
- }, queue.name),
84
- checkSchemaVersion: (expected) => testingOperation("checkSchemaVersion", async () => {
85
- if ((await Effect.runPromise(inspection().schemaVersion())) !== expected) {
86
- throw new Error(`Expected pg-boss schema version ${expected}`);
87
- }
88
- }),
89
- clientFactory,
90
- expireAfter: (queue, attempts) => Effect.try({
91
- catch: (original) => new PgBossTestingError({ operation: "expireAfter", original: Redacted.make(original), queue: queue.name }),
92
- try: () => {
93
- if (!Number.isSafeInteger(attempts) || attempts < 1) {
94
- throw new RangeError("Attempts must be a positive integer");
95
- }
96
- controls.expirations.set(queue.name, attempts);
97
- },
98
- }),
99
- expireIn: (queue, duration) => Effect.try({
100
- catch: (original) => new PgBossTestingError({ operation: "expireIn", original: Redacted.make(original), queue: queue.name }),
101
- try: () => {
102
- const milliseconds = Duration.toMillis(Duration.fromInputUnsafe(duration));
103
- if (!Number.isFinite(milliseconds) || milliseconds < 1000) {
104
- throw new RangeError("Expiry must be finite and at least one second");
105
- }
106
- controls.expirySeconds.set(queue.name, Math.ceil(milliseconds / 1000));
107
- },
108
- }),
109
- failNextSend: (queue) => Effect.sync(() => controls.failures.add(queue.name)).pipe(Effect.asVoid),
110
- jobs: (queue, readOptions) => Effect.suspend(() => testingInspection("jobs", inspection().jobs(queue, readOptions), queue.name)),
111
- refreshQueueStats: (queue) => testingOperation("refreshQueueStats", () => client().supervise(queue?.name), queue?.name),
112
- revision: signal.revision,
113
- schemaVersion: Effect.suspend(() => testingInspection("schemaVersion", inspection().schemaVersion())),
114
- snapshot: (queues) => Effect.suspend(() => testingInspection("snapshot", inspection().snapshot(queues))),
115
- waitForChange: signal.waitForChange,
116
- waitForIdle: idle,
117
- ...testingTime(settings.clock, clock, idle),
118
- };
119
- }
120
- //# sourceMappingURL=testingController.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"testingController.js","sourceRoot":"","sources":["../../../src/server/adapters/testingController.ts"],"names":[],"mappings":"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"}
@@ -1,7 +0,0 @@
1
- import type { QueueDefinition } from "#server/definition.ts";
2
- import type { EngineClient } from "#server/engineClient.ts";
3
- export declare function testingDueNow(client: () => EngineClient, schema: () => string, changed: () => void): {
4
- runDeferredNow: (queue: Pick<QueueDefinition, "name">) => import("effect/Effect").Effect<void, import("../error.ts").PgBossTestingError, never>;
5
- runDueNow: (queue: Pick<QueueDefinition, "name">) => import("effect/Effect").Effect<void, import("../error.ts").PgBossTestingError, never>;
6
- };
7
- //# sourceMappingURL=testingDueNow.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"testingDueNow.d.ts","sourceRoot":"","sources":["../../../src/server/adapters/testingDueNow.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAI5D,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,YAAY,EAAE,MAAM,EAAE,MAAM,MAAM,EAAE,OAAO,EAAE,MAAM,IAAI;IAuBjG,cAAc,UAAU,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;IACrD,SAAS,UAAU,IAAI,CAAC,eAAe,EAAE,MAAM,CAAC;EAEjD"}