@shivaedev/effect-pg-boss 0.5.0 → 0.6.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 (51) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +53 -12
  3. package/dist/server/client.d.ts +7 -1
  4. package/dist/server/client.d.ts.map +1 -1
  5. package/dist/server/client.js.map +1 -1
  6. package/dist/server/definition.d.ts +5 -5
  7. package/dist/server/definition.d.ts.map +1 -1
  8. package/dist/server/error.d.ts +10 -1
  9. package/dist/server/error.d.ts.map +1 -1
  10. package/dist/server/error.js +5 -0
  11. package/dist/server/error.js.map +1 -1
  12. package/dist/server/health.d.ts +6 -0
  13. package/dist/server/health.d.ts.map +1 -1
  14. package/dist/server/health.js.map +1 -1
  15. package/dist/server/internal/countsFor.d.ts +5 -0
  16. package/dist/server/internal/countsFor.d.ts.map +1 -0
  17. package/dist/server/internal/countsFor.js +27 -0
  18. package/dist/server/internal/countsFor.js.map +1 -0
  19. package/dist/server/internal/ensureQueue.d.ts +4 -0
  20. package/dist/server/internal/ensureQueue.d.ts.map +1 -0
  21. package/dist/server/internal/ensureQueue.js +27 -0
  22. package/dist/server/internal/ensureQueue.js.map +1 -0
  23. package/dist/server/internal/jobControl.d.ts +5 -0
  24. package/dist/server/internal/jobControl.d.ts.map +1 -0
  25. package/dist/server/internal/jobControl.js +34 -0
  26. package/dist/server/internal/jobControl.js.map +1 -0
  27. package/dist/server/internal/register.d.ts +2 -1
  28. package/dist/server/internal/register.d.ts.map +1 -1
  29. package/dist/server/internal/register.js +5 -22
  30. package/dist/server/internal/register.js.map +1 -1
  31. package/dist/server/internal/service.d.ts +1 -1
  32. package/dist/server/internal/service.d.ts.map +1 -1
  33. package/dist/server/internal/service.js +7 -2
  34. package/dist/server/internal/service.js.map +1 -1
  35. package/dist/server/service.d.ts +8 -5
  36. package/dist/server/service.d.ts.map +1 -1
  37. package/dist/server/service.js +1 -1
  38. package/dist/server/service.js.map +1 -1
  39. package/docs/north-star.md +1 -1
  40. package/docs/roadmap.md +9 -3
  41. package/package.json +2 -2
  42. package/src/server/client.ts +17 -1
  43. package/src/server/definition.ts +5 -5
  44. package/src/server/error.ts +10 -1
  45. package/src/server/health.ts +7 -0
  46. package/src/server/internal/countsFor.ts +33 -0
  47. package/src/server/internal/ensureQueue.ts +29 -0
  48. package/src/server/internal/jobControl.ts +46 -0
  49. package/src/server/internal/register.ts +6 -24
  50. package/src/server/internal/service.ts +7 -2
  51. package/src/server/service.ts +13 -7
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.6.0 - 2026-10-17
4
+
5
+ ### Added
6
+
7
+ - `PgBossService.counts(queue)` returns live `QueueCounts` without waiting for the pg-boss monitor; `health` keeps using cached counts.
8
+ - `PgBossService.getJob(queue, id)` returns optional job metadata with Schema-decoded payloads and decoding service requirements. `PgBossService.retry(queue, id)` reprocesses failed or retry-waiting jobs under their original ID.
9
+ - `PgBossQueueOptionsError` identifies immutable queue option conflicts during Layer acquisition. Custom `PgBossClient` factories can provide optional native `findJobs`, `retry`, `update`, `getDb` and `updateQueue` capabilities for the new operations.
10
+
11
+ ### Fixed
12
+
13
+ - Queue and schedule definitions accept pg-boss's full `Queue` options except the owned name and dead-letter setup, including notification delivery, policy, partitioning, heartbeat and backlog warnings.
14
+ - Startup reconciles declared mutable queue settings through `updateQueue`, including expiry and retry limits, so they reach existing queues after restart.
15
+
3
16
  ## 0.5.0 - 2026-10-13
4
17
 
5
18
  ### Added
package/README.md CHANGED
@@ -31,7 +31,7 @@ A **queue definition** names a pg-boss queue and the Schema of its payload. Appl
31
31
 
32
32
  A **schedule definition** describes a queue with a cron trigger. `schedule.run(effect)` pairs it with an Effect that needs no payload. Queue workers and scheduled workers are **registrations**: the values you put in the jobs Layer's `jobs` list.
33
33
 
34
- The application creates one jobs service with `makePgBoss(identifier)`. Its Layer starts a client, registers the job list and captures the services those workers need. The Layer's scope owns its client reference and releases it when the scope ends; the final reference closes the client. Callers use the jobs service to enqueue a decoded payload or read queue health.
34
+ The application creates one jobs service with `makePgBoss(identifier)`. Its Layer starts a client, registers the job list and captures the services those workers need. The Layer's scope owns its client reference and releases it when the scope ends; the final reference closes the client. Callers use the jobs service to enqueue a decoded payload, look up or retry a job, or read queue health and live counts.
35
35
 
36
36
  Use a distinct literal identifier for each jobs service. The service and its Layer keep that identifier in their types, so providing a Layer for a different identifier leaves the required jobs service unprovided at compile time.
37
37
 
@@ -116,7 +116,7 @@ export const jobsLayer = (databaseUrl: string) =>
116
116
  }).pipe(Layer.provide(MailLive));
117
117
  ```
118
118
 
119
- The constructor options belong to pg-boss. `jobs` is the complete list of registrations for this Layer. The Layer captures `MailLive` for both the queue handler and the scheduled Effect. A startup or registration failure fails Layer acquisition with `PgBossError` and releases its acquired client reference. A shared client stays running while another scope still owns a reference.
119
+ The constructor options belong to pg-boss. `jobs` is the complete list of registrations for this Layer. The Layer captures `MailLive` for both the queue handler and the scheduled Effect. A startup or registration failure fails Layer acquisition with `PgBossError` or `PgBossQueueOptionsError` and releases its acquired client reference. A shared client stays running while another scope still owns a reference.
120
120
 
121
121
  Keep the Layer in the application's worker runtime scope. A short scope is useful for an acquisition or health check; a worker process needs its scope to remain open while it handles jobs.
122
122
 
@@ -173,7 +173,35 @@ export const readJobCounts = Effect.gen(function* () {
173
173
  });
174
174
  ```
175
175
 
176
- `health` exposes pg-boss queue counts as data. Its total fields include the registered queue's active, failed, queued and ready counts, plus the dead-letter queue's queued count. Decide in the application which values affect an HTTP health response or an alert.
176
+ `health` exposes pg-boss cached queue counts as data. It stays cheap and follows the pg-boss monitor interval; it does not establish that a queue has just drained. Its total fields include the registered queue's active, failed, queued and ready counts, plus the dead-letter queue's queued count. Decide in the application which values affect an HTTP health response or an alert.
177
+
178
+ ### Read live counts and retry a job
179
+
180
+ ```ts
181
+ import { Effect, Option } from "effect";
182
+ import { SendEmail } from "./jobs.ts";
183
+ import { Jobs } from "./services.ts";
184
+
185
+ export const inspectEmail = (id: string) => Effect.gen(function* () {
186
+ const jobs = yield* Jobs;
187
+ const job = yield* jobs.getJob(SendEmail, id);
188
+ if (Option.isSome(job) && job.value.state === "failed") {
189
+ yield* jobs.retry(SendEmail, id);
190
+ }
191
+ const counts = yield* jobs.counts(SendEmail);
192
+ return counts.queuedCount === 0 && counts.activeCount === 0;
193
+ });
194
+ ```
195
+
196
+ `counts(queue)` reads the job table directly on each call. `queuedCount` includes created and retry-waiting jobs, including future jobs; `activeCount` counts running jobs, `failedCount` counts retained failures, and `totalCount` includes retained terminal jobs. A queue has drained when queued and active counts are both zero. These counts are a snapshot, so a producer can enqueue more work after the query returns.
197
+
198
+ `getJob(queue, id)` returns `None` when the ID is absent, or `Some` pg-boss job metadata with `data` decoded by the queue's Schema. Invalid stored data fails with `PgBossPayloadError`, and the Effect requires the Schema's decoding services. `retry(queue, id)` reuses the original ID: it makes a failed job eligible for another attempt and pulls a retry-waiting job forward to run now. Missing IDs and jobs in other states are left unchanged. It does not remove an earlier copy from the dead-letter queue.
199
+
200
+ ### Queue settings on startup
201
+
202
+ `queue` accepts pg-boss `Queue` options except `name` and `deadLetter`, which the definition and adapter own. For prompt delivery, set `queue: { notify: true }` and enable `useListenNotify: true` in the worker Layer's constructor options. The PostgreSQL notification test waits for an idle worker with a ten-second polling interval and verifies delivery within 1.5 seconds.
203
+
204
+ Startup creates missing queues and reconciles declared settings on existing queues through `updateQueue`. Unspecified settings keep their stored values; the adapter always supplies its default retry settings and dead-letter destination. Changing an explicitly declared `policy` or `partition` on an existing queue fails startup with `PgBossQueueOptionsError`; its `queue`, `options` and message identify the conflict. Queue setting changes apply to subsequently enqueued jobs. Schedule queues follow the same registration path.
177
205
 
178
206
  ### Share a client between Layer builds
179
207
 
@@ -195,7 +223,17 @@ Overlapping Layer builds with the same `clientCacheKey` share one started client
195
223
 
196
224
  ### Separate producers and workers
197
225
 
198
- Pass a queue definition directly in `Jobs.layer({ jobs: [SendEmail] })` to create its queue and dead-letter queue without starting a consumer. A separate worker process registers `SendEmail.handle(...)` against the same database. Producer queues use the same retry options and appear in `health`; only worker registrations capture handler services.
226
+ Pass a queue definition directly in the jobs Layer to create its queue and dead-letter queue without starting a consumer:
227
+
228
+ ```ts
229
+ import { SendEmail } from "./jobs.ts";
230
+ import { Jobs } from "./services.ts";
231
+
232
+ export const producerLayer = (databaseUrl: string) =>
233
+ Jobs.layer({ connectionString: databaseUrl, jobs: [SendEmail] });
234
+ ```
235
+
236
+ Provide this Layer to the request runtime and call `jobs.enqueue(SendEmail, { userId })` as above. A separate worker process registers `SendEmail.handle(...)` against the same database. Producer queues use the same retry options and appear in `health`; only worker registrations capture handler services. The PostgreSQL producer test creates both queues through this Layer, enqueues a transformed payload, and observes a failing worker exhaust two retries before the job reaches its dead-letter queue.
199
237
 
