@shivaedev/effect-pg-boss 0.6.0 → 0.7.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.0 - 2026-10-17
4
+
5
+ ### Changed
6
+
7
+ - 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.
8
+
9
+ ### Fixed
10
+
11
+ - `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.
12
+
13
+ ## 0.6.1 - 2026-10-17
14
+
15
+ ### Fixed
16
+
17
+ - Run each queue and scheduled job attempt inside a root consumer span named for its queue, with job identity, attempt and retry-count attributes and handler failures. Handler steps share that job trace.
18
+ - Persist the enqueueing Effect span context in pg-boss job data and link the job span to it. Handlers and `getJob` still decode the original payload Schema; direct pg-boss data readers see an envelope for traced sends.
19
+
3
20
  ## 0.6.0 - 2026-10-17
4
21
 
5
22
  ### Added
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. A failed handler rejects its batch, so pg-boss can retry earlier jobs in that batch; handlers must tolerate repeated side effects.
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`:
@@ -154,6 +171,14 @@ Provide `Jobs` through the application's existing runtime. `enqueue` takes the d
154
171
 
155
172
  `PgBossPayloadError` names a payload boundary failure; malformed durable input is rejected before the worker's domain code runs. The PostgreSQL test also checks that invalid data sent directly to pg-boss reaches the dead-letter queue without reaching the handler.
156
173
 
174
+ ### Trace jobs
175
+
176
+ Each queue or scheduled job attempt runs in one root consumer span named for its queue. The span encloses payload decoding and the whole handler, so top-level `Effect.fn` steps are children of the job span. Its attributes include `job.id`, `job.queue`, `job.name`, the one-based `job.attempt` and pg-boss's zero-based `job.retry_count`. A failed handler ends the span with its failure.
177
+
178
+ `enqueue` captures the current Effect span, including an external parent span, when present. It stores that context in a typed envelope in pg-boss's existing job `data`; the adapter unwraps the envelope before Schema decoding in the handler and `getJob`, so the application's payload Schema stays unchanged. Jobs sent without a span keep their ordinary encoded payload, and workers also accept those unwrapped jobs. Direct pg-boss data readers see the envelope for traced sends.
179
+
180
+ The consumer span links to the sender rather than sharing its parent trace, following OpenTelemetry messaging conventions for asynchronous processing. Each retry gets its own job trace. Provide the application's Effect tracer when building the worker Layer; the worker uses that captured tracer. The PostgreSQL tracing tests use Effect's in-memory tracer and a producer that shuts down before its worker starts; the scheduled-worker test checks the same span boundary with a fake client.
181
+
157
182
  ### Read health
158
183
 
159
184
  ```ts
@@ -235,6 +260,33 @@ export const producerLayer = (databaseUrl: string) =>
235
260
 
236
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.
237
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
+
238
290
  ### API
239
291
 
240
292
  Import the module that defines the name; the package has no root entry.
@@ -259,7 +311,7 @@ The application's service has these operations:
259
311
 
260
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 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`.
261
313
 
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.
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.
263
315
 
264
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.
265
317
 
@@ -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"}
@@ -1 +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"}
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;AAG/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"}
@@ -1,5 +1,6 @@
1
1
  import { Effect, Option, Redacted, Schema } from "effect";
2
2
  import { PgBossPayloadError, toPgBossError } from "#error.ts";
