@shivaedev/effect-pg-boss 0.6.1 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.1 - 2026-10-17
4
+
5
+ ### Added
6
+
7
+ - Custom `PgBossClient` factories can supply optional native `complete` and `fail` methods. Queue and schedule worker registration requires both capabilities and fails with a registration `PgBossError` when either is absent; producer-only clients do not need them.
8
+
9
+ ### Fixed
10
+
11
+ - Settle each queue and scheduled job separately through pg-boss, recording typed failures and defects on only the failed job. In 0.7.0, one failing handler failed and retried the whole fetched batch, spending unrelated jobs’ retries and rerunning successful handlers. Batches still drain with `burstWhenBatchFull`. Interruption leaves unprocessed jobs to pg-boss expiry.
12
+
13
+ ## 0.7.0 - 2026-10-17
14
+
15
+ ### Changed
16
+
17
+ - Queue and schedule workers default to native pg-boss `batchSize: 10` and `burstWhenBatchFull: true`, draining full batches immediately instead of waiting for the notification polling backstop. Native worker options still override the defaults, including batch size and local concurrency. Handlers run sequentially within each batch; pg-boss retries a rejected batch together.
18
+
19
+ ### Fixed
20
+
21
+ - `PgBossDefinition.layer` supplies its own jobs service to queue handlers and scheduled effects through the scoped Effect context. Handlers can enqueue follow-ups to worker or producer-only queues using that same client. Only the owning identifier is removed from the Layer's input requirements; other services remain typed. Startup creates every declared queue before starting consumers.
22
+
3
23
  ## 0.6.1 - 2026-10-17
4
24
 
5
25
  ### Fixed
package/README.md CHANGED
@@ -99,6 +99,23 @@ The schedule runs a payload-free Effect. This schedule registers its cron expres
99
99
 
100
100
  The Layer requires the workers' Effect services. Leaving `Mail` unprovided leaves that requirement in the resulting Effect's type. A primitive Schema such as `Schema.String` is rejected as a queue definition because the durable contract must be an object.
101
101
 
102
+ ### Backlog throughput and concurrency
103
+
104
+ Queue and schedule workers default to `batchSize: 10` and `burstWhenBatchFull: true`. pg-boss fetches again immediately after a full batch completes, until a fetch returns fewer than ten jobs. The adapter runs handlers sequentially within each batch, and pg-boss defaults `localConcurrency` to one. Set native `localConcurrency` to run multiple batches at once:
105
+
106
+ ```ts
107
+ const Compare = defineQueue({
108
+ name: "compare",
109
+ schema: Schema.Struct({ id: Schema.Number }),
110
+ queue: { notify: true },
111
+ worker: { batchSize: 2, localConcurrency: 5 },
112
+ });
113
+ ```
114
+
115
+ This worker runs up to five handlers at once. `worker` accepts pg-boss 12's `WorkOptions`, including `batchSize`, `localConcurrency`, `pollingIntervalSeconds`, `notifyPollingIntervalSeconds` and the burst options. Explicit options override the adapter defaults. pg-boss ignores `burstWhenBatchFull` at `batchSize: 1`; keep a batch size of at least two for immediate backlog draining. Each job is settled separately through pg-boss: success completes that job, and a typed failure, payload decoding failure or defect fails only that job with its own error. A failed job does not spend the retries of other jobs in its batch or rerun their successful handlers. Interruption stops the batch and leaves the interrupted and remaining jobs to pg-boss expiry; handlers must still tolerate repeated side effects across retries and interrupted attempts.
116
+
117
+ Apps do not need to shorten the polling backstop to drain a backlog. With `notify: true` and an active LISTEN/NOTIFY listener, pg-boss wakes workers on notifications and defaults to a 30-second backstop (`notifyPollingIntervalSeconds`). Without active notifications its base poll defaults to two seconds (`pollingIntervalSeconds`). Bursting takes precedence over both intervals. Override the backstop only when the application needs a different bound for work that becomes runnable without a notification, such as delayed jobs or retries. The PostgreSQL backlog tests insert 30 jobs at once and verify completion within 2.5 seconds with both defaults and configured batches and concurrency.
118
+
102
119
  ### Once per runtime: provide the workers
103
120
 
104
121
  Build the jobs Layer in `runtime.ts`:
@@ -243,6 +260,33 @@ export const producerLayer = (databaseUrl: string) =>
243
260
 
244
261
  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.
245
262
 
263
+ ### Enqueue follow-ups from a handler
264
+
265
+ A handler can yield the same `Jobs` service that owns it. The Layer supplies that service from its scoped client; other handler and Schema service requirements remain required inputs to the Layer.
266
+
267
+ ```ts
268
+ const Receipt = defineQueue({
269
+ name: "receipt",
270
+ schema: Schema.Struct({ userId: Schema.Number }),
271
+ });
272
+
273
+ const sendAndQueueReceipt = SendEmail.handle(({ userId }) =>
274
+ Effect.gen(function* () {
275
+ const mail = yield* Mail;
276
+ yield* mail.send(userId);
277
+ const jobs = yield* Jobs;
278
+ yield* jobs.enqueue(Receipt, { userId });
279
+ }),
280
+ );
281
+
282
+ const live = Jobs.layer({
283
+ connectionString: databaseUrl,
284
+ jobs: [sendAndQueueReceipt, Receipt],
285
+ }).pipe(Layer.provide(MailLive));
286
+ ```
287
+
288
+ Include every target queue in `jobs`, as either a worker or a producer-only definition. Startup creates all queues before starting consumers. The example registers `Receipt` for another process to consume. A follow-up target can also have a worker in the same Layer. Scheduled effects can yield `Jobs` too. Keep one jobs Layer in the process's native Layer graph; that Layer owns one client for enqueueing and handling. The PostgreSQL follow-up test completes a chain across two workers, enqueues to a producer-only queue and asserts one client acquisition and shutdown.
289
+
246
290
  ### API