200
238
  ### API
201
239
 
@@ -205,18 +243,21 @@ Import the module that defines the name; the package has no root entry.
205
243
  | --- | --- |
206
244
  | `@shivaedev/effect-pg-boss/definition.ts` | `defineQueue`, `defineSchedule`, `jobContext`; `DefineQueueOptions`, `DefineScheduleOptions`, `JobContext`, `JobPayloadSchema`, `JobRegistration`, `QueueDefinition`, `QueueWorker`, `RegistrationRequirements`, `ScheduleDefinition`, `ScheduledWorker` |
207
245
  | `@shivaedev/effect-pg-boss/service.ts` | `makePgBoss`; `PgBossDefinition`, `PgBossLayerOptions`, `PgBossService` |
208
- | `@shivaedev/effect-pg-boss/health.ts` | `deadLetterQueueName`; `JobsHealth`, `QueueHealth` |
209
- | `@shivaedev/effect-pg-boss/error.ts` | `PgBossError`, `PgBossPayloadError`, `toPgBossError`; `PgBossOperation` |
246
+ | `@shivaedev/effect-pg-boss/health.ts` | `deadLetterQueueName`; `JobsHealth`, `QueueCounts`, `QueueHealth` |
247
+ | `@shivaedev/effect-pg-boss/error.ts` | `PgBossError`, `PgBossPayloadError`, `PgBossQueueOptionsError`, `toPgBossError`; `PgBossOperation` |
210
248
  | `@shivaedev/effect-pg-boss/client.ts` | `defaultClientFactory`; `PgBossClient`, `PgBossClientFactory` |
211
249
 
212
- The definition options keep the pg-boss names: `queue` uses `QueueOptions` except `deadLetter`, `worker` uses `WorkOptions`, and a schedule's `schedule` uses `ScheduleOptions`. A queue also requires `name` and `schema`; a schedule requires `name` and `cron`.
250
+ The definition options keep the pg-boss names: `queue` uses `Queue` except `name` and `deadLetter`, `worker` uses `WorkOptions`, and a schedule's `schedule` uses `ScheduleOptions`. A queue also requires `name` and `schema`; a schedule requires `name` and `cron`.
213
251
 
214
- The application's service has two operations:
252
+ The application's service has these operations:
215
253
 
216
254
  - `enqueue(queue, payload, options?)`: an Effect returning `Option.Option<string>`, with `PgBossError | PgBossPayloadError` in its error type. Its options use pg-boss `SendOptions`.
217
- - `health`: an Effect returning `JobsHealth`, with `PgBossError` in its error type.
255
+ - `health`: an Effect returning cached `JobsHealth`, with `PgBossError` in its error type.
256
+ - `counts(queue)`: an Effect returning live `QueueCounts`, with `PgBossError` in its error type.
257
+ - `getJob(queue, id)`: an Effect returning `Option.Option<JobWithMetadata<Payload>>` with decoded payload data, `PgBossError | PgBossPayloadError` in its error type and the Schema's decoding services in its requirements.
258
+ - `retry(queue, id)`: an Effect returning `void`, with `PgBossError` in its error type.
218
259
 
219
- `Jobs.layer(options)` accepts pg-boss `ConstructorOptions` plus `jobs`, optional `clientCacheKey`, optional `clientFactory`, optional `onError` and optional `stop`. The factory type accepts constructor options and returns `PgBossClient`; `onError` has the type `(error: Error) => Effect.Effect<unknown, never, R>`; `stop` uses pg-boss `StopOptions`.
260
+ `Jobs.layer(options)` accepts pg-boss `ConstructorOptions` plus `jobs`, optional `clientCacheKey`, optional `clientFactory`, optional `onError` and optional `stop`. The factory type accepts constructor options and returns `PgBossClient`. Custom clients can supply the optional native capabilities `findJobs`, `retry`, `update`, `getDb` and `updateQueue` for lookup, retry, live counts and reconciliation; a requested operation fails with `PgBossError` if its required capability is absent. `onError` has the type `(error: Error) => Effect.Effect<unknown, never, R>`; `stop` uses pg-boss `StopOptions`.
220
261
 
221
262
  `onError` handles pg-boss client `error` events using the services captured by the Layer. The Layer's requirement type includes the workers' services, the workers' payload Schemas' `DecodingServices` and the callback's services. `enqueue` includes the payload Schema's `EncodingServices` in its requirement type.
222
263
 
@@ -227,12 +268,12 @@ The application's service has two operations:
227
268
  ### Install, setup and limits
228
269
 
229
270
  ```sh
230
- pnpm add @shivaedev/effect-pg-boss effect@4.0.4 pg-boss@12.23.1
271
+ pnpm add @shivaedev/effect-pg-boss effect@4.0.4 pg-boss@12.37.0
231
272
  ```
232
273
 
233
274
  The package requires Node.js 24 or later and PostgreSQL. `effect` and `pg-boss` are peers; use versions that satisfy the package's published peer ranges.
234
275
 
235
- Provide the database connection and job registrations at the application runtime boundary. Application services own the domain work and provider calls; pg-boss owns queue execution. Treat enqueueing and an application database transaction as separate operations, and choose any required transaction or outbox policy in the application.
276
+ Provide the database connection and job registrations at the application runtime boundary. Application services own the domain work and provider calls; pg-boss owns queue execution. Treat enqueueing and an application database transaction as separate operations. Enqueue after the application write commits, and handle queue failures in the application so they cannot roll back the write. The starter logs enqueue failures and returns the saved note; a failed enqueue leaves its word count pending. The package supplies no application transaction adapter.
236
277
 
237
278
  For package development, the real PostgreSQL test uses `PLATFORM_EFFECT_PG_BOSS_TEST_DATABASE_URL` and skips when the variable is absent. A skipped test does not establish durable queue behavior. Fake-client tests cover registration and lifecycle calls; they do not establish real cron execution, retry timing or deployment behavior. The package is built for ShivaeDev applications and may change without a deprecation period.
238
279
 
@@ -1,14 +1,20 @@
1
- import type { ConstructorOptions, Job, Queue, QueueResult, ScheduleOptions, SendOptions, StopOptions, WorkOptions } from "pg-boss";
1
+ import type { ConstructorOptions, FindJobsOptions, Job, JobWithMetadata, Queue, QueueResult, ScheduleOptions, SendOptions, StopOptions, WorkOptions } from "pg-boss";
2
+ import { PgBoss } from "pg-boss";
2
3
  export interface PgBossClient {
3
4
  readonly createQueue: (name: string, options?: Omit<Queue, "name">) => Promise<void>;
5
+ readonly findJobs?: (name: string, options?: FindJobsOptions) => Promise<readonly JobWithMetadata<unknown>[]>;
6
+ readonly getDb?: PgBoss["getDb"];
4
7
  readonly getQueue: (name: string) => Promise<QueueResult | null>;
5
8
  readonly off: (event: "error", listener: (error: Error) => void) => unknown;
6
9
  readonly offWork: (name: string) => Promise<void>;
7
10
  readonly on: (event: "error", listener: (error: Error) => void) => unknown;
11
+ readonly retry?: PgBoss["retry"];
8
12
  readonly schedule: (name: string, cron: string, data?: object | null, options?: ScheduleOptions) => Promise<void>;
9
13
  readonly send: (name: string, data?: object | null, options?: SendOptions) => Promise<string | null>;
10
14
  readonly start: () => Promise<unknown>;
11
15
  readonly stop: (options?: StopOptions) => Promise<void>;
16
+ readonly update?: PgBoss["update"];
17
+ readonly updateQueue?: PgBoss["updateQueue"];
12
18
  readonly work: (name: string, options: WorkOptions, handler: (jobs: readonly Job<unknown>[]) => Promise<unknown>) => Promise<string>;
13
19
  }
14
20
  export type PgBossClientFactory = (options: ConstructorOptions) => PgBossClient;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/server/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGnI,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACjE,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,OAAO,CAAC;IAC5E,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,QAAQ,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,OAAO,CAAC;IAC3E,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClH,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACrG,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACrI;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,kBAAkB,KAAK,YAAY,CAAC;AAEhF,eAAO,MAAM,oBAAoB,EAAE,mBAAsD,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/server/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,kBAAkB,EAClB,eAAe,EACf,GAAG,EACH,eAAe,EACf,KAAK,EACL,WAAW,EACX,eAAe,EACf,WAAW,EACX,WAAW,EACX,WAAW,EACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEjC,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACrF,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,SAAS,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC9G,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IACjE,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,OAAO,CAAC;IAC5E,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,QAAQ,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,KAAK,OAAO,CAAC;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IACjC,QAAQ,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClH,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACrG,QAAQ,CAAC,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;IACnC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;IAC7C,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,SAAS,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACrI;AAED,MAAM,MAAM,mBAAmB,GAAG,CAAC,OAAO,EAAE,kBAAkB,KAAK,YAAY,CAAC;AAEhF,eAAO,MAAM,oBAAoB,EAAE,mBAAsD,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/server/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAiBjC,MAAM,CAAC,MAAM,oBAAoB,GAAwB,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/server/client.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAsBjC,MAAM,CAAC,MAAM,oBAAoB,GAAwB,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import type { Effect, Schema } from "effect";
2
- import type { Job, QueueOptions, ScheduleOptions, WorkOptions } from "pg-boss";
2
+ import type { Job, Queue, ScheduleOptions, WorkOptions } from "pg-boss";
3
3
  export interface JobPayloadSchema extends Schema.Top {
4
4
  readonly Encoded: object;
5
5
  readonly Type: object;
@@ -15,7 +15,7 @@ export interface QueueDefinition<Name extends string = string, Payload extends J
15
15
  readonly _tag: "QueueDefinition";
16
16
  readonly handle: <E, R>(handler: (payload: Schema.Schema.Type<Payload>, job: JobContext) => Effect.Effect<unknown, E, R>) => QueueWorker<Payload, R>;
17
17
  readonly name: Name;
18
- readonly queueOptions: Omit<QueueOptions, "deadLetter">;
18
+ readonly queueOptions: Omit<Queue, "name" | "deadLetter">;
19
19
  readonly schema: Payload;
20
20
  readonly workerOptions: WorkOptions;
21
21
  }