3
+ import { payloadOf } from "#internal/tracing.ts";
3
4
  export function getJobFor(client) {
4
5
  return (queue, id) => Effect.tryPromise({
5
6
  catch: (error) => toPgBossError("getJob", error, queue.name),
@@ -11,7 +12,7 @@ export function getJobFor(client) {
11
12
  },
12
13
  }).pipe(Effect.flatMap((job) => job === undefined
13
14
  ? 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
+ : Schema.decodeUnknownEffect(queue.schema)(payloadOf(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
  }
16
17
  export function retryFor(client) {
17
18
  return (queue, id) => Effect.tryPromise({
@@ -1 +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
+ {"version":3,"file":"jobControl.js","sourceRoot":"","sources":["../../../src/server/internal/jobControl.ts"],"names":[],"mappings":"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"}
@@ -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;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
+ {"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;AA6BvF,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,eAAe,GAAG,MAAM,CAEtE;AAgED,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,7 +1,8 @@
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
4
  import { ensureQueue } from "#internal/ensureQueue.ts";
5
+ import { payloadOf, traceJob } from "#internal/tracing.ts";
5
6
  function isQueueWorker(registration) {
6
7
  return registration._tag === "QueueWorker";
7
8
  }
@@ -11,35 +12,45 @@ function isScheduledWorker(registration) {
11
12
  function isQueueDefinition(registration) {
12
13
  return registration._tag === "QueueDefinition";
13
14
  }
14
- export const registrationName = (registration) => {
15
+ function registrationDefinition(registration) {
15
16
  if (isQueueDefinition(registration)) {
16
- return registration.name;
17
+ return registration;
17
18
  }
18
19
  if (isQueueWorker(registration)) {
19
- return registration.queue.name;
20
+ return registration.queue;
20
21
  }
21
22
  if (isScheduledWorker(registration)) {
22
- return registration.schedule.name;
23
+ return registration.schedule;
23
24
  }
24
25
  throw new TypeError(`Unknown pg-boss registration: ${registration._tag}`);
25
- };
26
+ }
27
+ export function registrationName(registration) {
28
+ return registrationDefinition(registration).name;
29
+ }
30
+ async function prepareQueues(client, registrations, replaceWorkers) {
31
+ for (const registration of registrations) {
32
+ if (replaceWorkers && !isQueueDefinition(registration)) {
33
+ await client.offWork(registrationName(registration));
34
+ }
35
+ }
36
+ for (const registration of registrations) {
37
+ const definition = registrationDefinition(registration);
38
+ await ensureQueue(client, definition.name, definition.queueOptions);
39
+ }
40
+ }
26
41
  function workerContext(context) {
27
42
  return context;
28
43
  }
29
44
  function runQueueWorker(worker, job, context) {
30
- return Effect.runPromise(Schema.decodeUnknownEffect(worker.queue.schema)(job.data).pipe(Effect.mapError((error) => new PgBossPayloadError({
45
+ return Effect.runPromise(Schema.decodeUnknownEffect(worker.queue.schema)(payloadOf(job.data)).pipe(Effect.mapError((error) => new PgBossPayloadError({
31
46
  direction: "decode",
32
47
  original: Redacted.make(error),
33
48
  queue: worker.queue.name,
34
- })), Effect.flatMap((payload) => worker.handler(payload, jobContext(job))), Effect.provide(context)), { signal: job.signal });
49
+ })), Effect.flatMap((payload) => worker.handler(payload, jobContext(job))), (effect) => traceJob(effect, job, worker.queue.name), Effect.provide(context)), { signal: job.signal });
35
50
  }
36
- async function registerQueue(client, registration, context, replaceWorker) {
51
+ async function registerQueue(client, registration, context) {
37
52
  const queue = registration._tag === "QueueWorker" ? registration.queue : registration;
38
53
  const name = queue.name;
39
- if (replaceWorker && registration._tag === "QueueWorker") {
40
- await client.offWork(name);
41
- }
42
- await ensureQueue(client, name, queue.queueOptions);
43
54
  if (registration._tag === "QueueDefinition") {
44
55
  return;
45
56
  }
@@ -49,15 +60,11 @@ async function registerQueue(client, registration, context, replaceWorker) {
49
60
  }
50
61
  });
51
62
  }
52
- async function registerSchedule(client, worker, context, replaceWorker) {
63
+ async function registerSchedule(client, worker, context) {
53
64
  const { schedule } = worker;
54
- if (replaceWorker) {
55
- await client.offWork(schedule.name);
56
- }
57
- await ensureQueue(client, schedule.name, schedule.queueOptions);
58
65
  await client.work(schedule.name, schedule.workerOptions, async (jobs) => {
59
66
  for (const job of jobs) {
60
- await Effect.runPromise(Effect.provide(worker.effect, context), {
67
+ await Effect.runPromise(Effect.provide(traceJob(worker.effect, job, schedule.name), context), {
61
68
  signal: job.signal,
62
69
  });
63
70
  }
@@ -75,13 +82,14 @@ export const registerJobs = (client, registrations, context, replaceWorkers) =>
75
82
  catch: (error) => (error instanceof PgBossQueueOptionsError ? error : toPgBossError("register", error)),
76
83
  try: async () => {
77
84
  registrationNames(registrations);
85
+ await prepareQueues(client, registrations, replaceWorkers);
78
86
  const provided = workerContext(context);
79
87
  for (const registration of registrations) {
80
88
  if (isQueueWorker(registration) || isQueueDefinition(registration)) {
81
- await registerQueue(client, registration, provided, replaceWorkers);
89
+ await registerQueue(client, registration, provided);
82
90
  }
83
91
  else if (isScheduledWorker(registration)) {
84
- await registerSchedule(client, registration, provided, replaceWorkers);
92
+ await registerSchedule(client, registration, provided);
85
93
  }
86
94
  }
87
95
  },
@@ -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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"}
@@ -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;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
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/server/internal/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,eAAO,MAAM,WAAW,WAAY,YAAY,SAAS,SAAS,MAAM,EAAE,sBAAsB,aAoC9F,CAAC"}
@@ -3,6 +3,7 @@ import { PgBossPayloadError, toPgBossError } from "#error.ts";
3
3
  import { countsFor } from "#internal/countsFor.ts";
4
4
  import { healthFor } from "#internal/health.ts";
5
5
  import { getJobFor, retryFor } from "#internal/jobControl.ts";
6
+ import { capturePayload } from "#internal/tracing.ts";
6
7
  export const makeService = (client, names, schema = "pgboss") => ({
7
8
  counts: (queue) => countsFor(client, schema, queue.name),
8
9
  enqueue: (queue, payload, options) => Schema.encodeUnknownEffect(queue.schema)(payload).pipe(Effect.mapError((error) => new PgBossPayloadError({
@@ -17,10 +18,10 @@ export const makeService = (client, names, schema = "pgboss") => ({
17
18
  queue: queue.name,
18
19
  }));
19
20
  }
20
- return Effect.tryPromise({
21
+ return capturePayload(encoded).pipe(Effect.flatMap((data) => Effect.tryPromise({
21
22
  catch: (error) => toPgBossError("enqueue", error, queue.name),
22
- try: () => client.send(queue.name, encoded, options),
23
- }).pipe(Effect.map(Option.fromNullishOr));
23
+ try: () => client.send(queue.name, data, options),
24
+ })), Effect.map(Option.fromNullishOr));
24
25
  })),
25
26
  getJob: getJobFor(client),
26
27
  health: healthFor(client, names),
@@ -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;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
+ {"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;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAGtD,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,cAAc,CAAC,OAAO,CAAC,CAAC,IAAI,CAClC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CACvB,MAAM,CAAC,UAAU,CAAC;YACjB,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,IAAI,EAAE,OAAO,CAAC;SACjD,CAAC,CACF,EACD,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,aAAa,CAAC,CAChC,CAAC;IACH,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"}
@@ -0,0 +1,6 @@
1
+ import { Effect, Tracer } from "effect";
2
+ import type { Job } from "pg-boss";
3
+ export declare function capturePayload(payload: object): Effect.Effect<object>;
4
+ export declare function payloadOf(data: unknown): unknown;
5
+ export declare function traceJob<A, E, R>(effect: Effect.Effect<A, E, R>, job: Job<unknown>, queue: string): Effect.Effect<A, E, Exclude<R, Tracer.ParentSpan>>;
6
+ //# sourceMappingURL=tracing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../../src/server/internal/tracing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkB,MAAM,EAAE,MAAM,QAAQ,CAAC;AACxD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAUnC,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAUrE;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAEhD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,sDAgBjG"}
@@ -0,0 +1,37 @@
1
+ import { Effect, Option, Schema, Tracer } from "effect";
2
+ const TracedPayload = Schema.Struct({
3
+ _tag: Schema.Literal("@shivaedev/effect-pg-boss/TracedPayload"),
4
+ payload: Schema.Unknown,
5
+ span: Schema.Struct({ sampled: Schema.Boolean, spanId: Schema.String, traceId: Schema.String }),
6
+ });
7
+ const isTracedPayload = Schema.is(TracedPayload);
8
+ export function capturePayload(payload) {
9
+ return Effect.map(Effect.option(Effect.currentParentSpan), (span) => Option.isNone(span)
10
+ ? payload
11
+ : {
12
+ _tag: "@shivaedev/effect-pg-boss/TracedPayload",
13
+ payload,
14
+ span: { sampled: span.value.sampled, spanId: span.value.spanId, traceId: span.value.traceId },
15
+ });
16
+ }
17
+ export function payloadOf(data) {
18
+ return isTracedPayload(data) ? data.payload : data;
19
+ }
20
+ export function traceJob(effect, job, queue) {
21
+ return Effect.withSpan(effect, queue, {
22
+ attributes: {
23
+ "job.attempt": job.retryCount + 1,
24
+ "job.id": job.id,
25
+ "job.name": job.name,
26
+ "job.queue": queue,
27
+ "job.retry_count": job.retryCount,
28
+ "messaging.destination.name": queue,
29
+ "messaging.message.id": job.id,
30
+ "messaging.system": "pg-boss",
31
+ },
32
+ kind: "consumer",
33
+ links: isTracedPayload(job.data) ? [{ attributes: {}, span: Tracer.externalSpan(job.data.span) }] : [],
34
+ root: true,
35
+ });
36
+ }
37
+ //# sourceMappingURL=tracing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.js","sourceRoot":"","sources":["../../../src/server/internal/tracing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGxD,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,yCAAyC,CAAC;IAC/D,OAAO,EAAE,MAAM,CAAC,OAAO;IACvB,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;CAC/F,CAAC,CAAC;AAEH,MAAM,eAAe,GAAG,MAAM,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC;AAEjD,MAAM,UAAU,cAAc,CAAC,OAAe;IAC7C,OAAO,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CACnE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC;QAClB,CAAC,CAAC,OAAO;QACT,CAAC,CAAE;YACD,IAAI,EAAE,yCAAyC;YAC/C,OAAO;YACP,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE;SACxD,CACxC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,IAAa;IACtC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,QAAQ,CAAU,MAA8B,EAAE,GAAiB,EAAE,KAAa;IACjG,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE;QACrC,UAAU,EAAE;YACX,aAAa,EAAE,GAAG,CAAC,UAAU,GAAG,CAAC;YACjC,QAAQ,EAAE,GAAG,CAAC,EAAE;YAChB,UAAU,EAAE,GAAG,CAAC,IAAI;YACpB,WAAW,EAAE,KAAK;YAClB,iBAAiB,EAAE,GAAG,CAAC,UAAU;YACjC,4BAA4B,EAAE,KAAK;YACnC,sBAAsB,EAAE,GAAG,CAAC,EAAE;YAC9B,kBAAkB,EAAE,SAAS;SAC7B;QACD,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;QACtG,IAAI,EAAE,IAAI;KACV,CAAC,CAAC;AACJ,CAAC"}
@@ -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.0",
3
+ "version": "0.7.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": {
@@ -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
  };
@@ -1,6 +1,7 @@
1
1
  import { Effect, Option, Redacted, Schema } from "effect";
2
2
  import type { PgBossClient } from "#client.ts";
3
3
  import { PgBossPayloadError, toPgBossError } from "#error.ts";
4
+ import { payloadOf } from "#internal/tracing.ts";
4
5
  import type { PgBossService } from "#service.ts";
5
6
 
6
7
  export function getJobFor(client: PgBossClient): PgBossService["getJob"] {
@@ -17,7 +18,7 @@ export function getJobFor(client: PgBossClient): PgBossService["getJob"] {
17
18
  Effect.flatMap((job) =>
18
19
  job === undefined
19
20
  ? Effect.succeed(Option.none())
20
- : Schema.decodeUnknownEffect(queue.schema)(job.data).pipe(
21
+ : Schema.decodeUnknownEffect(queue.schema)(payloadOf(job.data)).pipe(
21
22
  Effect.mapError((error) => new PgBossPayloadError({ direction: "decode", original: Redacted.make(error), queue: queue.name })),
22
23
  Effect.map((data) => Option.some({ ...job, data })),
23
24
  ),
@@ -1,9 +1,17 @@
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";
6
13
  import { ensureQueue } from "#internal/ensureQueue.ts";
14
+ import { payloadOf, traceJob } from "#internal/tracing.ts";
7
15
 
8
16
  function isQueueWorker(registration: JobRegistration): registration is QueueWorker {
9
17
  return registration._tag === "QueueWorker";
@@ -17,18 +25,34 @@ function isQueueDefinition(registration: JobRegistration): registration is Queue
17
25
  return registration._tag === "QueueDefinition";
18
26
  }
19
27
 
20
- export const registrationName = (registration: JobRegistration): string => {
28
+ function registrationDefinition(registration: JobRegistration): QueueDefinition | ScheduleDefinition {
21
29
  if (isQueueDefinition(registration)) {
22
- return registration.name;
30
+ return registration;
23
31
  }
24
32
  if (isQueueWorker(registration)) {
25
- return registration.queue.name;
33
+ return registration.queue;
26
34
  }
27
35
  if (isScheduledWorker(registration)) {
28
- return registration.schedule.name;
36
+ return registration.schedule;
29
37
  }
30
38
  throw new TypeError(`Unknown pg-boss registration: ${registration._tag}`);
31
- };
39
+ }
40
+
41
+ export function registrationName(registration: JobRegistration): string {
42
+ return registrationDefinition(registration).name;
43
+ }
44
+
45
+ async function prepareQueues(client: PgBossClient, registrations: readonly JobRegistration[], replaceWorkers: boolean): Promise<void> {
46
+ for (const registration of registrations) {
47
+ if (replaceWorkers && !isQueueDefinition(registration)) {
48
+ await client.offWork(registrationName(registration));
49
+ }
50
+ }
51
+ for (const registration of registrations) {
52
+ const definition = registrationDefinition(registration);
53
+ await ensureQueue(client, definition.name, definition.queueOptions);
54
+ }
55
+ }
32
56
 
33
57
  // The layer requires RegistrationRequirements of its jobs, so its context provides every registered worker.
34
58
  function workerContext<R>(context: Context.Context<R>): Context.Context<unknown>;
@@ -38,7 +62,7 @@ function workerContext(context: unknown): unknown {
38
62
 
39
63
  function runQueueWorker(worker: QueueWorker, job: Job<unknown>, context: Context.Context<unknown>): Promise<unknown> {
40
64
  return Effect.runPromise(
41
- Schema.decodeUnknownEffect(worker.queue.schema)(job.data).pipe(
65
+ Schema.decodeUnknownEffect(worker.queue.schema)(payloadOf(job.data)).pipe(
42
66
  Effect.mapError(
43
67
  (error) =>
44
68
  new PgBossPayloadError({
@@ -48,24 +72,16 @@ function runQueueWorker(worker: QueueWorker, job: Job<unknown>, context: Context
48
72
  }),
49
73
  ),
50
74
  Effect.flatMap((payload) => worker.handler(payload, jobContext(job))),
75
+ (effect) => traceJob(effect, job, worker.queue.name),
51
76
  Effect.provide(context),
52
77
  ),
53
78
  { signal: job.signal },
54
79
  );
55
80
  }
56
81
 
57
- async function registerQueue(
58
- client: PgBossClient,
59
- registration: QueueWorker | QueueDefinition,
60
- context: Context.Context<unknown>,
61
- replaceWorker: boolean,
62
- ): Promise<void> {
82
+ async function registerQueue(client: PgBossClient, registration: QueueWorker | QueueDefinition, context: Context.Context<unknown>): Promise<void> {
63
83
  const queue = registration._tag === "QueueWorker" ? registration.queue : registration;
64
84
  const name = queue.name;
65
- if (replaceWorker && registration._tag === "QueueWorker") {
66
- await client.offWork(name);
67
- }
68
- await ensureQueue(client, name, queue.queueOptions);
69
85
  if (registration._tag === "QueueDefinition") {
70
86
  return;
71
87
  }
@@ -76,20 +92,11 @@ async function registerQueue(
76
92
  });
77
93
  }
78
94
 
79
- async function registerSchedule(
80
- client: PgBossClient,
81
- worker: ScheduledWorker,
82
- context: Context.Context<unknown>,
83
- replaceWorker: boolean,
84
- ): Promise<void> {
95
+ async function registerSchedule(client: PgBossClient, worker: ScheduledWorker, context: Context.Context<unknown>): Promise<void> {
85
96
  const { schedule } = worker;
86
- if (replaceWorker) {
87
- await client.offWork(schedule.name);
88
- }
89
- await ensureQueue(client, schedule.name, schedule.queueOptions);
90
97
  await client.work(schedule.name, schedule.workerOptions, async (jobs: readonly Job<unknown>[]) => {
91
98
  for (const job of jobs) {
92
- await Effect.runPromise(Effect.provide(worker.effect, context), {
99
+ await Effect.runPromise(Effect.provide(traceJob(worker.effect, job, schedule.name), context), {
93
100
  signal: job.signal,
94
101
  });
95
102
  }
@@ -115,12 +122,13 @@ export const registerJobs = <R>(
115
122
  catch: (error) => (error instanceof PgBossQueueOptionsError ? error : toPgBossError("register", error)),
116
123
  try: async () => {
117
124
  registrationNames(registrations);
125
+ await prepareQueues(client, registrations, replaceWorkers);
118
126
  const provided = workerContext(context);
119
127
  for (const registration of registrations) {
120
128
  if (isQueueWorker(registration) || isQueueDefinition(registration)) {
121
- await registerQueue(client, registration, provided, replaceWorkers);
129
+ await registerQueue(client, registration, provided);
122
130
  } else if (isScheduledWorker(registration)) {
123
- await registerSchedule(client, registration, provided, replaceWorkers);
131
+ await registerSchedule(client, registration, provided);
124
132
  }
125
133
  }
126
134
  },
@@ -4,6 +4,7 @@ import { type PgBossError, PgBossPayloadError, toPgBossError } from "#error.ts";
4
4
  import { countsFor } from "#internal/countsFor.ts";
5
5
  import { healthFor } from "#internal/health.ts";
6
6
  import { getJobFor, retryFor } from "#internal/jobControl.ts";
7
+ import { capturePayload } from "#internal/tracing.ts";
7
8
  import type { PgBossService } from "#service.ts";
8
9
 
9
10
  export const makeService = (client: PgBossClient, names: readonly string[], schema = "pgboss"): PgBossService => ({
@@ -28,10 +29,15 @@ export const makeService = (client: PgBossClient, names: readonly string[], sche
28
29
  }),
29
30
  );
30
31
  }
31
- return Effect.tryPromise({
32
- catch: (error) => toPgBossError("enqueue", error, queue.name),
33
- try: () => client.send(queue.name, encoded, options),
34
- }).pipe(Effect.map(Option.fromNullishOr));
32
+ return capturePayload(encoded).pipe(
33
+ Effect.flatMap((data) =>
34
+ Effect.tryPromise({
35
+ catch: (error) => toPgBossError("enqueue", error, queue.name),
36
+ try: () => client.send(queue.name, data, options),
37
+ }),
38
+ ),
39
+ Effect.map(Option.fromNullishOr),
40
+ );
35
41
  }),
36
42
  ),
37
43
  getJob: getJobFor(client),
@@ -0,0 +1,44 @@
1
+ import { Effect, Option, Schema, Tracer } from "effect";
2
+ import type { Job } from "pg-boss";
3
+
4
+ const TracedPayload = Schema.Struct({
5
+ _tag: Schema.Literal("@shivaedev/effect-pg-boss/TracedPayload"),
6
+ payload: Schema.Unknown,
7
+ span: Schema.Struct({ sampled: Schema.Boolean, spanId: Schema.String, traceId: Schema.String }),
8
+ });
9
+
10
+ const isTracedPayload = Schema.is(TracedPayload);
11
+
12
+ export function capturePayload(payload: object): Effect.Effect<object> {
13
+ return Effect.map(Effect.option(Effect.currentParentSpan), (span) =>
14
+ Option.isNone(span)
15
+ ? payload
16
+ : ({
17
+ _tag: "@shivaedev/effect-pg-boss/TracedPayload",
18
+ payload,
19
+ span: { sampled: span.value.sampled, spanId: span.value.spanId, traceId: span.value.traceId },
20
+ } satisfies typeof TracedPayload.Type),
21
+ );
22
+ }
23
+
24
+ export function payloadOf(data: unknown): unknown {
25
+ return isTracedPayload(data) ? data.payload : data;
26
+ }
27
+
28
+ export function traceJob<A, E, R>(effect: Effect.Effect<A, E, R>, job: Job<unknown>, queue: string) {
29
+ return Effect.withSpan(effect, queue, {
30
+ attributes: {
31
+ "job.attempt": job.retryCount + 1,
32
+ "job.id": job.id,
33
+ "job.name": job.name,
34
+ "job.queue": queue,
35
+ "job.retry_count": job.retryCount,
36
+ "messaging.destination.name": queue,
37
+ "messaging.message.id": job.id,
38
+ "messaging.system": "pg-boss",
39
+ },
40
+ kind: "consumer",
41
+ links: isTracedPayload(job.data) ? [{ attributes: {}, span: Tracer.externalSpan(job.data.span) }] : [],
42
+ root: true,
43
+ });
44
+ }
@@ -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