247
291
 
248
292
  Import the module that defines the name; the package has no root entry.
@@ -265,9 +309,9 @@ The application's service has these operations:
265
309
  - `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.
266
310
  - `retry(queue, id)`: an Effect returning `void`, with `PgBossError` in its error type.
267
311
 
268
- `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`.
312
+ `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 must supply native `complete` and `fail` capabilities to register queue or schedule workers; missing settlement capabilities fail Layer acquisition with a registration `PgBossError`. Producer-only clients do not need them. Custom clients can also 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`.
269
313
 
270
- `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.
314
+ `onError` handles pg-boss client `error` events using the services captured by the Layer. The Layer's requirement type includes the workers' services and their payload Schemas' `DecodingServices`, excluding its own jobs identifier, plus the callback's services. Only the owning jobs service is supplied automatically; a handler using another jobs definition still requires that definition's Layer. `enqueue` includes the payload Schema's `EncodingServices` in its requirement type.
271
315
 
272
316
  `JobContext` has `id`, `name`, `signal`, `expireInSeconds` and `heartbeatSeconds`. `QueueHealth` has `name`, `activeCount`, `deadLetteredCount`, `failedCount`, `queuedCount` and `readyCount`. `JobsHealth` has `jobs` and the corresponding `activeTotal`, `deadLetteredTotal`, `failedTotal`, `queuedTotal` and `readyTotal` fields.
273
317
 
@@ -1,7 +1,9 @@
1
1
  import type { ConstructorOptions, FindJobsOptions, Job, JobWithMetadata, Queue, QueueResult, ScheduleOptions, SendOptions, StopOptions, WorkOptions } from "pg-boss";
2
2
  import { PgBoss } from "pg-boss";
3
3
  export interface PgBossClient {
4
+ readonly complete?: PgBoss["complete"];
4
5
  readonly createQueue: (name: string, options?: Omit<Queue, "name">) => Promise<void>;
6
+ readonly fail?: PgBoss["fail"];
5
7
  readonly findJobs?: (name: string, options?: FindJobsOptions) => Promise<readonly JobWithMetadata<unknown>[]>;
6
8
  readonly getDb?: PgBoss["getDb"];
7
9
  readonly getQueue: (name: string) => Promise<QueueResult | null>;
@@ -1 +1 @@
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
+ {"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,QAAQ,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IACvC,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,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IAC/B,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":"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
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/server/client.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAwBjC,MAAM,CAAC,MAAM,oBAAoB,GAAwB,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC"}
@@ -9,7 +9,7 @@ export const defineQueue = (options) => {
9
9
  name: options.name,
10
10
  queueOptions: Object.freeze({ ...options.queue }),
11
11
  schema: options.schema,
12
- workerOptions: Object.freeze({ batchSize: 1, ...options.worker }),
12
+ workerOptions: Object.freeze({ batchSize: 10, burstWhenBatchFull: true, ...options.worker }),
13
13
  };
14
14
  return Object.freeze(definition);
15
15
  };
@@ -25,7 +25,7 @@ export const defineSchedule = (options) => {
25
25
  schedule: definition,
26
26
  }),
27
27
  scheduleOptions: Object.freeze({ tz: "UTC", ...options.schedule }),
28
- workerOptions: Object.freeze({ batchSize: 1, ...options.worker }),
28
+ workerOptions: Object.freeze({ batchSize: 10, burstWhenBatchFull: true, ...options.worker }),
29
29
  };
30
30
  return Object.freeze(definition);
31
31
  };
