@shivaedev/effect-pg-boss 0.7.0 → 0.8.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 +20 -0
- package/README.md +40 -3
- package/dist/server/client.d.ts +2 -0
- package/dist/server/client.d.ts.map +1 -1
- package/dist/server/client.js.map +1 -1
- package/dist/server/definition.d.ts +2 -1
- package/dist/server/definition.d.ts.map +1 -1
- package/dist/server/definition.js +3 -0
- package/dist/server/definition.js.map +1 -1
- package/dist/server/internal/batchHandler.d.ts +5 -0
- package/dist/server/internal/batchHandler.d.ts.map +1 -0
- package/dist/server/internal/batchHandler.js +41 -0
- package/dist/server/internal/batchHandler.js.map +1 -0
- package/dist/server/internal/deadlineOf.d.ts +3 -0
- package/dist/server/internal/deadlineOf.d.ts.map +1 -0
- package/dist/server/internal/deadlineOf.js +7 -0
- package/dist/server/internal/deadlineOf.js.map +1 -0
- package/dist/server/internal/register.d.ts.map +1 -1
- package/dist/server/internal/register.js +5 -14
- package/dist/server/internal/register.js.map +1 -1
- package/package.json +1 -1
- package/src/server/client.ts +2 -0
- package/src/server/definition.ts +4 -1
- package/src/server/internal/batchHandler.ts +46 -0
- package/src/server/internal/deadlineOf.ts +8 -0
- package/src/server/internal/register.ts +23 -27
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.8.0 - 2026-10-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `JobContext.remainingBudget` is an `Effect.Effect<Duration.Duration>` that reads the time left until the fetched job's expiry deadline, clamped to zero.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Bound queue and scheduled handlers by each job's pg-boss `startedOn` plus `expireInSeconds`, including time spent waiting in a batch. Skip jobs whose window has passed and interrupt running Effects at their deadline, leaving interrupted and unstarted jobs for pg-boss expiry and retry. Worker registration requests start-time metadata even when `includeMetadata: false` is supplied.
|
|
12
|
+
|
|
13
|
+
## 0.7.1 - 2026-10-17
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- 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.
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- 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.
|
|
22
|
+
|
|
3
23
|
## 0.7.0 - 2026-10-17
|
|
4
24
|
|
|
5
25
|
### Changed
|
package/README.md
CHANGED
|
@@ -112,10 +112,47 @@ const Compare = defineQueue({
|
|
|
112
112
|
});
|
|
113
113
|
```
|
|
114
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
|
|
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
116
|
|
|
117
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
118
|
|
|
119
|
+
### Size batches against expiry
|
|
120
|
+
|
|
121
|
+
pg-boss marks every job in a fetched batch active together. Each job's expiry window starts at its stored `startedOn`, including time waiting for earlier handlers. Size each queue's batch so its sequential work fits within that window; use a small batch for long-running work and keep the default for short work:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
const Ingest = defineQueue({
|
|
125
|
+
name: "ingest",
|
|
126
|
+
schema: Schema.Struct({ sourceId: Schema.String }),
|
|
127
|
+
queue: { expireInSeconds: 300 },
|
|
128
|
+
worker: { batchSize: 1 },
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const IndexTitle = defineQueue({
|
|
132
|
+
name: "index-title",
|
|
133
|
+
schema: Schema.Struct({ titleId: Schema.String }),
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`Ingest` fetches one job at a time; `IndexTitle` keeps the default batch of ten. Configure the expiry for the work's expected duration. Increasing `localConcurrency` adds batches; it does not extend any job's window.
|
|
138
|
+
|
|
139
|
+
The adapter enforces each queue or scheduled job's deadline using pg-boss's `startedOn` and `expireInSeconds`. It skips jobs whose window has already passed and interrupts a running Effect at its deadline. Expired jobs remain for pg-boss's expiry and retry engine. Interruption stops the rest of that batch, as described above.
|
|
140
|
+
|
|
141
|
+
Queue handlers can yield `job.remainingBudget`, an `Effect.Effect<Duration.Duration>` that recomputes the time left at each read and clamps it to zero. Use it to size a downstream operation's timeout:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
import { Duration, Effect } from "effect";
|
|
145
|
+
|
|
146
|
+
const ingestWorker = Ingest.handle(({ sourceId }, job) =>
|
|
147
|
+
Effect.gen(function* () {
|
|
148
|
+
const budget = yield* job.remainingBudget;
|
|
149
|
+
yield* Effect.log({ sourceId, remainingMilliseconds: Duration.toMillis(budget) });
|
|
150
|
+
}),
|
|
151
|
+
);
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Keep handler work interruptible and use cancellation-aware Effect integrations for external operations. A deadline interrupts the Effect fiber; it cannot stop an uninterruptible region or an external side effect that ignores cancellation. Handlers must tolerate retries.
|
|
155
|
+
|
|
119
156
|
### Once per runtime: provide the workers
|
|
120
157
|
|
|
121
158
|
Build the jobs Layer in `runtime.ts`:
|
|
@@ -309,11 +346,11 @@ The application's service has these operations:
|
|
|
309
346
|
- `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.
|
|
310
347
|
- `retry(queue, id)`: an Effect returning `void`, with `PgBossError` in its error type.
|
|
311
348
|
|
|
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`.
|
|
349
|
+
`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`.
|
|
313
350
|
|
|
314
351
|
`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.
|
|
315
352
|
|
|
316
|
-
`JobContext` has `id`, `name`, `signal`, `expireInSeconds` and `
|
|
353
|
+
`JobContext` has `id`, `name`, `signal`, `expireInSeconds`, `heartbeatSeconds` and `remainingBudget`. Worker registration always requests `includeMetadata: true`, including when `worker` supplies `includeMetadata: false`; custom clients must return pg-boss's `startedOn` metadata. When calling `jobContext` directly, reading `remainingBudget` requires that same metadata. `QueueHealth` has `name`, `activeCount`, `deadLetteredCount`, `failedCount`, `queuedCount` and `readyCount`. `JobsHealth` has `jobs` and the corresponding `activeTotal`, `deadLetteredTotal`, `failedTotal`, `queuedTotal` and `readyTotal` fields.
|
|
317
354
|
|
|
318
355
|
`PgBossError` has `operation`, optional `queue` and a `Redacted` `original`. `PgBossPayloadError` has `direction`, `queue` and a `Redacted` `original`. Those fields distinguish the pg-boss operation from the payload boundary.
|
|
319
356
|
|
package/dist/server/client.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Duration, Effect, type Schema } from "effect";
|
|
2
2
|
import type { Job, Queue, ScheduleOptions, WorkOptions } from "pg-boss";
|
|
3
3
|
export interface JobPayloadSchema extends Schema.Top {
|
|
4
4
|
readonly Encoded: object;
|
|
@@ -9,6 +9,7 @@ export interface JobContext {
|
|
|
9
9
|
readonly heartbeatSeconds: number | null;
|
|
10
10
|
readonly id: string;
|
|
11
11
|
readonly name: string;
|
|
12
|
+
readonly remainingBudget: Effect.Effect<Duration.Duration>;
|
|
12
13
|
readonly signal: AbortSignal;
|
|
13
14
|
}
|
|
14
15
|
export interface QueueDefinition<Name extends string = string, Payload extends JobPayloadSchema = JobPayloadSchema> {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/server/definition.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../src/server/definition.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { Clock, Duration, Effect } from "effect";
|
|
2
|
+
import { deadlineOf } from "#internal/deadlineOf.ts";
|
|
1
3
|
export const defineQueue = (options) => {
|
|
2
4
|
const definition = {
|
|
3
5
|
_tag: "QueueDefinition",
|
|
@@ -34,6 +36,7 @@ export const jobContext = (job) => ({
|
|
|
34
36
|
heartbeatSeconds: job.heartbeatSeconds,
|
|
35
37
|
id: job.id,
|
|
36
38
|
name: job.name,
|
|
39
|
+
remainingBudget: Effect.map(Clock.currentTimeMillis, (now) => Duration.millis(Math.max(0, deadlineOf(job) - now))),
|
|
37
40
|
signal: job.signal,
|
|
38
41
|
});
|
|
39
42
|
//# sourceMappingURL=definition.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.js","sourceRoot":"","sources":["../../src/server/definition.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"definition.js","sourceRoot":"","sources":["../../src/server/definition.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAe,MAAM,QAAQ,CAAC;AAE9D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAoErD,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,eAAe,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IAClH,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,EAAgB,MAAM,EAAQ,MAAM,QAAQ,CAAC;AACpD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAQ/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,CA6B3D"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Cause, Clock, Effect, Exit } from "effect";
|
|
2
|
+
import { deadlineOf } from "#internal/deadlineOf.ts";
|
|
3
|
+
function failureOutput(cause) {
|
|
4
|
+
const error = Cause.squash(cause);
|
|
5
|
+
return typeof error === "object" && error !== null ? error : { message: String(error) };
|
|
6
|
+
}
|
|
7
|
+
export function batchHandler(client, name, run) {
|
|
8
|
+
const complete = client.complete?.bind(client);
|
|
9
|
+
const fail = client.fail?.bind(client);
|
|
10
|
+
if (complete === undefined || fail === undefined) {
|
|
11
|
+
throw new TypeError("This pg-boss client does not support complete and fail");
|
|
12
|
+
}
|
|
13
|
+
return async (jobs) => {
|
|
14
|
+
let expired = false;
|
|
15
|
+
for (const job of jobs) {
|
|
16
|
+
const deadline = deadlineOf(job);
|
|
17
|
+
if ((await Effect.runPromise(Clock.currentTimeMillis)) >= deadline) {
|
|
18
|
+
expired = true;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
const exit = await Effect.runPromiseExit(Effect.flatMap(Clock.currentTimeMillis, (now) => {
|
|
22
|
+
const remaining = deadline - now;
|
|
23
|
+
return remaining <= 0 ? Effect.interrupt : run(job).pipe(Effect.timeoutOrElse({ duration: remaining, orElse: () => Effect.interrupt }));
|
|
24
|
+
}), { signal: job.signal });
|
|
25
|
+
if (job.signal.aborted || (Exit.isFailure(exit) && Cause.hasInterrupts(exit.cause))) {
|
|
26
|
+
// Returning would let pg-boss complete the unprocessed jobs; its expiry owns them instead.
|
|
27
|
+
return new Promise(() => undefined);
|
|
28
|
+
}
|
|
29
|
+
if (Exit.isSuccess(exit)) {
|
|
30
|
+
await complete(name, job);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
await fail(name, job, failureOutput(exit.cause));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (expired) {
|
|
37
|
+
return new Promise(() => undefined);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# 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,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAGpD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,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,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YACjC,IAAI,CAAC,MAAM,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACpE,OAAO,GAAG,IAAI,CAAC;gBACf,SAAS;YACV,CAAC;YACD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,cAAc,CACvC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,iBAAiB,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC/C,MAAM,SAAS,GAAG,QAAQ,GAAG,GAAG,CAAC;gBACjC,OAAO,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;YACzI,CAAC,CAAC,EACF,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;QACD,IAAI,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,OAAO,CAAQ,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;QAC5C,CAAC;IACF,CAAC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deadlineOf.d.ts","sourceRoot":"","sources":["../../../src/server/internal/deadlineOf.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAEnC,wBAAgB,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,GAAG,MAAM,CAKpD"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export function deadlineOf(job) {
|
|
2
|
+
if (!("startedOn" in job && job.startedOn instanceof Date && Number.isFinite(job.startedOn.getTime()))) {
|
|
3
|
+
throw new TypeError("Worker jobs must include pg-boss startedOn metadata");
|
|
4
|
+
}
|
|
5
|
+
return job.startedOn.getTime() + job.expireInSeconds * 1000;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=deadlineOf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deadlineOf.js","sourceRoot":"","sources":["../../../src/server/internal/deadlineOf.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,UAAU,CAAC,GAAiB;IAC3C,IAAI,CAAC,CAAC,WAAW,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,YAAY,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC,EAAE,CAAC;QACxG,MAAM,IAAI,SAAS,CAAC,qDAAqD,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,eAAe,GAAG,IAAI,CAAC;AAC7D,CAAC"}
|
|
@@ -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,EACN,KAAK,eAAe,EAMpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAsB,uBAAuB,EAAiB,MAAM,WAAW,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
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) {
|
|
@@ -42,11 +43,11 @@ function workerContext(context) {
|
|
|
42
43
|
return context;
|
|
43
44
|
}
|
|
44
45
|
function runQueueWorker(worker, job, context) {
|
|
45
|
-
return
|
|
46
|
+
return Schema.decodeUnknownEffect(worker.queue.schema)(payloadOf(job.data)).pipe(Effect.mapError((error) => new PgBossPayloadError({
|
|
46
47
|
direction: "decode",
|
|
47
48
|
original: Redacted.make(error),
|
|
48
49
|
queue: worker.queue.name,
|
|
49
|
-
})), Effect.flatMap((payload) => worker.handler(payload, jobContext(job))), (effect) => traceJob(effect, job, worker.queue.name), Effect.provide(context))
|
|
50
|
+
})), Effect.flatMap((payload) => worker.handler(payload, jobContext(job))), (effect) => traceJob(effect, job, worker.queue.name), Effect.provide(context));
|
|
50
51
|
}
|
|
51
52
|
async function registerQueue(client, registration, context) {
|
|
52
53
|
const queue = registration._tag === "QueueWorker" ? registration.queue : registration;
|
|
@@ -54,21 +55,11 @@ async function registerQueue(client, registration, context) {
|
|
|
54
55
|
if (registration._tag === "QueueDefinition") {
|
|
55
56
|
return;
|
|
56
57
|
}
|
|
57
|
-
await client.work(name, queue.workerOptions,
|
|
58
|
-
for (const job of jobs) {
|
|
59
|
-
await runQueueWorker(registration, job, context);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
58
|
+
await client.work(name, { ...queue.workerOptions, includeMetadata: true }, batchHandler(client, name, (job) => runQueueWorker(registration, job, context)));
|
|
62
59
|
}
|
|
63
60
|
async function registerSchedule(client, worker, context) {
|
|
64
61
|
const { schedule } = worker;
|
|
65
|
-
await client.work(schedule.name, schedule.workerOptions,
|
|
66
|
-
for (const job of jobs) {
|
|
67
|
-
await Effect.runPromise(Effect.provide(traceJob(worker.effect, job, schedule.name), context), {
|
|
68
|
-
signal: job.signal,
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
});
|
|
62
|
+
await client.work(schedule.name, { ...schedule.workerOptions, includeMetadata: true }, batchHandler(client, schedule.name, (job) => Effect.provide(traceJob(worker.effect, job, schedule.name), context)));
|
|
72
63
|
await client.schedule(schedule.name, schedule.cron, null, schedule.scheduleOptions);
|
|
73
64
|
}
|
|
74
65
|
export const registrationNames = (registrations) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/server/internal/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhE,OAAO,EAEN,UAAU,GAKV,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACvF,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAE3D,SAAS,aAAa,CAAC,YAA6B;IACnD,OAAO,YAAY,CAAC,IAAI,KAAK,aAAa,CAAC;AAC5C,CAAC;AAED,SAAS,iBAAiB,CAAC,YAA6B;IACvD,OAAO,YAAY,CAAC,IAAI,KAAK,iBAAiB,CAAC;AAChD,CAAC;AAED,SAAS,iBAAiB,CAAC,YAA6B;IACvD,OAAO,YAAY,CAAC,IAAI,KAAK,iBAAiB,CAAC;AAChD,CAAC;AAED,SAAS,sBAAsB,CAAC,YAA6B;IAC5D,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;QACrC,OAAO,YAAY,CAAC;IACrB,CAAC;IACD,IAAI,aAAa,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,YAAY,CAAC,KAAK,CAAC;IAC3B,CAAC;IACD,IAAI,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;QACrC,OAAO,YAAY,CAAC,QAAQ,CAAC;IAC9B,CAAC;IACD,MAAM,IAAI,SAAS,CAAC,iCAAiC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,YAA6B;IAC7D,OAAO,sBAAsB,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,MAAoB,EAAE,aAAyC,EAAE,cAAuB;IACpH,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;QAC1C,IAAI,cAAc,IAAI,CAAC,iBAAiB,CAAC,YAAY,CAAC,EAAE,CAAC;YACxD,MAAM,MAAM,CAAC,OAAO,CAAC,gBAAgB,CAAC,YAAY,CAAC,CAAC,CAAC;QACtD,CAAC;IACF,CAAC;IACD,KAAK,MAAM,YAAY,IAAI,aAAa,EAAE,CAAC;QAC1C,MAAM,UAAU,GAAG,sBAAsB,CAAC,YAAY,CAAC,CAAC;QACxD,MAAM,WAAW,CAAC,MAAM,EAAE,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC;IACrE,CAAC;AACF,CAAC;AAID,SAAS,aAAa,CAAC,OAAgB;IACtC,OAAO,OAAO,CAAC;AAChB,CAAC;AAED,SAAS,cAAc,CAAC,MAAmB,EAAE,GAAiB,EAAE,OAAiC;IAChG,OAAO,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/server/internal/register.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/effect-pg-boss",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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": {
|
package/src/server/client.ts
CHANGED
|
@@ -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>;
|
package/src/server/definition.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Clock, Duration, Effect, type Schema } from "effect";
|
|
2
2
|
import type { Job, Queue, ScheduleOptions, WorkOptions } from "pg-boss";
|
|
3
|
+
import { deadlineOf } from "#internal/deadlineOf.ts";
|
|
3
4
|
|
|
4
5
|
export interface JobPayloadSchema extends Schema.Top {
|
|
5
6
|
readonly Encoded: object;
|
|
@@ -11,6 +12,7 @@ export interface JobContext {
|
|
|
11
12
|
readonly heartbeatSeconds: number | null;
|
|
12
13
|
readonly id: string;
|
|
13
14
|
readonly name: string;
|
|
15
|
+
readonly remainingBudget: Effect.Effect<Duration.Duration>;
|
|
14
16
|
readonly signal: AbortSignal;
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -116,5 +118,6 @@ export const jobContext = (job: Job<unknown>): JobContext => ({
|
|
|
116
118
|
heartbeatSeconds: job.heartbeatSeconds,
|
|
117
119
|
id: job.id,
|
|
118
120
|
name: job.name,
|
|
121
|
+
remainingBudget: Effect.map(Clock.currentTimeMillis, (now) => Duration.millis(Math.max(0, deadlineOf(job) - now))),
|
|
119
122
|
signal: job.signal,
|
|
120
123
|
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { Cause, Clock, Effect, Exit } from "effect";
|
|
2
|
+
import type { Job } from "pg-boss";
|
|
3
|
+
import type { PgBossClient } from "#client.ts";
|
|
4
|
+
import { deadlineOf } from "#internal/deadlineOf.ts";
|
|
5
|
+
|
|
6
|
+
function failureOutput(cause: Cause.Cause<unknown>): object {
|
|
7
|
+
const error = Cause.squash(cause);
|
|
8
|
+
return typeof error === "object" && error !== null ? error : { message: String(error) };
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function batchHandler(client: PgBossClient, name: string, run: (job: Job<unknown>) => Effect.Effect<unknown, unknown>) {
|
|
12
|
+
const complete = client.complete?.bind(client);
|
|
13
|
+
const fail = client.fail?.bind(client);
|
|
14
|
+
if (complete === undefined || fail === undefined) {
|
|
15
|
+
throw new TypeError("This pg-boss client does not support complete and fail");
|
|
16
|
+
}
|
|
17
|
+
return async (jobs: readonly Job<unknown>[]): Promise<void> => {
|
|
18
|
+
let expired = false;
|
|
19
|
+
for (const job of jobs) {
|
|
20
|
+
const deadline = deadlineOf(job);
|
|
21
|
+
if ((await Effect.runPromise(Clock.currentTimeMillis)) >= deadline) {
|
|
22
|
+
expired = true;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
const exit = await Effect.runPromiseExit(
|
|
26
|
+
Effect.flatMap(Clock.currentTimeMillis, (now) => {
|
|
27
|
+
const remaining = deadline - now;
|
|
28
|
+
return remaining <= 0 ? Effect.interrupt : run(job).pipe(Effect.timeoutOrElse({ duration: remaining, orElse: () => Effect.interrupt }));
|
|
29
|
+
}),
|
|
30
|
+
{ signal: job.signal },
|
|
31
|
+
);
|
|
32
|
+
if (job.signal.aborted || (Exit.isFailure(exit) && Cause.hasInterrupts(exit.cause))) {
|
|
33
|
+
// Returning would let pg-boss complete the unprocessed jobs; its expiry owns them instead.
|
|
34
|
+
return new Promise<never>(() => undefined);
|
|
35
|
+
}
|
|
36
|
+
if (Exit.isSuccess(exit)) {
|
|
37
|
+
await complete(name, job);
|
|
38
|
+
} else {
|
|
39
|
+
await fail(name, job, failureOutput(exit.cause));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
if (expired) {
|
|
43
|
+
return new Promise<never>(() => undefined);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Job } from "pg-boss";
|
|
2
|
+
|
|
3
|
+
export function deadlineOf(job: Job<unknown>): number {
|
|
4
|
+
if (!("startedOn" in job && job.startedOn instanceof Date && Number.isFinite(job.startedOn.getTime()))) {
|
|
5
|
+
throw new TypeError("Worker jobs must include pg-boss startedOn metadata");
|
|
6
|
+
}
|
|
7
|
+
return job.startedOn.getTime() + job.expireInSeconds * 1000;
|
|
8
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
type ScheduledWorker,
|
|
11
11
|
} from "#definition.ts";
|
|
12
12
|
import { PgBossPayloadError, PgBossQueueOptionsError, toPgBossError } from "#error.ts";
|
|
13
|
+
import { batchHandler } from "#internal/batchHandler.ts";
|
|
13
14
|
import { ensureQueue } from "#internal/ensureQueue.ts";
|
|
14
15
|
import { payloadOf, traceJob } from "#internal/tracing.ts";
|
|
15
16
|
|
|
@@ -60,22 +61,19 @@ function workerContext(context: unknown): unknown {
|
|
|
60
61
|
return context;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
function runQueueWorker(worker: QueueWorker, job: Job<unknown>, context: Context.Context<unknown>)
|
|
64
|
-
return
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
(
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}),
|
|
73
|
-
),
|
|
74
|
-
Effect.flatMap((payload) => worker.handler(payload, jobContext(job))),
|
|
75
|
-
(effect) => traceJob(effect, job, worker.queue.name),
|
|
76
|
-
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
|
+
}),
|
|
77
73
|
),
|
|
78
|
-
|
|
74
|
+
Effect.flatMap((payload) => worker.handler(payload, jobContext(job))),
|
|
75
|
+
(effect) => traceJob(effect, job, worker.queue.name),
|
|
76
|
+
Effect.provide(context),
|
|
79
77
|
);
|
|
80
78
|
}
|
|
81
79
|
|
|
@@ -85,22 +83,20 @@ async function registerQueue(client: PgBossClient, registration: QueueWorker | Q
|
|
|
85
83
|
if (registration._tag === "QueueDefinition") {
|
|
86
84
|
return;
|
|
87
85
|
}
|
|
88
|
-
await client.work(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
await client.work(
|
|
87
|
+
name,
|
|
88
|
+
{ ...queue.workerOptions, includeMetadata: true },
|
|
89
|
+
batchHandler(client, name, (job) => runQueueWorker(registration, job, context)),
|
|
90
|
+
);
|
|
93
91
|
}
|
|
94
92
|
|
|
95
93
|
async function registerSchedule(client: PgBossClient, worker: ScheduledWorker, context: Context.Context<unknown>): Promise<void> {
|
|
96
94
|
const { schedule } = worker;
|
|
97
|
-
await client.work(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
103
|
-
});
|
|
95
|
+
await client.work(
|
|
96
|
+
schedule.name,
|
|
97
|
+
{ ...schedule.workerOptions, includeMetadata: true },
|
|
98
|
+
batchHandler(client, schedule.name, (job) => Effect.provide(traceJob(worker.effect, job, schedule.name), context)),
|
|
99
|
+
);
|
|
104
100
|
await client.schedule(schedule.name, schedule.cron, null, schedule.scheduleOptions);
|
|
105
101
|
}
|
|
106
102
|
|