@@ -31,7 +31,7 @@ export interface ScheduleDefinition<Name extends string = string> {
31
31
  readonly _tag: "ScheduleDefinition";
32
32
  readonly cron: string;
33
33
  readonly name: Name;
34
- readonly queueOptions: Omit<QueueOptions, "deadLetter">;
34
+ readonly queueOptions: Omit<Queue, "name" | "deadLetter">;
35
35
  readonly run: <E, R>(effect: Effect.Effect<unknown, E, R>) => ScheduledWorker<R>;
36
36
  readonly scheduleOptions: ScheduleOptions;
37
37
  readonly workerOptions: WorkOptions;
@@ -44,7 +44,7 @@ export interface ScheduledWorker<Requirements = unknown> {
44
44
  export type RegistrationRequirements<Registrations extends readonly JobRegistration[]> = Registrations[number] extends infer Registration ? Registration extends QueueWorker<infer Payload, infer Requirements> ? Requirements | Payload["DecodingServices"] : Registration extends ScheduledWorker<infer Requirements> ? Requirements : never : never;
45
45
  export interface DefineQueueOptions<Name extends string, Payload extends JobPayloadSchema> {
46
46
  readonly name: Name;
47
- readonly queue?: Omit<QueueOptions, "deadLetter">;
47
+ readonly queue?: Omit<Queue, "name" | "deadLetter">;
48
48
  readonly schema: Payload;
49
49
  readonly worker?: WorkOptions;
50
50
  }
@@ -52,7 +52,7 @@ export declare const defineQueue: <const Name extends string, const Payload exte
52
52
  export interface DefineScheduleOptions<Name extends string> {
53
53
  readonly cron: string;
54
54
  readonly name: Name;
55
- readonly queue?: Omit<QueueOptions, "deadLetter">;
55
+ readonly queue?: Omit<Queue, "name" | "deadLetter">;
56
56
  readonly schedule?: ScheduleOptions;
57
57
  readonly worker?: WorkOptions;
58
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/server/definition.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/server/definition.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { Redacted } from "effect";
2
- export type PgBossOperation = "enqueue" | "health" | "register" | "start" | "stop";
2
+ export type PgBossOperation = "counts" | "enqueue" | "getJob" | "health" | "register" | "retry" | "start" | "stop";
3
3
  declare const PgBossError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
4
4
  readonly _tag: "PgBossError";
5
5
  } & Readonly<A>;
@@ -9,6 +9,15 @@ export declare class PgBossError extends PgBossError_base<{
9
9
  readonly original: Redacted.Redacted<unknown>;
10
10
  }> {
11
11
  }
12
+ declare const PgBossQueueOptionsError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
13
+ readonly _tag: "PgBossQueueOptionsError";
14
+ } & Readonly<A>;
15
+ export declare class PgBossQueueOptionsError extends PgBossQueueOptionsError_base<{
16
+ readonly queue: string;
17
+ readonly options: readonly ("partition" | "policy")[];
18
+ }> {
19
+ get message(): string;
20
+ }
12
21
  declare const PgBossPayloadError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
13
22
  readonly _tag: "PgBossPayloadError";
14
23
  } & Readonly<A>;