@@ -1 +1 @@
1
- {"version":3,"file":"definition.js","sourceRoot":"","sources":["../../src/server/definition.ts"],"names":[],"mappings":"AAoEA,MAAM,CAAC,MAAM,WAAW,GAAG,CAC1B,OAA0C,EACT,EAAE;IACnC,MAAM,UAAU,GAAmC;QAClD,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CACnB,MAAM,CAAC,MAAM,CAAC;YACb,IAAI,EAAE,aAAsB;YAC5B,OAAO;YACP,KAAK,EAAE,UAAU;SACjB,CAAC;QACH,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;QACjD,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;KACjE,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAClC,CAAC,CAAC;AAUF,MAAM,CAAC,MAAM,cAAc,GAAG,CAA4B,OAAoC,EAA4B,EAAE;IAC3H,MAAM,UAAU,GAA6B;QAC5C,IAAI,EAAE,oBAAoB;QAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;QACjD,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,CACf,MAAM,CAAC,MAAM,CAAC;YACb,IAAI,EAAE,iBAA0B;YAChC,MAAM;YACN,QAAQ,EAAE,UAAU;SACpB,CAAC;QACH,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QAClE,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;KACjE,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAClC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAiB,EAAc,EAAE,CAAC,CAAC;IAC7D,eAAe,EAAE,GAAG,CAAC,eAAe;IACpC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;IACtC,EAAE,EAAE,GAAG,CAAC,EAAE;IACV,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,MAAM,EAAE,GAAG,CAAC,MAAM;CAClB,CAAC,CAAC"}
1
+ {"version":3,"file":"definition.js","sourceRoot":"","sources":["../../src/server/definition.ts"],"names":[],"mappings":"AAoEA,MAAM,CAAC,MAAM,WAAW,GAAG,CAC1B,OAA0C,EACT,EAAE;IACnC,MAAM,UAAU,GAAmC;QAClD,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CACnB,MAAM,CAAC,MAAM,CAAC;YACb,IAAI,EAAE,aAAsB;YAC5B,OAAO;YACP,KAAK,EAAE,UAAU;SACjB,CAAC;QACH,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;QACjD,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;KAC5F,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAClC,CAAC,CAAC;AAUF,MAAM,CAAC,MAAM,cAAc,GAAG,CAA4B,OAAoC,EAA4B,EAAE;IAC3H,MAAM,UAAU,GAA6B;QAC5C,IAAI,EAAE,oBAAoB;QAC1B,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;QACjD,GAAG,EAAE,CAAC,MAAM,EAAE,EAAE,CACf,MAAM,CAAC,MAAM,CAAC;YACb,IAAI,EAAE,iBAA0B;YAChC,MAAM;YACN,QAAQ,EAAE,UAAU;SACpB,CAAC;QACH,eAAe,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;QAClE,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,kBAAkB,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;KAC5F,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;AAClC,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAiB,EAAc,EAAE,CAAC,CAAC;IAC7D,eAAe,EAAE,GAAG,CAAC,eAAe;IACpC,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;IACtC,EAAE,EAAE,GAAG,CAAC,EAAE;IACV,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,MAAM,EAAE,GAAG,CAAC,MAAM;CAClB,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Effect } from "effect";
2
+ import type { Job } from "pg-boss";
3
+ import type { PgBossClient } from "#client.ts";
4
+ export declare function batchHandler(client: PgBossClient, name: string, run: (job: Job<unknown>) => Effect.Effect<unknown, unknown>): (jobs: readonly Job<unknown>[]) => Promise<void>;
5
+ //# sourceMappingURL=batchHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batchHandler.d.ts","sourceRoot":"","sources":["../../../src/server/internal/batchHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAQ,MAAM,QAAQ,CAAC;AAC7C,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAO/C,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,UAMvG,SAAS,GAAG,CAAC,OAAO,CAAC,EAAE,KAAG,OAAO,CAAC,IAAI,CAAC,CAiB3D"}
@@ -0,0 +1,28 @@
1
+ import { Cause, Effect, Exit } from "effect";
2
+ function failureOutput(cause) {
3
+ const error = Cause.squash(cause);
4
+ return typeof error === "object" && error !== null ? error : { message: String(error) };
5
+ }
6
+ export function batchHandler(client, name, run) {
7
+ const complete = client.complete?.bind(client);
8
+ const fail = client.fail?.bind(client);
9
+ if (complete === undefined || fail === undefined) {
10
+ throw new TypeError("This pg-boss client does not support complete and fail");
11
+ }
12
+ return async (jobs) => {
13
+ for (const job of jobs) {
14
+ const exit = await Effect.runPromiseExit(Effect.suspend(() => run(job)), { signal: job.signal });
15
+ if (job.signal.aborted || (Exit.isFailure(exit) && Cause.hasInterrupts(exit.cause))) {
16
+ // Returning would let pg-boss complete the unprocessed jobs; its expiry owns them instead.
17
+ return new Promise(() => undefined);
18
+ }
19
+ if (Exit.isSuccess(exit)) {
20
+ await complete(name, job);
21
+ }
22
+ else {
23
+ await fail(name, job, failureOutput(exit.cause));
24
+ }
25
+ }
26
+ };
27
+ }
28
+ //# sourceMappingURL=batchHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batchHandler.js","sourceRoot":"","sources":["../../../src/server/internal/batchHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAI7C,SAAS,aAAa,CAAC,KAA2B;IACjD,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AACzF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAoB,EAAE,IAAY,EAAE,GAA2D;IAC3H,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,QAAQ,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QAClD,MAAM,IAAI,SAAS,CAAC,wDAAwD,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,KAAK,EAAE,IAA6B,EAAiB,EAAE;QAC7D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CACvC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAC9B,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CACtB,CAAC;YACF,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACrF,2FAA2F;gBAC3F,OAAO,IAAI,OAAO,CAAQ,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;YAC5C,CAAC;YACD,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1B,MAAM,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;YAC3B,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;YAClD,CAAC;QACF,CAAC;IACF,CAAC,CAAC;AACH,CAAC"}
@@ -2,7 +2,7 @@ import { type Context, Effect } from "effect";
2
2
  import type { PgBossClient } from "#client.ts";
3
3
  import { type JobRegistration } from "#definition.ts";
4
4
  import { PgBossQueueOptionsError } from "#error.ts";
5
- export declare const registrationName: (registration: JobRegistration) => string;
5
+ export declare function registrationName(registration: JobRegistration): string;
6
6
  export declare const registrationNames: (registrations: readonly JobRegistration[]) => readonly string[];
7
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>;
8
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;AAChI,OAAO,EAAsB,uBAAuB,EAAiB,MAAM,WAAW,CAAC;AAgBvF,eAAO,MAAM,gBAAgB,iBAAkB,eAAe,KAAG,MAWhE,CAAC;AAsEF,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
+ {"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,EACN,KAAK,eAAe,EAMpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAsB,uBAAuB,EAAiB,MAAM,WAAW,CAAC;AA8BvF,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,eAAe,GAAG,MAAM,CAEtE;AA2DD,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,CAe7E,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { Effect, Redacted, Schema } from "effect";
2
- import { jobContext } from "#definition.ts";
2
+ import { jobContext, } from "#definition.ts";
3
3
  import { PgBossPayloadError, PgBossQueueOptionsError, toPgBossError } from "#error.ts";
4
+ import { batchHandler } from "#internal/batchHandler.ts";
4
5
  import { ensureQueue } from "#internal/ensureQueue.ts";
5
6
  import { payloadOf, traceJob } from "#internal/tracing.ts";
6
7
  function isQueueWorker(registration) {
@@ -12,57 +13,53 @@ function isScheduledWorker(registration) {
12
13
  function isQueueDefinition(registration) {
13
14
  return registration._tag === "QueueDefinition";
14
15
  }
15
- export const registrationName = (registration) => {
16
+ function registrationDefinition(registration) {
16
17
  if (isQueueDefinition(registration)) {
17
- return registration.name;
18
+ return registration;
18
19
  }
19
20
  if (isQueueWorker(registration)) {
20
- return registration.queue.name;
21
+ return registration.queue;
21
22
  }
22
23
  if (isScheduledWorker(registration)) {
23
- return registration.schedule.name;
24
+ return registration.schedule;
24
25
  }
25
26
  throw new TypeError(`Unknown pg-boss registration: ${registration._tag}`);
26
- };
27
+ }
28
+ export function registrationName(registration) {
29
+ return registrationDefinition(registration).name;
30
+ }
31
+ async function prepareQueues(client, registrations, replaceWorkers) {
32
+ for (const registration of registrations) {
33
+ if (replaceWorkers && !isQueueDefinition(registration)) {
34
+ await client.offWork(registrationName(registration));
35
+ }
36
+ }
37
+ for (const registration of registrations) {
38
+ const definition = registrationDefinition(registration);
39
+ await ensureQueue(client, definition.name, definition.queueOptions);
40
+ }
41
+ }
27
42
  function workerContext(context) {
28
43
  return context;
29
44
  }
30
45
  function runQueueWorker(worker, job, context) {
31
- return Effect.runPromise(Schema.decodeUnknownEffect(worker.queue.schema)(payloadOf(job.data)).pipe(Effect.mapError((error) => new PgBossPayloadError({
46
+ return Schema.decodeUnknownEffect(worker.queue.schema)(payloadOf(job.data)).pipe(Effect.mapError((error) => new PgBossPayloadError({
32
47
  direction: "decode",
33
48
  original: Redacted.make(error),
34
49
  queue: worker.queue.name,
35
- })), Effect.flatMap((payload) => worker.handler(payload, jobContext(job))), (effect) => traceJob(effect, job, worker.queue.name), Effect.provide(context)), { signal: job.signal });
50
+ })), Effect.flatMap((payload) => worker.handler(payload, jobContext(job))), (effect) => traceJob(effect, job, worker.queue.name), Effect.provide(context));
36
51
  }
37
- async function registerQueue(client, registration, context, replaceWorker) {
52
+ async function registerQueue(client, registration, context) {
38
53
  const queue = registration._tag === "QueueWorker" ? registration.queue : registration;
39
54
  const name = queue.name;
40
- if (replaceWorker && registration._tag === "QueueWorker") {
41
- await client.offWork(name);
42
- }
43
- await ensureQueue(client, name, queue.queueOptions);
44
55
  if (registration._tag === "QueueDefinition") {
45
56
  return;
46
57
  }
47
- await client.work(name, queue.workerOptions, async (jobs) => {
48
- for (const job of jobs) {
49
- await runQueueWorker(registration, job, context);
50
- }
51
- });
58
+ await client.work(name, queue.workerOptions, batchHandler(client, name, (job) => runQueueWorker(registration, job, context)));
52
59
  }
53
- async function registerSchedule(client, worker, context, replaceWorker) {
60
+ async function registerSchedule(client, worker, context) {
54
61
  const { schedule } = worker;
55
- if (replaceWorker) {
56
- await client.offWork(schedule.name);
57
- }
58
- await ensureQueue(client, schedule.name, schedule.queueOptions);
59
- await client.work(schedule.name, schedule.workerOptions, async (jobs) => {
60
- for (const job of jobs) {
61
- await Effect.runPromise(Effect.provide(traceJob(worker.effect, job, schedule.name), context), {
62
- signal: job.signal,
63
- });
64
- }
65
- });
62
+ await client.work(schedule.name, schedule.workerOptions, batchHandler(client, schedule.name, (job) => Effect.provide(traceJob(worker.effect, job, schedule.name), context)));
66
63
  await client.schedule(schedule.name, schedule.cron, null, schedule.scheduleOptions);
67
64
  }
68
65
  export const registrationNames = (registrations) => {
@@ -76,13 +73,14 @@ export const registerJobs = (client, registrations, context, replaceWorkers) =>
76
73
  catch: (error) => (error instanceof PgBossQueueOptionsError ? error : toPgBossError("register", error)),
77
74
  try: async () => {
78
75
  registrationNames(registrations);
76
+ await prepareQueues(client, registrations, replaceWorkers);
79
77
  const provided = workerContext(context);
80
78
  for (const registration of registrations) {
81
79
  if (isQueueWorker(registration) || isQueueDefinition(registration)) {
82
- await registerQueue(client, registration, provided, replaceWorkers);
80
+ await registerQueue(client, registration, provided);
83
81
  }
84
82
  else if (isScheduledWorker(registration)) {
85
- await registerSchedule(client, registration, provided, replaceWorkers);
83
+ await registerSchedule(client, registration, provided);
86
84
  }
87
85
  }
88
86
  },
@@ -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":"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"}
@@ -19,7 +19,7 @@ export type PgBossLayerOptions<TRegistrations extends readonly JobRegistration[]
19
19
  readonly stop?: StopOptions;
20
20
  };
21
21
  export interface PgBossDefinition<TIdentifier extends string = string> extends Context.Service<TIdentifier, PgBossService> {
22
- readonly layer: <const TRegistrations extends readonly JobRegistration[], TErrorRequirements = never>(options: PgBossLayerOptions<TRegistrations, TErrorRequirements>) => Layer.Layer<TIdentifier, PgBossError | PgBossQueueOptionsError, RegistrationRequirements<TRegistrations> | TErrorRequirements>;
22
+ readonly layer: <const TRegistrations extends readonly JobRegistration[], TErrorRequirements = never>(options: PgBossLayerOptions<TRegistrations, TErrorRequirements>) => Layer.Layer<TIdentifier, PgBossError | PgBossQueueOptionsError, Exclude<RegistrationRequirements<TRegistrations>, TIdentifier> | TErrorRequirements>;
23
23
  }
24
24
  export declare const makePgBoss: <const TIdentifier extends string>(identifier: TIdentifier) => PgBossDefinition<TIdentifier>;
25
25
  //# sourceMappingURL=service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/server/service.ts"],"names":[],"mappings":"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"}
@@ -11,19 +11,21 @@ export const makePgBoss = (identifier) => {
11
11
  const names = options.jobs.map(registrationName);
12
12
  const { clientFactory, clientCacheKey, jobs, onError, stop, ...constructorOptions } = options;
13
13
  const acquire = Effect.acquireRelease(Effect.gen(function* () {
14
- const context = yield* Effect.context();
14
+ const dependencies = yield* Effect.context();
15
15
  const acquired = yield* acquireClient({
16
16
  clientCacheKey,
17
17
  clientFactory,
18
18
  constructor: constructorOptions,
19
19
  });
20
+ const service = makeService(acquired.client, names, constructorOptions.schema);
21
+ const context = Context.add(dependencies, Service, service);
20
22
  const reportError = onError ?? logClientError;
21
23
  const errorListener = (error) => {
22
24
  void Effect.runPromise(Effect.exit(Effect.provide(reportError(error), context)));
23
25
  };
24
26
  acquired.client.on("error", errorListener);
25
27
  const registration = registerJobs(acquired.client, jobs, context, acquired.reused);
26
- return yield* registration.pipe(Effect.as({ acquired, context, errorListener }), Effect.onError(() => {
28
+ return yield* registration.pipe(Effect.as({ acquired, errorListener, service }), Effect.onError(() => {
27
29
  acquired.client.off("error", errorListener);
28
30
  return releaseClient(acquired, stop);
29
31
  }));
@@ -31,7 +33,7 @@ export const makePgBoss = (identifier) => {
31
33
  resource.acquired.client.off("error", resource.errorListener);
32
34
  return releaseClient(resource.acquired, stop);
33
35
  });
34
- return Layer.effect(Service, Effect.map(acquire, ({ acquired }) => makeService(acquired.client, names, constructorOptions.schema)));
36
+ return Layer.effect(Service, Effect.map(acquire, ({ service }) => service));
35
37
  };
36
38
  return Object.assign(Service, { layer });
37
39
  };
@@ -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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"}
package/docs/roadmap.md CHANGED
@@ -9,6 +9,8 @@ This file owns the package's implementation inventory and open API choices. The
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
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.
12
+ - [x] Native pg-boss burst defaults (`batchSize: 10`, `burstWhenBatchFull: true`) and configurable batches and local concurrency. [PostgreSQL backlog evidence](../src/server/throughputPostgres.spec.ts) drains 30 jobs within 2.5 seconds.
13
+ - [x] Handlers and scheduled effects can yield their owning jobs service without an external self requirement. [PostgreSQL follow-up evidence](../src/server/followUpPostgres.spec.ts) completes a worker chain and enqueues to a producer-only queue using one scoped client. All declared queues exist before consumers start.
12
14
  - [x] Worker and scheduled Effect service capture. Runtime and packed-consumer type tests preserve handler requirements.
13
15
  - [x] Scoped startup and shutdown, including cleanup when startup or registration fails.
14
16
  - [x] Explicit keyed client reuse and unkeyed per-build acquisition. Lifecycle tests cover two builds sharing one client and replacing the registered worker.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/effect-pg-boss",
3
- "version": "0.6.1",
3
+ "version": "0.7.1",
4
4
  "description": "Effect-native jobs and lifecycle management for pg-boss",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-pg-boss#readme",
6
6
  "bugs": {
@@ -13,7 +13,9 @@ import type {
13
13
  import { PgBoss } from "pg-boss";
14
14
 
15
15
  export interface PgBossClient {
16
+ readonly complete?: PgBoss["complete"];
16
17
  readonly createQueue: (name: string, options?: Omit<Queue, "name">) => Promise<void>;
18
+ readonly fail?: PgBoss["fail"];
17
19
  readonly findJobs?: (name: string, options?: FindJobsOptions) => Promise<readonly JobWithMetadata<unknown>[]>;
18
20
  readonly getDb?: PgBoss["getDb"];
19
21
  readonly getQueue: (name: string) => Promise<QueueResult | null>;
@@ -80,7 +80,7 @@ export const defineQueue = <const Name extends string, const Payload extends Job
80
80
  name: options.name,
81
81
  queueOptions: Object.freeze({ ...options.queue }),
82
82
  schema: options.schema,
83
- workerOptions: Object.freeze({ batchSize: 1, ...options.worker }),
83
+ workerOptions: Object.freeze({ batchSize: 10, burstWhenBatchFull: true, ...options.worker }),
84
84
  };
85
85
  return Object.freeze(definition);
86
86
  };
@@ -106,7 +106,7 @@ export const defineSchedule = <const Name extends string>(options: DefineSchedul
106
106
  schedule: definition,
107
107
  }),
108
108
  scheduleOptions: Object.freeze({ tz: "UTC", ...options.schedule }),
109
- workerOptions: Object.freeze({ batchSize: 1, ...options.worker }),
109
+ workerOptions: Object.freeze({ batchSize: 10, burstWhenBatchFull: true, ...options.worker }),
110
110
  };
111
111
  return Object.freeze(definition);
112
112
  };
@@ -0,0 +1,33 @@
1
+ import { Cause, Effect, Exit } from "effect";
2
+ import type { Job } from "pg-boss";
3
+ import type { PgBossClient } from "#client.ts";
4
+
5
+ function failureOutput(cause: Cause.Cause<unknown>): object {
6
+ const error = Cause.squash(cause);
7
+ return typeof error === "object" && error !== null ? error : { message: String(error) };
8
+ }
9
+
10
+ export function batchHandler(client: PgBossClient, name: string, run: (job: Job<unknown>) => Effect.Effect<unknown, unknown>) {
11
+ const complete = client.complete?.bind(client);
12
+ const fail = client.fail?.bind(client);
13
+ if (complete === undefined || fail === undefined) {
14
+ throw new TypeError("This pg-boss client does not support complete and fail");
15
+ }
16
+ return async (jobs: readonly Job<unknown>[]): Promise<void> => {
17
+ for (const job of jobs) {
18
+ const exit = await Effect.runPromiseExit(
19
+ Effect.suspend(() => run(job)),
20
+ { signal: job.signal },
21
+ );
22
+ if (job.signal.aborted || (Exit.isFailure(exit) && Cause.hasInterrupts(exit.cause))) {
23
+ // Returning would let pg-boss complete the unprocessed jobs; its expiry owns them instead.
24
+ return new Promise<never>(() => undefined);
25
+ }
26
+ if (Exit.isSuccess(exit)) {
27
+ await complete(name, job);
28
+ } else {
29
+ await fail(name, job, failureOutput(exit.cause));
30
+ }
31
+ }
32
+ };
33
+ }
@@ -1,8 +1,16 @@
1
1
  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
- import { type JobRegistration, jobContext, type QueueDefinition, type QueueWorker, type ScheduledWorker } from "#definition.ts";
4
+ import {
5
+ type JobRegistration,
6
+ jobContext,
7
+ type QueueDefinition,
8
+ type QueueWorker,
9
+ type ScheduleDefinition,
10
+ type ScheduledWorker,
11
+ } from "#definition.ts";
5
12
  import { PgBossPayloadError, PgBossQueueOptionsError, toPgBossError } from "#error.ts";
13
+ import { batchHandler } from "#internal/batchHandler.ts";
6
14
  import { ensureQueue } from "#internal/ensureQueue.ts";
7
15
  import { payloadOf, traceJob } from "#internal/tracing.ts";
8
16
 
@@ -18,18 +26,34 @@ function isQueueDefinition(registration: JobRegistration): registration is Queue
18
26
  return registration._tag === "QueueDefinition";
19
27
  }
20
28
 
21
- export const registrationName = (registration: JobRegistration): string => {
29
+ function registrationDefinition(registration: JobRegistration): QueueDefinition | ScheduleDefinition {
22
30
  if (isQueueDefinition(registration)) {
23
- return registration.name;
31
+ return registration;
24
32
  }
25
33
  if (isQueueWorker(registration)) {
26
- return registration.queue.name;
34
+ return registration.queue;
27
35
  }
28
36
  if (isScheduledWorker(registration)) {
29
- return registration.schedule.name;
37
+ return registration.schedule;
30
38
  }
31
39
  throw new TypeError(`Unknown pg-boss registration: ${registration._tag}`);
32
- };
40
+ }
41
+
42
+ export function registrationName(registration: JobRegistration): string {
43
+ return registrationDefinition(registration).name;
44
+ }
45
+
46
+ async function prepareQueues(client: PgBossClient, registrations: readonly JobRegistration[], replaceWorkers: boolean): Promise<void> {
47
+ for (const registration of registrations) {
48
+ if (replaceWorkers && !isQueueDefinition(registration)) {
49
+ await client.offWork(registrationName(registration));
50
+ }
51
+ }
52
+ for (const registration of registrations) {
53
+ const definition = registrationDefinition(registration);
54
+ await ensureQueue(client, definition.name, definition.queueOptions);
55
+ }
56
+ }
33
57
 
34
58
  // The layer requires RegistrationRequirements of its jobs, so its context provides every registered worker.
35
59
  function workerContext<R>(context: Context.Context<R>): Context.Context<unknown>;
@@ -37,65 +61,42 @@ function workerContext(context: unknown): unknown {
37
61
  return context;
38
62
  }
39
63
 
40
- function runQueueWorker(worker: QueueWorker, job: Job<unknown>, context: Context.Context<unknown>): Promise<unknown> {
41
- return Effect.runPromise(
42
- Schema.decodeUnknownEffect(worker.queue.schema)(payloadOf(job.data)).pipe(
43
- Effect.mapError(
44
- (error) =>
45
- new PgBossPayloadError({
46
- direction: "decode",
47
- original: Redacted.make(error),
48
- queue: worker.queue.name,
49
- }),
50
- ),
51
- Effect.flatMap((payload) => worker.handler(payload, jobContext(job))),
52
- (effect) => traceJob(effect, job, worker.queue.name),
53
- Effect.provide(context),
64
+ function runQueueWorker(worker: QueueWorker, job: Job<unknown>, context: Context.Context<unknown>) {
65
+ return Schema.decodeUnknownEffect(worker.queue.schema)(payloadOf(job.data)).pipe(
66
+ Effect.mapError(
67
+ (error) =>
68
+ new PgBossPayloadError({
69
+ direction: "decode",
70
+ original: Redacted.make(error),
71
+ queue: worker.queue.name,
72
+ }),
54
73
  ),
55
- { signal: job.signal },
74
+ Effect.flatMap((payload) => worker.handler(payload, jobContext(job))),
75
+ (effect) => traceJob(effect, job, worker.queue.name),
76
+ Effect.provide(context),
56
77
  );
57
78
  }
58
79
 
59
- async function registerQueue(
60
- client: PgBossClient,
61
- registration: QueueWorker | QueueDefinition,
62
- context: Context.Context<unknown>,
63
- replaceWorker: boolean,
64
- ): Promise<void> {
80
+ async function registerQueue(client: PgBossClient, registration: QueueWorker | QueueDefinition, context: Context.Context<unknown>): Promise<void> {
65
81
  const queue = registration._tag === "QueueWorker" ? registration.queue : registration;
66
82
  const name = queue.name;
67
- if (replaceWorker && registration._tag === "QueueWorker") {
68
- await client.offWork(name);
69
- }
70
- await ensureQueue(client, name, queue.queueOptions);
71
83
  if (registration._tag === "QueueDefinition") {
72
84
  return;
73
85
  }
74
- await client.work(name, queue.workerOptions, async (jobs) => {
75
- for (const job of jobs) {
76
- await runQueueWorker(registration, job, context);
77
- }
78
- });
86
+ await client.work(
87
+ name,
88
+ queue.workerOptions,
89
+ batchHandler(client, name, (job) => runQueueWorker(registration, job, context)),
90
+ );
79
91
  }
80
92
 
81
- async function registerSchedule(
82
- client: PgBossClient,
83
- worker: ScheduledWorker,
84
- context: Context.Context<unknown>,
85
- replaceWorker: boolean,
86
- ): Promise<void> {
93
+ async function registerSchedule(client: PgBossClient, worker: ScheduledWorker, context: Context.Context<unknown>): Promise<void> {
87
94
  const { schedule } = worker;
88
- if (replaceWorker) {
89
- await client.offWork(schedule.name);
90
- }
91
- await ensureQueue(client, schedule.name, schedule.queueOptions);
92
- await client.work(schedule.name, schedule.workerOptions, async (jobs: readonly Job<unknown>[]) => {
93
- for (const job of jobs) {
94
- await Effect.runPromise(Effect.provide(traceJob(worker.effect, job, schedule.name), context), {
95
- signal: job.signal,
96
- });
97
- }
98
- });
95
+ await client.work(
96
+ schedule.name,
97
+ schedule.workerOptions,
98
+ batchHandler(client, schedule.name, (job) => Effect.provide(traceJob(worker.effect, job, schedule.name), context)),
99
+ );
99
100
  await client.schedule(schedule.name, schedule.cron, null, schedule.scheduleOptions);
100
101
  }
101
102
 
@@ -117,12 +118,13 @@ export const registerJobs = <R>(
117
118
  catch: (error) => (error instanceof PgBossQueueOptionsError ? error : toPgBossError("register", error)),
118
119
  try: async () => {
119
120
  registrationNames(registrations);
121
+ await prepareQueues(client, registrations, replaceWorkers);
120
122
  const provided = workerContext(context);
121
123
  for (const registration of registrations) {
122
124
  if (isQueueWorker(registration) || isQueueDefinition(registration)) {
123
- await registerQueue(client, registration, provided, replaceWorkers);
125
+ await registerQueue(client, registration, provided);
124
126
  } else if (isScheduledWorker(registration)) {
125
- await registerSchedule(client, registration, provided, replaceWorkers);
127
+ await registerSchedule(client, registration, provided);
126
128
  }
127
129
  }
128
130
  },
@@ -35,7 +35,11 @@ export type PgBossLayerOptions<TRegistrations extends readonly JobRegistration[]
35
35
  export interface PgBossDefinition<TIdentifier extends string = string> extends Context.Service<TIdentifier, PgBossService> {
36
36
  readonly layer: <const TRegistrations extends readonly JobRegistration[], TErrorRequirements = never>(
37
37
  options: PgBossLayerOptions<TRegistrations, TErrorRequirements>,
38
- ) => Layer.Layer<TIdentifier, PgBossError | PgBossQueueOptionsError, RegistrationRequirements<TRegistrations> | TErrorRequirements>;
38
+ ) => Layer.Layer<
39
+ TIdentifier,
40
+ PgBossError | PgBossQueueOptionsError,
41
+ Exclude<RegistrationRequirements<TRegistrations>, TIdentifier> | TErrorRequirements
42
+ >;
39
43
  }
40
44
 
41
45
  function logClientError(error: Error): Effect.Effect<void> {
@@ -47,27 +51,33 @@ export const makePgBoss = <const TIdentifier extends string>(identifier: TIdenti
47
51
 
48
52
  const layer = <const TRegistrations extends readonly JobRegistration[], TErrorRequirements = never>(
49
53
  options: PgBossLayerOptions<TRegistrations, TErrorRequirements>,
50
- ): Layer.Layer<TIdentifier, PgBossError | PgBossQueueOptionsError, RegistrationRequirements<TRegistrations> | TErrorRequirements> => {
51
- type Requirements = RegistrationRequirements<TRegistrations> | TErrorRequirements;
54
+ ): Layer.Layer<
55
+ TIdentifier,
56
+ PgBossError | PgBossQueueOptionsError,
57
+ Exclude<RegistrationRequirements<TRegistrations>, TIdentifier> | TErrorRequirements
58
+ > => {
59
+ type Requirements = Exclude<RegistrationRequirements<TRegistrations>, TIdentifier> | TErrorRequirements;
52
60
  const names = options.jobs.map(registrationName);
53
61
  const { clientFactory, clientCacheKey, jobs, onError, stop, ...constructorOptions } = options;
54
62
 
55
63
  const acquire = Effect.acquireRelease(
56
64
  Effect.gen(function* () {
57
- const context = yield* Effect.context<Requirements>();
65
+ const dependencies = yield* Effect.context<Requirements>();
58
66
  const acquired = yield* acquireClient({
59
67
  clientCacheKey,
60
68
  clientFactory,
61
69
  constructor: constructorOptions,
62
70
  });
63
- const reportError: (error: Error) => Effect.Effect<unknown, never, Requirements> = onError ?? logClientError;
71
+ const service = makeService(acquired.client, names, constructorOptions.schema);
72
+ const context = Context.add(dependencies, Service, service);
73
+ const reportError: (error: Error) => Effect.Effect<unknown, never, Requirements | TIdentifier> = onError ?? logClientError;
64
74
  const errorListener = (error: Error) => {
65
75
  void Effect.runPromise(Effect.exit(Effect.provide(reportError(error), context)));
66
76
  };
67
77
  acquired.client.on("error", errorListener);
68
78
  const registration = registerJobs(acquired.client, jobs, context, acquired.reused);
69
79
  return yield* registration.pipe(
70
- Effect.as({ acquired, context, errorListener }),
80
+ Effect.as({ acquired, errorListener, service }),
71
81
  Effect.onError(() => {
72
82
  acquired.client.off("error", errorListener);
73
83
  return releaseClient(acquired, stop);
@@ -82,7 +92,7 @@ export const makePgBoss = <const TIdentifier extends string>(identifier: TIdenti
82
92
 
83
93
  return Layer.effect(
84
94
  Service,
85
- Effect.map(acquire, ({ acquired }) => makeService(acquired.client, names, constructorOptions.schema)),
95
+ Effect.map(acquire, ({ service }) => service),
86
96
  );
87
97
  };
88
98