@@ -1 +1 @@
1
- {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/server/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAExC,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;;;;AAEnF,qBAAa,WAAY,SAAQ,iBAAgC;IAChE,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;CAAG;;;;AAEL,qBAAa,kBAAmB,SAAQ,wBAAuC;IAC9E,QAAQ,CAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;CAAG;AAEL,eAAO,MAAM,aAAa,cAAe,eAAe,SAAS,OAAO,UAAU,MAAM,KAAG,WAKxF,CAAC"}
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/server/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAExC,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,CAAC;;;;AAEnH,qBAAa,WAAY,SAAQ,iBAAgC;IAChE,QAAQ,CAAC,SAAS,EAAE,eAAe,CAAC;IACpC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;CAAG;;;;AAEL,qBAAa,uBAAwB,SAAQ,6BAA4C;IACxF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,QAAQ,CAAC,EAAE,CAAC;CACtD,CAAC;IACD,IAAa,OAAO,IAAI,MAAM,CAE7B;CACD;;;;AAED,qBAAa,kBAAmB,SAAQ,wBAAuC;IAC9E,QAAQ,CAAC,SAAS,EAAE,QAAQ,GAAG,QAAQ,CAAC;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;CAC9C,CAAC;CAAG;AAEL,eAAO,MAAM,aAAa,cAAe,eAAe,SAAS,OAAO,UAAU,MAAM,KAAG,WAKxF,CAAC"}
@@ -1,6 +1,11 @@
1
1
  import { Data, Redacted } from "effect";
2
2
  export class PgBossError extends Data.TaggedError("PgBossError") {
3
3
  }
4
+ export class PgBossQueueOptionsError extends Data.TaggedError("PgBossQueueOptionsError") {
5
+ get message() {
6
+ return `Queue ${this.queue} cannot change options after creation: ${this.options.join(", ")}`;
7
+ }
8
+ }
4
9
  export class PgBossPayloadError extends Data.TaggedError("PgBossPayloadError") {
5
10
  }
6
11
  export const toPgBossError = (operation, error, queue) => new PgBossError({
@@ -1 +1 @@
1
- {"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/server/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAIxC,MAAM,OAAO,WAAY,SAAQ,IAAI,CAAC,WAAW,CAAC,aAAa,CAI7D;CAAG;AAEL,MAAM,OAAO,kBAAmB,SAAQ,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAI3E;CAAG;AAEL,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAA0B,EAAE,KAAc,EAAE,KAAc,EAAe,EAAE,CACxG,IAAI,WAAW,CAAC;IACf,SAAS;IACT,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;IAC9B,KAAK;CACL,CAAC,CAAC"}
1
+ {"version":3,"file":"error.js","sourceRoot":"","sources":["../../src/server/error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAIxC,MAAM,OAAO,WAAY,SAAQ,IAAI,CAAC,WAAW,CAAC,aAAa,CAI7D;CAAG;AAEL,MAAM,OAAO,uBAAwB,SAAQ,IAAI,CAAC,WAAW,CAAC,yBAAyB,CAGrF;IACD,IAAa,OAAO;QACnB,OAAO,SAAS,IAAI,CAAC,KAAK,0CAA0C,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC/F,CAAC;CACD;AAED,MAAM,OAAO,kBAAmB,SAAQ,IAAI,CAAC,WAAW,CAAC,oBAAoB,CAI3E;CAAG;AAEL,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,SAA0B,EAAE,KAAc,EAAE,KAAc,EAAe,EAAE,CACxG,IAAI,WAAW,CAAC;IACf,SAAS;IACT,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;IAC9B,KAAK;CACL,CAAC,CAAC"}
@@ -1,3 +1,9 @@
1
+ export interface QueueCounts {
2
+ readonly activeCount: number;
3
+ readonly failedCount: number;
4
+ readonly queuedCount: number;
5
+ readonly totalCount: number;
6
+ }
1
7
  export interface QueueHealth {
2
8
  readonly activeCount: number;
3
9
  readonly deadLetteredCount: number;
@@ -1 +1 @@
1
- {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/server/health.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,mBAAmB,cAAe,MAAM,KAAG,MAA4B,CAAC"}
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/server/health.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,UAAU;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAC;IACtC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC5B;AAED,eAAO,MAAM,mBAAmB,cAAe,MAAM,KAAG,MAA4B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/server/health.ts"],"names":[],"mappings":"AAkBA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,SAAiB,EAAU,EAAE,CAAC,GAAG,SAAS,MAAM,CAAC"}
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/server/health.ts"],"names":[],"mappings":"AAyBA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,SAAiB,EAAU,EAAE,CAAC,GAAG,SAAS,MAAM,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Effect } from "effect";
2
+ import type { PgBossClient } from "#client.ts";
3
+ import type { QueueCounts } from "#health.ts";
4
+ export declare function countsFor(client: PgBossClient, schema: string, name: string): Effect.Effect<QueueCounts, import("#error.ts").PgBossError>;
5
+ //# sourceMappingURL=countsFor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"countsFor.d.ts","sourceRoot":"","sources":["../../../src/server/internal/countsFor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAU,MAAM,QAAQ,CAAC;AACxC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAS9C,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,WAAW,EAAE,WAAW,CAAC,CAoBzI"}
@@ -0,0 +1,27 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { toPgBossError } from "#error.ts";
3
+ const Counts = Schema.Struct({
4
+ activeCount: Schema.Number,
5
+ failedCount: Schema.Number,
6
+ queuedCount: Schema.Number,
7
+ totalCount: Schema.Number,
8
+ });
9
+ export function countsFor(client, schema, name) {
10
+ return Effect.tryPromise({
11
+ catch: (error) => toPgBossError("counts", error, name),
12
+ try: async () => {
13
+ if (client.getDb === undefined) {
14
+ throw new TypeError("This pg-boss client does not support getDb");
15
+ }
16
+ const quotedSchema = `"${schema.replaceAll('"', '""')}"`;
17
+ const { rows } = await client.getDb().executeSql(`SELECT
18
+ count(*) FILTER (WHERE state = 'active')::int AS "activeCount",
19
+ count(*) FILTER (WHERE state = 'failed')::int AS "failedCount",
20
+ count(*) FILTER (WHERE state IN ('created', 'retry'))::int AS "queuedCount",
21
+ count(*)::int AS "totalCount"
22
+ FROM ${quotedSchema}.job WHERE name = $1`, [name]);
23
+ return Schema.decodeUnknownPromise(Counts)(rows[0]);
24
+ },
25
+ });
26
+ }
27
+ //# sourceMappingURL=countsFor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"countsFor.js","sourceRoot":"","sources":["../../../src/server/internal/countsFor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC,MAAM;IAC1B,WAAW,EAAE,MAAM,CAAC,MAAM;IAC1B,WAAW,EAAE,MAAM,CAAC,MAAM;IAC1B,UAAU,EAAE,MAAM,CAAC,MAAM;CACzB,CAAC,CAAC;AAEH,MAAM,UAAU,SAAS,CAAC,MAAoB,EAAE,MAAc,EAAE,IAAY;IAC3E,OAAO,MAAM,CAAC,UAAU,CAAC;QACxB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC;QACtD,GAAG,EAAE,KAAK,IAAI,EAAE;YACf,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;gBAChC,MAAM,IAAI,SAAS,CAAC,4CAA4C,CAAC,CAAC;YACnE,CAAC;YACD,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;YACzD,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC,UAAU,CAC/C;;;;;WAKO,YAAY,sBAAsB,EACzC,CAAC,IAAI,CAAC,CACN,CAAC;YACF,OAAO,MAAM,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QACrD,CAAC;KACD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { Queue } from "pg-boss";
2
+ import type { PgBossClient } from "#client.ts";
3
+ export declare function ensureQueue(client: PgBossClient, name: string, options: Omit<Queue, "name" | "deadLetter">): Promise<void>;
4
+ //# sourceMappingURL=ensureQueue.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensureQueue.d.ts","sourceRoot":"","sources":["../../../src/server/internal/ensureQueue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAI/C,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBhI"}
@@ -0,0 +1,27 @@
1
+ import { PgBossQueueOptionsError } from "#error.ts";
2
+ import { deadLetterQueueName } from "#health.ts";
3
+ export async function ensureQueue(client, name, options) {
4
+ const deadLetter = deadLetterQueueName(name);
5
+ const desired = { retryBackoff: true, retryLimit: 3, ...options, deadLetter };
6
+ await client.createQueue(deadLetter);
7
+ await client.createQueue(name, desired);
8
+ const existing = await client.getQueue(name);
9
+ if (existing === null) {
10
+ return;
11
+ }
12
+ const immutable = ["partition", "policy"].filter((key) => desired[key] !== undefined && desired[key] !== existing[key]);
13
+ if (immutable.length > 0) {
14
+ throw new PgBossQueueOptionsError({ options: immutable, queue: name });
15
+ }
16
+ const { partition: _partition, policy: _policy, ...mutable } = desired;
17
+ const changed = Object.entries(mutable).some(([key, value]) => value !== undefined && value !== Reflect.get(existing, key));
18
+ if (!changed) {
19
+ return;
20
+ }
21
+ if (client.updateQueue === undefined) {
22
+ throw new TypeError("This pg-boss client does not support updateQueue");
23
+ }
24
+ // pg-boss validates retryDelayMax against retryBackoff in the same update.
25
+ await client.updateQueue(name, mutable);
26
+ }
27
+ //# sourceMappingURL=ensureQueue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ensureQueue.js","sourceRoot":"","sources":["../../../src/server/internal/ensureQueue.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAoB,EAAE,IAAY,EAAE,OAA2C;IAChH,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,EAAE,GAAG,OAAO,EAAE,UAAU,EAAE,CAAC;IAC9E,MAAM,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACxC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;QACvB,OAAO;IACR,CAAC;IACD,MAAM,SAAS,GAAI,CAAC,WAAW,EAAE,QAAQ,CAAW,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IACnI,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,uBAAuB,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,CAAC;IACvE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC5H,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,OAAO;IACR,CAAC;IACD,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACtC,MAAM,IAAI,SAAS,CAAC,kDAAkD,CAAC,CAAC;IACzE,CAAC;IACD,2EAA2E;IAC3E,MAAM,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { PgBossClient } from "#client.ts";
2
+ import type { PgBossService } from "#service.ts";
3
+ export declare function getJobFor(client: PgBossClient): PgBossService["getJob"];
4
+ export declare function retryFor(client: PgBossClient): PgBossService["retry"];
5
+ //# sourceMappingURL=jobControl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobControl.d.ts","sourceRoot":"","sources":["../../../src/server/internal/jobControl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,wBAAgB,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAAC,QAAQ,CAAC,CAoBvE;AAED,wBAAgB,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAAC,OAAO,CAAC,CAkBrE"}
@@ -0,0 +1,34 @@
1
+ import { Effect, Option, Redacted, Schema } from "effect";
2
+ import { PgBossPayloadError, toPgBossError } from "#error.ts";
3
+ export function getJobFor(client) {
4
+ return (queue, id) => Effect.tryPromise({
5
+ catch: (error) => toPgBossError("getJob", error, queue.name),
6
+ try: async () => {
7
+ if (client.findJobs === undefined) {
8
+ throw new TypeError("This pg-boss client does not support findJobs");
9
+ }
10
+ return (await client.findJobs(queue.name, { id }))[0];
11
+ },
12
+ }).pipe(Effect.flatMap((job) => job === undefined
13
+ ? Effect.succeed(Option.none())
14
+ : Schema.decodeUnknownEffect(queue.schema)(job.data).pipe(Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue: queue.name })), Effect.map((data) => Option.some({ ...job, data })))));
15
+ }
16
+ export function retryFor(client) {
17
+ return (queue, id) => Effect.tryPromise({
18
+ catch: (error) => toPgBossError("retry", error, queue.name),
19
+ try: async () => {
20
+ if (client.findJobs === undefined || client.retry === undefined || client.update === undefined) {
21
+ throw new TypeError("This pg-boss client does not support findJobs, retry and update");
22
+ }
23
+ const job = (await client.findJobs(queue.name, { id }))[0];
24
+ if (job?.state !== "failed" && job?.state !== "retry") {
25
+ return;
26
+ }
27
+ if (job.state === "failed") {
28
+ await client.retry(queue.name, id);
29
+ }
30
+ await client.update(queue.name, undefined, { id, startAfter: 0 });
31
+ },
32
+ });
33
+ }
34
+ //# sourceMappingURL=jobControl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jobControl.js","sourceRoot":"","sources":["../../../src/server/internal/jobControl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE1D,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG9D,MAAM,UAAU,SAAS,CAAC,MAAoB;IAC7C,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CACpB,MAAM,CAAC,UAAU,CAAC;QACjB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;QAC5D,GAAG,EAAE,KAAK,IAAI,EAAE;YACf,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;gBACnC,MAAM,IAAI,SAAS,CAAC,+CAA+C,CAAC,CAAC;YACtE,CAAC;YACD,OAAO,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvD,CAAC;KACD,CAAC,CAAC,IAAI,CACN,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE,CACtB,GAAG,KAAK,SAAS;QAChB,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC;QAC/B,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CACvD,MAAM,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,kBAAkB,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,EAC9H,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CACnD,CACH,CACD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,MAAoB;IAC5C,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,CACpB,MAAM,CAAC,UAAU,CAAC;QACjB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;QAC3D,GAAG,EAAE,KAAK,IAAI,EAAE;YACf,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;gBAChG,MAAM,IAAI,SAAS,CAAC,iEAAiE,CAAC,CAAC;YACxF,CAAC;YACD,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3D,IAAI,GAAG,EAAE,KAAK,KAAK,QAAQ,IAAI,GAAG,EAAE,KAAK,KAAK,OAAO,EAAE,CAAC;gBACvD,OAAO;YACR,CAAC;YACD,IAAI,GAAG,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC5B,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YACpC,CAAC;YACD,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC;QACnE,CAAC;KACD,CAAC,CAAC;AACL,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import { type Context, Effect } from "effect";
2
2
  import type { PgBossClient } from "#client.ts";
3
3
  import { type JobRegistration } from "#definition.ts";
4
+ import { PgBossQueueOptionsError } from "#error.ts";
4
5
  export declare const registrationName: (registration: JobRegistration) => string;
5
6
  export declare const registrationNames: (registrations: readonly JobRegistration[]) => readonly string[];
6
- export declare const registerJobs: <R>(client: PgBossClient, registrations: readonly JobRegistration[], context: Context.Context<R>, replaceWorkers: boolean) => Effect.Effect<void, import("#error.ts").PgBossError>;
7
+ export declare const registerJobs: <R>(client: PgBossClient, registrations: readonly JobRegistration[], context: Context.Context<R>, replaceWorkers: boolean) => Effect.Effect<void, import("#error.ts").PgBossError | PgBossQueueOptionsError>;
7
8
  //# sourceMappingURL=register.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/server/internal/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,EAAoB,MAAM,QAAQ,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,KAAK,eAAe,EAA4E,MAAM,gBAAgB,CAAC;AAwBhI,eAAO,MAAM,gBAAgB,iBAAkB,eAAe,KAAG,MAWhE,CAAC;AA+EF,eAAO,MAAM,iBAAiB,kBAAmB,SAAS,eAAe,EAAE,KAAG,SAAS,MAAM,EAM5F,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,UACrB,YAAY,iBACL,SAAS,eAAe,EAAE,WAChC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,kBACX,OAAO,KACrB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,WAAW,EAAE,WAAW,CAcnD,CAAC"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/server/internal/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,EAAoB,MAAM,QAAQ,CAAC;AAEhE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EAAE,KAAK,eAAe,EAA4E,MAAM,gBAAgB,CAAC;AAChI,OAAO,EAAsB,uBAAuB,EAAiB,MAAM,WAAW,CAAC;AAevF,eAAO,MAAM,gBAAgB,iBAAkB,eAAe,KAAG,MAWhE,CAAC;AAqEF,eAAO,MAAM,iBAAiB,kBAAmB,SAAS,eAAe,EAAE,KAAG,SAAS,MAAM,EAM5F,CAAC;AAEF,eAAO,MAAM,YAAY,GAAI,CAAC,UACrB,YAAY,iBACL,SAAS,eAAe,EAAE,WAChC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,kBACX,OAAO,KACrB,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,WAAW,EAAE,WAAW,GAAG,uBAAuB,CAc7E,CAAC"}
@@ -1,14 +1,7 @@
1
1
  import { Effect, Redacted, Schema } from "effect";
2
2
  import { jobContext } from "#definition.ts";
3
- import { PgBossPayloadError, toPgBossError } from "#error.ts";
4
- import { deadLetterQueueName } from "#health.ts";
5
- function queueOptions(options) {
6
- return {
7
- retryBackoff: true,
8
- retryLimit: 3,
9
- ...options,
10
- };
11
- }
3
+ import { PgBossPayloadError, PgBossQueueOptionsError, toPgBossError } from "#error.ts";
4
+ import { ensureQueue } from "#internal/ensureQueue.ts";
12
5
  function isQueueWorker(registration) {
13
6
  return registration._tag === "QueueWorker";
14
7
  }
@@ -43,15 +36,10 @@ function runQueueWorker(worker, job, context) {
43
36
  async function registerQueue(client, registration, context, replaceWorker) {
44
37
  const queue = registration._tag === "QueueWorker" ? registration.queue : registration;
45
38
  const name = queue.name;
46
- const deadLetter = deadLetterQueueName(name);
47
39
  if (replaceWorker && registration._tag === "QueueWorker") {
48
40
  await client.offWork(name);
49
41
  }
50
- await client.createQueue(deadLetter);
51
- await client.createQueue(name, {
52
- ...queueOptions(queue.queueOptions),
53
- deadLetter,
54
- });
42
+ await ensureQueue(client, name, queue.queueOptions);
55
43
  if (registration._tag === "QueueDefinition") {
56
44
  return;
57
45
  }
@@ -63,15 +51,10 @@ async function registerQueue(client, registration, context, replaceWorker) {
63
51
  }
64
52
  async function registerSchedule(client, worker, context, replaceWorker) {
65
53
  const { schedule } = worker;
66
- const deadLetter = deadLetterQueueName(schedule.name);
67
54
  if (replaceWorker) {
68
55
  await client.offWork(schedule.name);
69
56
  }
70
- await client.createQueue(deadLetter);
71
- await client.createQueue(schedule.name, {
72
- ...queueOptions(schedule.queueOptions),
73
- deadLetter,
74
- });
57
+ await ensureQueue(client, schedule.name, schedule.queueOptions);
75
58
  await client.work(schedule.name, schedule.workerOptions, async (jobs) => {
76
59
  for (const job of jobs) {
77
60
  await Effect.runPromise(Effect.provide(worker.effect, context), {
@@ -89,7 +72,7 @@ export const registrationNames = (registrations) => {
89
72
  return names;
90
73
  };
91
74
  export const registerJobs = (client, registrations, context, replaceWorkers) => Effect.tryPromise({
92
- catch: (error) => toPgBossError("register", error),
75
+ catch: (error) => (error instanceof PgBossQueueOptionsError ? error : toPgBossError("register", error)),
93
76
  try: async () => {
94
77
  registrationNames(registrations);
95
78
  const provided = workerContext(context);
@@ -1 +1 @@
1
- {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/server/internal/register.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/server/internal/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhE,OAAO,EAAwB,UAAU,EAAgE,MAAM,gBAAgB,CAAC;AAChI,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,SAAS,aAAa,CAAC,YAA6B;IACnD,OAAO,YAAY,CAAC,IAAI,KAAK,aAAa,CAAC;AAC5C,CAAC;AAED,SAAS,iBAAiB,CAAC,YAA6B;IACvD,OAAO,YAAY,CAAC,IAAI,KAAK,iBAAiB,CAAC;AAChD,CAAC;AAED,SAAS,iBAAiB,CAAC,YAA6B;IACvD,OAAO,YAAY,CAAC,IAAI,KAAK,iBAAiB,CAAC;AAChD,CAAC;AAED,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,YAA6B,EAAU,EAAE;IACzE,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;QACrC,OAAO,YAAY,CAAC,IAAI,CAAC;IAC1B,CAAC;IACD,IAAI,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC;IAChC,CAAC;IACD,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;QACrC,OAAO,YAAY,CAAC,QAAQ,CAAC,IAAI,CAAC;IACnC,CAAC;IACD,MAAM,IAAI,SAAS,CAAC,iCAAiC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;AAC3E,CAAC,CAAC;AAIF,SAAS,aAAa,CAAC,OAAgB;IACtC,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,SAAS,cAAc,CAAC,MAAmB,EAAE,GAAiB,EAAE,OAAiC;IAChG,OAAO,MAAM,CAAC,UAAU,CACvB,MAAM,CAAC,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAC7D,MAAM,CAAC,QAAQ,CACd,CAAC,KAAK,EAAE,EAAE,CACT,IAAI,kBAAkB,CAAC;QACtB,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;QAC9B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;KACxB,CAAC,CACH,EACD,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EACrE,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CACvB,EACD,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CACtB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa,CAC3B,MAAoB,EACpB,YAA2C,EAC3C,OAAiC,EACjC,aAAsB;IAEtB,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,KAAK,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC;IACtF,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IACxB,IAAI,aAAa,IAAI,YAAY,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;QAC1D,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,WAAW,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;IACpD,IAAI,YAAY,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QAC7C,OAAO;IACR,CAAC;IACD,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,aAAa,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;QAC3D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,cAAc,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QAClD,CAAC;IACF,CAAC,CAAC,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC9B,MAAoB,EACpB,MAAuB,EACvB,OAAiC,EACjC,aAAsB;IAEtB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC;IAC5B,IAAI,aAAa,EAAE,CAAC;QACnB,MAAM,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IACD,MAAM,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,YAAY,CAAC,CAAC;IAChE,MAAM,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,aAAa,EAAE,KAAK,EAAE,IAA6B,EAAE,EAAE;QAChG,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;gBAC/D,MAAM,EAAE,GAAG,CAAC,MAAM;aAClB,CAAC,CAAC;QACJ,CAAC;IACF,CAAC,CAAC,CAAC;IACH,MAAM,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,eAAe,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,aAAyC,EAAqB,EAAE;IACjG,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAClD,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;QAC1C,MAAM,IAAI,SAAS,CAAC,kCAAkC,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,KAAK,CAAC;AACd,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAG,CAC3B,MAAoB,EACpB,aAAyC,EACzC,OAA2B,EAC3B,cAAuB,EAC0D,EAAE,CACnF,MAAM,CAAC,UAAU,CAAC;IACjB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,YAAY,uBAAuB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACvG,GAAG,EAAE,KAAK,IAAI,EAAE;QACf,iBAAiB,CAAC,aAAa,CAAC,CAAC;QACjC,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACxC,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;YAC1C,IAAI,aAAa,CAAC,YAAY,CAAC,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;gBACpE,MAAM,aAAa,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;YACrE,CAAC;iBAAM,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;gBAC5C,MAAM,gBAAgB,CAAC,MAAM,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;YACxE,CAAC;QACF,CAAC;IACF,CAAC;CACD,CAAC,CAAC"}
@@ -1,4 +1,4 @@
1
1
  import type { PgBossClient } from "#client.ts";
2
2
  import type { PgBossService } from "#service.ts";
3
- export declare const makeService: (client: PgBossClient, names: readonly string[]) => PgBossService;
3
+ export declare const makeService: (client: PgBossClient, names: readonly string[], schema?: string) => PgBossService;
4
4
  //# sourceMappingURL=service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/server/internal/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,eAAO,MAAM,WAAW,WAAY,YAAY,SAAS,SAAS,MAAM,EAAE,KAAG,aA4B3E,CAAC"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/server/internal/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAK/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,eAAO,MAAM,WAAW,WAAY,YAAY,SAAS,SAAS,MAAM,EAAE,sBAAsB,aA+B9F,CAAC"}
@@ -1,7 +1,10 @@
1
1
  import { Effect, Option, Redacted, Schema } from "effect";
2
2
  import { PgBossPayloadError, toPgBossError } from "#error.ts";
3
- import { healthFor } from "./health.js";
4
- export const makeService = (client, names) => ({
3
+ import { countsFor } from "#internal/countsFor.ts";
4
+ import { healthFor } from "#internal/health.ts";
5
+ import { getJobFor, retryFor } from "#internal/jobControl.ts";
6
+ export const makeService = (client, names, schema = "pgboss") => ({
7
+ counts: (queue) => countsFor(client, schema, queue.name),
5
8
  enqueue: (queue, payload, options) => Schema.encodeUnknownEffect(queue.schema)(payload).pipe(Effect.mapError((error) => new PgBossPayloadError({
6
9
  direction: "encode",
7
10
  original: Redacted.make(error),
@@ -19,6 +22,8 @@ export const makeService = (client, names) => ({
19
22
  try: () => client.send(queue.name, encoded, options),
20
23
  }).pipe(Effect.map(Option.fromNullishOr));
21
24
  })),
25
+ getJob: getJobFor(client),
22
26
  health: healthFor(client, names),
27
+ retry: retryFor(client),
23
28
  });
24
29
  //# sourceMappingURL=service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/server/internal/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE1D,OAAO,EAAoB,kBAAkB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAEhF,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAoB,EAAE,KAAwB,EAAiB,EAAE,CAAC,CAAC;IAC9F,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CACpC,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CACrD,MAAM,CAAC,QAAQ,CACd,CAAC,KAAK,EAAE,EAAE,CACT,IAAI,kBAAkB,CAAC;QACtB,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;QAC9B,KAAK,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC,CACH,EACD,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAA0E,EAAE;QAClG,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrD,OAAO,MAAM,CAAC,IAAI,CACjB,IAAI,kBAAkB,CAAC;gBACtB,SAAS,EAAE,QAAQ;gBACnB,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;gBACjF,KAAK,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC,CACF,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC,UAAU,CAAC;YACxB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;YAC7D,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC;SACpD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CACF;IACF,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC;CAChC,CAAC,CAAC"}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/server/internal/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE1D,OAAO,EAAoB,kBAAkB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAG9D,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAoB,EAAE,KAAwB,EAAE,MAAM,GAAG,QAAQ,EAAiB,EAAE,CAAC,CAAC;IACjH,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC;IACxD,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CACpC,MAAM,CAAC,mBAAmB,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CACrD,MAAM,CAAC,QAAQ,CACd,CAAC,KAAK,EAAE,EAAE,CACT,IAAI,kBAAkB,CAAC;QACtB,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC;QAC9B,KAAK,EAAE,KAAK,CAAC,IAAI;KACjB,CAAC,CACH,EACD,MAAM,CAAC,OAAO,CAAC,CAAC,OAAO,EAA0E,EAAE;QAClG,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrD,OAAO,MAAM,CAAC,IAAI,CACjB,IAAI,kBAAkB,CAAC;gBACtB,SAAS,EAAE,QAAQ;gBACnB,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAC;gBACjF,KAAK,EAAE,KAAK,CAAC,IAAI;aACjB,CAAC,CACF,CAAC;QACH,CAAC;QACD,OAAO,MAAM,CAAC,UAAU,CAAC;YACxB,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC;YAC7D,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC;SACpD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CACF;IACF,MAAM,EAAE,SAAS,CAAC,MAAM,CAAC;IACzB,MAAM,EAAE,SAAS,CAAC,MAAM,EAAE,KAAK,CAAC;IAChC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC;CACvB,CAAC,CAAC"}
@@ -1,12 +1,15 @@
1
1
  import { Context, Effect, Layer, type Option, type Schema } from "effect";
2
- import type { ConstructorOptions, SendOptions, StopOptions } from "pg-boss";
2
+ import type { ConstructorOptions, JobWithMetadata, SendOptions, StopOptions } from "pg-boss";
3
3
  import type { PgBossClientFactory } from "#client.ts";
4
- import type { JobPayloadSchema, JobRegistration, QueueDefinition, RegistrationRequirements } from "./definition.ts";
5
- import type { PgBossError, PgBossPayloadError } from "./error.ts";
6
- import type { JobsHealth } from "./health.ts";
4
+ import type { JobPayloadSchema, JobRegistration, QueueDefinition, RegistrationRequirements } from "#definition.ts";
5
+ import type { PgBossError, PgBossPayloadError, PgBossQueueOptionsError } from "#error.ts";
6
+ import type { JobsHealth, QueueCounts } from "#health.ts";
7
7
  export interface PgBossService {
8
+ readonly counts: (queue: QueueDefinition) => Effect.Effect<QueueCounts, PgBossError>;
8
9
  readonly enqueue: <const TName extends string, const TPayload extends JobPayloadSchema>(queue: QueueDefinition<TName, TPayload>, payload: Schema.Schema.Type<TPayload>, options?: SendOptions) => Effect.Effect<Option.Option<string>, PgBossError | PgBossPayloadError, TPayload["EncodingServices"]>;
10
+ readonly getJob: <const TName extends string, const TPayload extends JobPayloadSchema>(queue: QueueDefinition<TName, TPayload>, id: string) => Effect.Effect<Option.Option<JobWithMetadata<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
9
11
  readonly health: Effect.Effect<JobsHealth, PgBossError>;
12
+ readonly retry: (queue: QueueDefinition, id: string) => Effect.Effect<void, PgBossError>;
10
13
  }
11
14
  export type PgBossLayerOptions<TRegistrations extends readonly JobRegistration[], TErrorRequirements> = ConstructorOptions & {
12
15
  readonly clientFactory?: PgBossClientFactory;
@@ -16,7 +19,7 @@ export type PgBossLayerOptions<TRegistrations extends readonly JobRegistration[]
16
19
  readonly stop?: StopOptions;
17
20
  };
18
21
  export interface PgBossDefinition<TIdentifier extends string = string> extends Context.Service<TIdentifier, PgBossService> {
19
- readonly layer: <const TRegistrations extends readonly JobRegistration[], TErrorRequirements = never>(options: PgBossLayerOptions<TRegistrations, TErrorRequirements>) => Layer.Layer<TIdentifier, PgBossError, RegistrationRequirements<TRegistrations> | TErrorRequirements>;
22
+ readonly layer: <const TRegistrations extends readonly JobRegistration[], TErrorRequirements = never>(options: PgBossLayerOptions<TRegistrations, TErrorRequirements>) => Layer.Layer<TIdentifier, PgBossError | PgBossQueueOptionsError, RegistrationRequirements<TRegistrations> | TErrorRequirements>;
20
23
  }
21
24
  export declare const makePgBoss: <const TIdentifier extends string>(identifier: TIdentifier) => PgBossDefinition<TIdentifier>;
22
25
  //# sourceMappingURL=service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC5E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAItD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAC;AACpH,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,aAAa;IAC7B,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,KAAK,SAAS,MAAM,EAAE,KAAK,CAAC,QAAQ,SAAS,gBAAgB,EACrF,KAAK,EAAE,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC,EACvC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EACrC,OAAO,CAAC,EAAE,WAAW,KACjB,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,kBAAkB,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAC1G,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,WAAW,CAAC,CAAC;CACxD;AAED,MAAM,MAAM,kBAAkB,CAAC,cAAc,SAAS,SAAS,eAAe,EAAE,EAAE,kBAAkB,IAAI,kBAAkB,GAAG;IAC5H,QAAQ,CAAC,aAAa,CAAC,EAAE,mBAAmB,CAAC;IAE7C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACtD,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,kBAAkB,CAAC,CAAC;IACvF,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC;CAC5B,CAAC;AAEF,MAAM,WAAW,gBAAgB,CAAC,WAAW,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,aAAa,CAAC;IACzH,QAAQ,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,cAAc,SAAS,SAAS,eAAe,EAAE,EAAE,kBAAkB,GAAG,KAAK,EACnG,OAAO,EAAE,kBAAkB,CAAC,cAAc,EAAE,kBAAkB,CAAC,KAC3D,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,WAAW,EAAE,wBAAwB,CAAC,cAAc,CAAC,GAAG,kBAAkB,CAAC,CAAC;CAC1G;AAMD,eAAO,MAAM,UAAU,GAAI,KAAK,CAAC,WAAW,SAAS,MAAM,cAAc,WAAW,KAAG,gBAAgB,CAAC,WAAW,CA6ClH,CAAC"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"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"}
@@ -31,7 +31,7 @@ export const makePgBoss = (identifier) => {
31
31
  resource.acquired.client.off("error", resource.errorListener);
32
32
  return releaseClient(resource.acquired, stop);
33
33
  });
34
- return Layer.effect(Service, Effect.map(acquire, ({ acquired }) => makeService(acquired.client, names)));
34
+ return Layer.effect(Service, Effect.map(acquire, ({ acquired }) => makeService(acquired.client, names, constructorOptions.schema)));
35
35
  };
36
36
  return Object.assign(Service, { layer });
37
37
  };
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"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"}
@@ -43,6 +43,6 @@ An application that needs only queueing should not import a repository framework
43
43
  - Domain workers, authorization rules, external-provider interfaces and application logging or health policy.
44
44
  - Another general service declaration system; native Context and Layer stay available, and general declaration ergonomics belong to `effect-service`.
45
45
  - Application repositories or migration ownership; those belong to `effect-sql`.
46
- - An implicit link between enqueueing and an application's database transaction. Transaction and outbox policy remain application decisions; after-commit changes have their own path through `effect-changes`.
46
+ - Transactional enqueueing: jobs use a separate connection from application SQL transactions. Applications own any required outbox policy; after-commit changes have their own path through `effect-changes`.
47
47
  - A promise of exactly-once domain side effects or provider idempotency. Those need application-specific decisions and evidence.
48
48
  - Browser, device or offline synchronization behavior. A PostgreSQL queue boundary cannot establish those product contracts.
package/docs/roadmap.md CHANGED
@@ -8,9 +8,13 @@ This file owns the package's implementation inventory and open API choices. The
8
8
  - [x] Object payload Schema definitions, decoded enqueue types and queue workers. Type tests reject primitive schemas, missing fields and encoded values passed as decoded payloads.
9
9
  - [x] Encoding at enqueue and decoding before the handler. The PostgreSQL test round-trips a transformed payload and checks that malformed stored data reaches the dead-letter queue without calling the domain handler.
10
10
  - [x] Queue and schedule registration, with dead-letter queues, default retry settings and UTC schedule registration. Fake-client tests verify the supplied settings and a retry-limit override.
11
+ - [x] Producer-only queue definitions create queues and dead-letter queues through `Jobs.layer({ jobs: [Queue] })`, without starting a consumer. The [PostgreSQL producer test](../src/server/producerPostgres.spec.ts) enqueues a transformed payload and observes worker retry exhaustion and dead-letter delivery. The [starter producer](../../../examples/starter/src/server/noteProducer.ts) uses this API.
11
12
  - [x] Worker and scheduled Effect service capture. Runtime and packed-consumer type tests preserve handler requirements.
12
13
  - [x] Scoped startup and shutdown, including cleanup when startup or registration fails.
13
14
  - [x] Explicit keyed client reuse and unkeyed per-build acquisition. Lifecycle tests cover two builds sharing one client and replacing the registered worker.
15
+ - [x] Full pg-boss queue creation options, excluding the adapter's name and dead-letter setup. [PostgreSQL evidence](../src/server/notifyPostgres.spec.ts) verifies notification delivery to a waiting worker and immediate live counts after completion; [type tests](../src/server/service.typecheck.test.ts) enforce option ownership.
16
+ - [x] Schema-decoded lookup by job ID and retry under the same ID for failed or retry-waiting jobs. [PostgreSQL evidence](../src/server/jobControlPostgres.spec.ts) verifies both states complete after a manual retry.
17
+ - [x] Startup reconciles declared mutable queue settings and rejects immutable policy or partition changes with a typed error. [PostgreSQL restart evidence](../src/server/queueOptionsPostgres.spec.ts) checks expiry and retry-limit changes on an existing queue.
14
18
  - [x] Queue health totals for active, failed, queued, ready and dead-lettered counts, verified with a populated fake queue.
15
19
  - [x] Public defining-module imports and an installed-package type fixture.
16
20
 
@@ -18,9 +22,11 @@ This file owns the package's implementation inventory and open API choices. The
18
22
 
19
23
  No further package API expansion is selected. Let the framework's jobs integration work identify the next package change, and preserve the existing payload and lifecycle contracts while it does. That integration's status stays in the framework roadmap.
20
24
 
25
+ ## Decisions
26
+
27
+ Enqueueing is separate from application SQL transactions. The package supplies no transactional enqueue adapter. Applications use transactions for database invariants and handle queue errors without failing those transactions. The starter enqueues after its note write transaction and logs queue failures; its [PostgreSQL queue-failure story](../../../examples/starter/src/server/queueFailure.spec.ts) proves that rejected enqueueing leaves create and edit writes saved. Its [rollback story](../../../examples/starter/src/server/committedJobs.spec.ts) also proves that an independently enqueued job survives an outer application rollback.
28
+
21
29
  ## Open questions
22
30
 
23
- - Which application boundary should choose how a database write becomes a durable job: an explicit after-commit action, an outbox, or another demonstrated approach? The enqueue API is independent of application SQL; no transaction coupling is selected.
24
31
  - Should a shared client key be checked against constructor settings and registration changes? The lifecycle fixture uses the same Layer twice; it does not settle incompatible configurations under one key.
25
- - Which public hooks need dedicated regression coverage before the guide makes stronger claims? Error-event reporting, cancellation through a job's AbortSignal, a declined send result, multi-queue health and actual cron/retry execution are implemented boundaries or engine behaviors without focused evidence here.
26
- - Should the package grow only when an application's integration needs a helper, or is a wider jobs API intended? The package has no in-repo application consumer to settle that question.
32
+ - Which public hooks need dedicated regression coverage before the guide makes stronger claims? Error-event reporting, cancellation through a job's AbortSignal, a declined send result, multi-queue health and actual cron execution are implemented boundaries or engine behaviors without focused evidence here.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/effect-pg-boss",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
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": {
@@ -43,7 +43,7 @@
43
43
  "README.md"
44
44
  ],
45
45
  "devDependencies": {
46
- "@shivaedev/quality": "0.20.0",
46
+ "@shivaedev/quality": "0.22.0",
47
47
  "@types/node": "24.19.1",
48
48
  "@typescript/native": "npm:typescript@7.0.2",
49
49
  "effect": "4.0.4",
@@ -1,16 +1,32 @@
1
- import type { ConstructorOptions, Job, Queue, QueueResult, ScheduleOptions, SendOptions, StopOptions, WorkOptions } from "pg-boss";
1
+ import type {
2
+ ConstructorOptions,
3
+ FindJobsOptions,
4
+ Job,
5
+ JobWithMetadata,
6
+ Queue,
7
+ QueueResult,
8
+ ScheduleOptions,
9
+ SendOptions,
10
+ StopOptions,
11
+ WorkOptions,
12
+ } from "pg-boss";
2
13
  import { PgBoss } from "pg-boss";
3
14
 
4
15
  export interface PgBossClient {
5
16
  readonly createQueue: (name: string, options?: Omit<Queue, "name">) => Promise<void>;
17
+ readonly findJobs?: (name: string, options?: FindJobsOptions) => Promise<readonly JobWithMetadata<unknown>[]>;
18
+ readonly getDb?: PgBoss["getDb"];
6
19
  readonly getQueue: (name: string) => Promise<QueueResult | null>;
7
20
  readonly off: (event: "error", listener: (error: Error) => void) => unknown;
8
21
  readonly offWork: (name: string) => Promise<void>;
9
22
  readonly on: (event: "error", listener: (error: Error) => void) => unknown;
23
+ readonly retry?: PgBoss["retry"];
10
24
  readonly schedule: (name: string, cron: string, data?: object | null, options?: ScheduleOptions) => Promise<void>;
11
25
  readonly send: (name: string, data?: object | null, options?: SendOptions) => Promise<string | null>;
12
26
  readonly start: () => Promise<unknown>;
13
27
  readonly stop: (options?: StopOptions) => Promise<void>;
28
+ readonly update?: PgBoss["update"];
29
+ readonly updateQueue?: PgBoss["updateQueue"];
14
30
  readonly work: (name: string, options: WorkOptions, handler: (jobs: readonly Job<unknown>[]) => Promise<unknown>) => Promise<string>;
15
31
  }
16
32
 
@@ -1,5 +1,5 @@
1
1
  import type { Effect, Schema } from "effect";
2
- import type { Job, QueueOptions, ScheduleOptions, WorkOptions } from "pg-boss";
2
+ import type { Job, Queue, ScheduleOptions, WorkOptions } from "pg-boss";
3
3
 
4
4
  export interface JobPayloadSchema extends Schema.Top {
5
5
  readonly Encoded: object;
@@ -20,7 +20,7 @@ export interface QueueDefinition<Name extends string = string, Payload extends J
20
20
  handler: (payload: Schema.Schema.Type<Payload>, job: JobContext) => Effect.Effect<unknown, E, R>,
21
21
  ) => QueueWorker<Payload, R>;
22
22
  readonly name: Name;
23
- readonly queueOptions: Omit<QueueOptions, "deadLetter">;
23
+ readonly queueOptions: Omit<Queue, "name" | "deadLetter">;
24
24
  readonly schema: Payload;
25
25
  readonly workerOptions: WorkOptions;
26
26
  }
@@ -39,7 +39,7 @@ export interface ScheduleDefinition<Name extends string = string> {
39
39
  readonly _tag: "ScheduleDefinition";
40
40
  readonly cron: string;
41
41
  readonly name: Name;
42
- readonly queueOptions: Omit<QueueOptions, "deadLetter">;
42
+ readonly queueOptions: Omit<Queue, "name" | "deadLetter">;
43
43
  readonly run: <E, R>(effect: Effect.Effect<unknown, E, R>) => ScheduledWorker<R>;
44
44
  readonly scheduleOptions: ScheduleOptions;
45
45
  readonly workerOptions: WorkOptions;
@@ -61,7 +61,7 @@ export type RegistrationRequirements<Registrations extends readonly JobRegistrat
61
61
 
62
62
  export interface DefineQueueOptions<Name extends string, Payload extends JobPayloadSchema> {
63
63
  readonly name: Name;
64
- readonly queue?: Omit<QueueOptions, "deadLetter">;
64
+ readonly queue?: Omit<Queue, "name" | "deadLetter">;
65
65
  readonly schema: Payload;
66
66
  readonly worker?: WorkOptions;
67
67
  }
@@ -88,7 +88,7 @@ export const defineQueue = <const Name extends string, const Payload extends Job
88
88
  export interface DefineScheduleOptions<Name extends string> {
89
89
  readonly cron: string;
90
90
  readonly name: Name;
91
- readonly queue?: Omit<QueueOptions, "deadLetter">;
91
+ readonly queue?: Omit<Queue, "name" | "deadLetter">;
92
92
  readonly schedule?: ScheduleOptions;
93
93
  readonly worker?: WorkOptions;
94
94
  }
@@ -1,6 +1,6 @@
1
1
  import { Data, Redacted } from "effect";
2
2
 
3
- export type PgBossOperation = "enqueue" | "health" | "register" | "start" | "stop";
3
+ export type PgBossOperation = "counts" | "enqueue" | "getJob" | "health" | "register" | "retry" | "start" | "stop";
4
4
 
5
5
  export class PgBossError extends Data.TaggedError("PgBossError")<{
6
6
  readonly operation: PgBossOperation;
@@ -8,6 +8,15 @@ export class PgBossError extends Data.TaggedError("PgBossError")<{
8
8
  readonly original: Redacted.Redacted<unknown>;
9
9
  }> {}
10
10
 
11
+ export class PgBossQueueOptionsError extends Data.TaggedError("PgBossQueueOptionsError")<{
12
+ readonly queue: string;
13
+ readonly options: readonly ("partition" | "policy")[];
14
+ }> {
15
+ override get message(): string {
16
+ return `Queue ${this.queue} cannot change options after creation: ${this.options.join(", ")}`;
17
+ }
18
+ }
19
+
11
20
  export class PgBossPayloadError extends Data.TaggedError("PgBossPayloadError")<{
12
21
  readonly direction: "decode" | "encode";
13
22
  readonly queue: string;
@@ -1,3 +1,10 @@
1
+ export interface QueueCounts {
2
+ readonly activeCount: number;
3
+ readonly failedCount: number;
4
+ readonly queuedCount: number;
5
+ readonly totalCount: number;
6
+ }
7
+
1
8
  export interface QueueHealth {
2
9
  readonly activeCount: number;
3
10
  readonly deadLetteredCount: number;
@@ -0,0 +1,33 @@
1
+ import { Effect, Schema } from "effect";
2
+ import type { PgBossClient } from "#client.ts";
3
+ import { toPgBossError } from "#error.ts";
4
+ import type { QueueCounts } from "#health.ts";
5
+
6
+ const Counts = Schema.Struct({
7
+ activeCount: Schema.Number,
8
+ failedCount: Schema.Number,
9
+ queuedCount: Schema.Number,
10
+ totalCount: Schema.Number,
11
+ });
12
+
13
+ export function countsFor(client: PgBossClient, schema: string, name: string): Effect.Effect<QueueCounts, import("#error.ts").PgBossError> {
14
+ return Effect.tryPromise({
15
+ catch: (error) => toPgBossError("counts", error, name),
16
+ try: async () => {
17
+ if (client.getDb === undefined) {
18
+ throw new TypeError("This pg-boss client does not support getDb");
19
+ }
20
+ const quotedSchema = `"${schema.replaceAll('"', '""')}"`;
21
+ const { rows } = await client.getDb().executeSql(
22
+ `SELECT
23
+ count(*) FILTER (WHERE state = 'active')::int AS "activeCount",
24
+ count(*) FILTER (WHERE state = 'failed')::int AS "failedCount",
25
+ count(*) FILTER (WHERE state IN ('created', 'retry'))::int AS "queuedCount",
26
+ count(*)::int AS "totalCount"
27
+ FROM ${quotedSchema}.job WHERE name = $1`,
28
+ [name],
29
+ );
30
+ return Schema.decodeUnknownPromise(Counts)(rows[0]);
31
+ },
32
+ });
33
+ }
@@ -0,0 +1,29 @@
1
+ import type { Queue } from "pg-boss";
2
+ import type { PgBossClient } from "#client.ts";
3
+ import { PgBossQueueOptionsError } from "#error.ts";
4
+ import { deadLetterQueueName } from "#health.ts";
5
+
6
+ export async function ensureQueue(client: PgBossClient, name: string, options: Omit<Queue, "name" | "deadLetter">): Promise<void> {
7
+ const deadLetter = deadLetterQueueName(name);
8
+ const desired = { retryBackoff: true, retryLimit: 3, ...options, deadLetter };
9
+ await client.createQueue(deadLetter);
10
+ await client.createQueue(name, desired);
11
+ const existing = await client.getQueue(name);
12
+ if (existing === null) {
13
+ return;
14
+ }
15
+ const immutable = (["partition", "policy"] as const).filter((key) => desired[key] !== undefined && desired[key] !== existing[key]);
16
+ if (immutable.length > 0) {
17
+ throw new PgBossQueueOptionsError({ options: immutable, queue: name });
18
+ }
19
+ const { partition: _partition, policy: _policy, ...mutable } = desired;
20
+ const changed = Object.entries(mutable).some(([key, value]) => value !== undefined && value !== Reflect.get(existing, key));
21
+ if (!changed) {
22
+ return;
23
+ }
24
+ if (client.updateQueue === undefined) {
25
+ throw new TypeError("This pg-boss client does not support updateQueue");
26
+ }
27
+ // pg-boss validates retryDelayMax against retryBackoff in the same update.
28
+ await client.updateQueue(name, mutable);
29
+ }
@@ -0,0 +1,46 @@
1
+ import { Effect, Option, Redacted, Schema } from "effect";
2
+ import type { PgBossClient } from "#client.ts";
3
+ import { PgBossPayloadError, toPgBossError } from "#error.ts";
4
+ import type { PgBossService } from "#service.ts";
5
+
6
+ export function getJobFor(client: PgBossClient): PgBossService["getJob"] {
7
+ return (queue, id) =>
8
+ Effect.tryPromise({
9
+ catch: (error) => toPgBossError("getJob", error, queue.name),
10
+ try: async () => {
11
+ if (client.findJobs === undefined) {
12
+ throw new TypeError("This pg-boss client does not support findJobs");
13
+ }
14
+ return (await client.findJobs(queue.name, { id }))[0];
15
+ },
16
+ }).pipe(
17
+ Effect.flatMap((job) =>
18
+ job === undefined
19
+ ? Effect.succeed(Option.none())
20
+ : Schema.decodeUnknownEffect(queue.schema)(job.data).pipe(
21
+ Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue: queue.name })),
22
+ Effect.map((data) => Option.some({ ...job, data })),
23
+ ),
24
+ ),
25
+ );
26
+ }
27
+
28
+ export function retryFor(client: PgBossClient): PgBossService["retry"] {
29
+ return (queue, id) =>
30
+ Effect.tryPromise({
31
+ catch: (error) => toPgBossError("retry", error, queue.name),
32
+ try: async () => {
33
+ if (client.findJobs === undefined || client.retry === undefined || client.update === undefined) {
34
+ throw new TypeError("This pg-boss client does not support findJobs, retry and update");
35
+ }
36
+ const job = (await client.findJobs(queue.name, { id }))[0];
37
+ if (job?.state !== "failed" && job?.state !== "retry") {
38
+ return;
39
+ }
40
+ if (job.state === "failed") {
41
+ await client.retry(queue.name, id);
42
+ }
43
+ await client.update(queue.name, undefined, { id, startAfter: 0 });
44
+ },
45
+ });
46
+ }
@@ -2,16 +2,8 @@ import { type Context, Effect, Redacted, Schema } from "effect";
2
2
  import type { Job } from "pg-boss";
3
3
  import type { PgBossClient } from "#client.ts";
4
4
  import { type JobRegistration, jobContext, type QueueDefinition, type QueueWorker, type ScheduledWorker } from "#definition.ts";
5
- import { PgBossPayloadError, toPgBossError } from "#error.ts";
6
- import { deadLetterQueueName } from "#health.ts";
7
-
8
- function queueOptions(options: Readonly<Record<string, unknown>>) {
9
- return {
10
- retryBackoff: true,
11
- retryLimit: 3,
12
- ...options,
13
- };
14
- }
5
+ import { PgBossPayloadError, PgBossQueueOptionsError, toPgBossError } from "#error.ts";
6
+ import { ensureQueue } from "#internal/ensureQueue.ts";
15
7
 
16
8
  function isQueueWorker(registration: JobRegistration): registration is QueueWorker {
17
9
  return registration._tag === "QueueWorker";
@@ -70,15 +62,10 @@ async function registerQueue(
70
62
  ): Promise<void> {
71
63
  const queue = registration._tag === "QueueWorker" ? registration.queue : registration;
72
64
  const name = queue.name;
73
- const deadLetter = deadLetterQueueName(name);
74
65
  if (replaceWorker && registration._tag === "QueueWorker") {
75
66
  await client.offWork(name);
76
67
  }
77
- await client.createQueue(deadLetter);
78
- await client.createQueue(name, {
79
- ...queueOptions(queue.queueOptions),
80
- deadLetter,
81
- });
68
+ await ensureQueue(client, name, queue.queueOptions);
82
69
  if (registration._tag === "QueueDefinition") {
83
70
  return;
84
71
  }
@@ -96,15 +83,10 @@ async function registerSchedule(
96
83
  replaceWorker: boolean,
97
84
  ): Promise<void> {
98
85
  const { schedule } = worker;
99
- const deadLetter = deadLetterQueueName(schedule.name);
100
86
  if (replaceWorker) {
101
87
  await client.offWork(schedule.name);
102
88
  }
103
- await client.createQueue(deadLetter);
104
- await client.createQueue(schedule.name, {
105
- ...queueOptions(schedule.queueOptions),
106
- deadLetter,
107
- });
89
+ await ensureQueue(client, schedule.name, schedule.queueOptions);
108
90
  await client.work(schedule.name, schedule.workerOptions, async (jobs: readonly Job<unknown>[]) => {
109
91
  for (const job of jobs) {
110
92
  await Effect.runPromise(Effect.provide(worker.effect, context), {
@@ -128,9 +110,9 @@ export const registerJobs = <R>(
128
110
  registrations: readonly JobRegistration[],
129
111
  context: Context.Context<R>,
130
112
  replaceWorkers: boolean,
131
- ): Effect.Effect<void, import("#error.ts").PgBossError> =>
113
+ ): Effect.Effect<void, import("#error.ts").PgBossError | PgBossQueueOptionsError> =>
132
114
  Effect.tryPromise({
133
- catch: (error) => toPgBossError("register", error),
115
+ catch: (error) => (error instanceof PgBossQueueOptionsError ? error : toPgBossError("register", error)),
134
116
  try: async () => {
135
117
  registrationNames(registrations);
136
118
  const provided = workerContext(context);
@@ -1,10 +1,13 @@
1
1
  import { Effect, Option, Redacted, Schema } from "effect";
2
2
  import type { PgBossClient } from "#client.ts";
3
3
  import { type PgBossError, PgBossPayloadError, toPgBossError } from "#error.ts";
4
+ import { countsFor } from "#internal/countsFor.ts";
5
+ import { healthFor } from "#internal/health.ts";
6
+ import { getJobFor, retryFor } from "#internal/jobControl.ts";
4
7
  import type { PgBossService } from "#service.ts";
5
- import { healthFor } from "./health.ts";
6
8
 
7
- export const makeService = (client: PgBossClient, names: readonly string[]): PgBossService => ({
9
+ export const makeService = (client: PgBossClient, names: readonly string[], schema = "pgboss"): PgBossService => ({
10
+ counts: (queue) => countsFor(client, schema, queue.name),
8
11
  enqueue: (queue, payload, options) =>
9
12
  Schema.encodeUnknownEffect(queue.schema)(payload).pipe(
10
13
  Effect.mapError(
@@ -31,5 +34,7 @@ export const makeService = (client: PgBossClient, names: readonly string[]): PgB
31
34
  }).pipe(Effect.map(Option.fromNullishOr));
32
35
  }),
33
36
  ),
37
+ getJob: getJobFor(client),
34
38
  health: healthFor(client, names),
39
+ retry: retryFor(client),
35
40
  });
@@ -1,20 +1,26 @@
1
1
  import { Context, Effect, Layer, type Option, type Schema } from "effect";
2
- import type { ConstructorOptions, SendOptions, StopOptions } from "pg-boss";
2
+ import type { ConstructorOptions, JobWithMetadata, SendOptions, StopOptions } from "pg-boss";
3
3
  import type { PgBossClientFactory } from "#client.ts";
4
+ import type { JobPayloadSchema, JobRegistration, QueueDefinition, RegistrationRequirements } from "#definition.ts";
5
+ import type { PgBossError, PgBossPayloadError, PgBossQueueOptionsError } from "#error.ts";
6
+ import type { JobsHealth, QueueCounts } from "#health.ts";
4
7
  import { acquireClient, releaseClient } from "#internal/lifecycle.ts";
5
8
  import { registerJobs, registrationName } from "#internal/register.ts";
6
9
  import { makeService } from "#internal/service.ts";
7
- import type { JobPayloadSchema, JobRegistration, QueueDefinition, RegistrationRequirements } from "./definition.ts";
8
- import type { PgBossError, PgBossPayloadError } from "./error.ts";
9
- import type { JobsHealth } from "./health.ts";
10
10
 
11
11
  export interface PgBossService {
12
+ readonly counts: (queue: QueueDefinition) => Effect.Effect<QueueCounts, PgBossError>;
12
13
  readonly enqueue: <const TName extends string, const TPayload extends JobPayloadSchema>(
13
14
  queue: QueueDefinition<TName, TPayload>,
14
15
  payload: Schema.Schema.Type<TPayload>,
15
16
  options?: SendOptions,
16
17
  ) => Effect.Effect<Option.Option<string>, PgBossError | PgBossPayloadError, TPayload["EncodingServices"]>;
18
+ readonly getJob: <const TName extends string, const TPayload extends JobPayloadSchema>(
19
+ queue: QueueDefinition<TName, TPayload>,
20
+ id: string,
21
+ ) => Effect.Effect<Option.Option<JobWithMetadata<TPayload["Type"]>>, PgBossError | PgBossPayloadError, TPayload["DecodingServices"]>;
17
22
  readonly health: Effect.Effect<JobsHealth, PgBossError>;
23
+ readonly retry: (queue: QueueDefinition, id: string) => Effect.Effect<void, PgBossError>;
18
24
  }
19
25
 
20
26
  export type PgBossLayerOptions<TRegistrations extends readonly JobRegistration[], TErrorRequirements> = ConstructorOptions & {
@@ -29,7 +35,7 @@ export type PgBossLayerOptions<TRegistrations extends readonly JobRegistration[]
29
35
  export interface PgBossDefinition<TIdentifier extends string = string> extends Context.Service<TIdentifier, PgBossService> {
30
36
  readonly layer: <const TRegistrations extends readonly JobRegistration[], TErrorRequirements = never>(
31
37
  options: PgBossLayerOptions<TRegistrations, TErrorRequirements>,
32
- ) => Layer.Layer<TIdentifier, PgBossError, RegistrationRequirements<TRegistrations> | TErrorRequirements>;
38
+ ) => Layer.Layer<TIdentifier, PgBossError | PgBossQueueOptionsError, RegistrationRequirements<TRegistrations> | TErrorRequirements>;
33
39
  }
34
40
 
35
41
  function logClientError(error: Error): Effect.Effect<void> {
@@ -41,7 +47,7 @@ export const makePgBoss = <const TIdentifier extends string>(identifier: TIdenti
41
47
 
42
48
  const layer = <const TRegistrations extends readonly JobRegistration[], TErrorRequirements = never>(
43
49
  options: PgBossLayerOptions<TRegistrations, TErrorRequirements>,
44
- ): Layer.Layer<TIdentifier, PgBossError, RegistrationRequirements<TRegistrations> | TErrorRequirements> => {
50
+ ): Layer.Layer<TIdentifier, PgBossError | PgBossQueueOptionsError, RegistrationRequirements<TRegistrations> | TErrorRequirements> => {
45
51
  type Requirements = RegistrationRequirements<TRegistrations> | TErrorRequirements;
46
52
  const names = options.jobs.map(registrationName);
47
53
  const { clientFactory, clientCacheKey, jobs, onError, stop, ...constructorOptions } = options;
@@ -76,7 +82,7 @@ export const makePgBoss = <const TIdentifier extends string>(identifier: TIdenti
76
82
 
77
83
  return Layer.effect(
78
84
  Service,
79
- Effect.map(acquire, ({ acquired }) => makeService(acquired.client, names)),
85
+ Effect.map(acquire, ({ acquired }) => makeService(acquired.client, names, constructorOptions.schema)),
80
86
  );
81
87
  };
82
88