@shivaedev/effect-pg-boss 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +1 -1
- 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/internal/batchHandler.d.ts +1 -1
- package/dist/server/internal/batchHandler.d.ts.map +1 -1
- package/dist/server/internal/batchHandler.js +2 -1
- package/dist/server/internal/batchHandler.js.map +1 -1
- package/dist/server/internal/register.d.ts +2 -2
- package/dist/server/internal/register.d.ts.map +1 -1
- package/dist/server/internal/register.js +9 -9
- package/dist/server/internal/register.js.map +1 -1
- package/dist/server/internal/registerWorker.d.ts +5 -0
- package/dist/server/internal/registerWorker.d.ts.map +1 -0
- package/dist/server/internal/registerWorker.js +28 -0
- package/dist/server/internal/registerWorker.js.map +1 -0
- package/package.json +4 -4
- package/src/server/client.ts +2 -0
- package/src/server/internal/batchHandler.ts +7 -1
- package/src/server/internal/register.ts +32 -27
- package/src/server/internal/registerWorker.ts +42 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.1 - 2026-10-18
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Wake workers when a failed job's retry delay ends instead of waiting for the polling backstop, including idle siblings when another worker in a concurrent registration is busy. Pending wakes are canceled when the worker Layer's scope closes. Custom clients can supply the optional `PgBossClient.notifyWorker` method to enable retry wakes and `PgBossClient.getWipData` to wake every native worker in the registration.
|
|
8
|
+
|
|
3
9
|
## 0.10.0 - 2026-10-18
|
|
4
10
|
|
|
5
11
|
### Added
|
package/README.md
CHANGED
|
@@ -128,7 +128,7 @@ const Compare = defineQueue({
|
|
|
128
128
|
|
|
129
129
|
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.
|
|
130
130
|
|
|
131
|
-
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
|
|
131
|
+
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. After an adapter worker fails a job, it reads pg-boss's stored retry time and schedules a wake for every native worker in its registration at that time, so an idle sibling can retry while another worker is busy. The wake belongs to the worker Layer's scope and is canceled when that scope closes. Override the backstop when the application needs a different bound for other work that becomes runnable without a notification, such as delayed jobs or retries initiated outside the adapter worker.
|
|
132
132
|
|
|
133
133
|
### Size batches against expiry
|
|
134
134
|
|
package/dist/server/client.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export interface PgBossClient {
|
|
|
7
7
|
readonly findJobs?: (name: string, options?: FindJobsOptions) => Promise<readonly JobWithMetadata<unknown>[]>;
|
|
8
8
|
readonly getDb?: PgBoss["getDb"];
|
|
9
9
|
readonly getQueue: (name: string) => Promise<QueueResult | null>;
|
|
10
|
+
readonly getWipData?: PgBoss["getWipData"];
|
|
11
|
+
readonly notifyWorker?: PgBoss["notifyWorker"];
|
|
10
12
|
readonly off: (event: "error", listener: (error: Error) => void) => unknown;
|
|
11
13
|
readonly offWork: (name: string) => Promise<void>;
|
|
12
14
|
readonly on: (event: "error", listener: (error: Error) => void) => unknown;
|
|
@@ -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,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
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/server/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;AA0BjC,MAAM,CAAC,MAAM,oBAAoB,GAAwB,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Effect } from "effect";
|
|
2
2
|
import type { Job } from "pg-boss";
|
|
3
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>;
|
|
4
|
+
export declare function batchHandler(client: PgBossClient, name: string, run: (job: Job<unknown>) => Effect.Effect<unknown, unknown>, afterFailure?: (job: Job<unknown>) => Promise<void>): (jobs: readonly Job<unknown>[]) => Promise<void>;
|
|
5
5
|
//# sourceMappingURL=batchHandler.d.ts.map
|
|
@@ -1 +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,
|
|
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,CAC3B,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,EAC3D,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,UAO/B,SAAS,GAAG,CAAC,OAAO,CAAC,EAAE,KAAG,OAAO,CAAC,IAAI,CAAC,CA8B3D"}
|
|
@@ -4,7 +4,7 @@ function failureOutput(cause) {
|
|
|
4
4
|
const error = Cause.squash(cause);
|
|
5
5
|
return typeof error === "object" && error !== null ? error : { message: String(error) };
|
|
6
6
|
}
|
|
7
|
-
export function batchHandler(client, name, run) {
|
|
7
|
+
export function batchHandler(client, name, run, afterFailure) {
|
|
8
8
|
const complete = client.complete?.bind(client);
|
|
9
9
|
const fail = client.fail?.bind(client);
|
|
10
10
|
if (complete === undefined || fail === undefined) {
|
|
@@ -31,6 +31,7 @@ export function batchHandler(client, name, run) {
|
|
|
31
31
|
}
|
|
32
32
|
else {
|
|
33
33
|
await fail(name, job, failureOutput(exit.cause));
|
|
34
|
+
await afterFailure?.(job);
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
if (expired) {
|
|
@@ -1 +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,
|
|
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,CAC3B,MAAoB,EACpB,IAAY,EACZ,GAA2D,EAC3D,YAAmD;IAEnD,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;gBACjD,MAAM,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC;YAC3B,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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { type Context, Effect } from "effect";
|
|
1
|
+
import { type Context, Effect, type Scope } from "effect";
|
|
2
2
|
import type { PgBossClient } from "#client.ts";
|
|
3
3
|
import { type JobRegistration } from "#definition.ts";
|
|
4
4
|
import { PgBossError, PgBossQueueOptionsError } from "#error.ts";
|
|
5
5
|
export declare function registrationName(registration: JobRegistration): string;
|
|
6
6
|
export declare const registrationNames: (registrations: readonly JobRegistration[]) => readonly string[];
|
|
7
|
-
export declare const registerJobs: <R>(client: PgBossClient, registrations: readonly JobRegistration[], context: Context.Context<R>, replaceWorkers: boolean) => Effect.Effect<void, PgBossError | PgBossQueueOptionsError>;
|
|
7
|
+
export declare const registerJobs: <R>(client: PgBossClient, registrations: readonly JobRegistration[], context: Context.Context<R>, replaceWorkers: boolean) => Effect.Effect<void, PgBossError | PgBossQueueOptionsError, Scope.Scope>;
|
|
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;
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/server/internal/register.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,EAAoB,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,EACN,KAAK,eAAe,EAMpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,WAAW,EAAsB,uBAAuB,EAAiB,MAAM,WAAW,CAAC;AA8BpG,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,eAAe,GAAG,MAAM,CAEtE;AAkED,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,WAAW,GAAG,uBAAuB,EAAE,KAAK,CAAC,KAAK,CAiBvE,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Effect, Redacted, Schema } from "effect";
|
|
2
2
|
import { jobContext, } from "#definition.ts";
|
|
3
3
|
import { PgBossError, PgBossPayloadError, PgBossQueueOptionsError, toPgBossError } from "#error.ts";
|
|
4
|
-
import { batchHandler } from "#internal/batchHandler.ts";
|
|
5
4
|
import { ensureQueue } from "#internal/ensureQueue.ts";
|
|
5
|
+
import { registerWorker } from "#internal/registerWorker.ts";
|
|
6
6
|
import { payloadOf, traceJob } from "#internal/tracing.ts";
|
|
7
7
|
function isQueueWorker(registration) {
|
|
8
8
|
return registration._tag === "QueueWorker";
|
|
@@ -54,17 +54,17 @@ function runQueueWorker(worker, job, context) {
|
|
|
54
54
|
queue: worker.queue.name,
|
|
55
55
|
})), Effect.flatMap((payload) => worker.handler(payload, jobContext(job))), (effect) => traceJob(effect, job, worker.queue.name), Effect.provide(context));
|
|
56
56
|
}
|
|
57
|
-
async function registerQueue(client, registration, context) {
|
|
57
|
+
async function registerQueue(client, registration, context, scope) {
|
|
58
58
|
const queue = registration._tag === "QueueWorker" ? registration.queue : registration;
|
|
59
59
|
const name = queue.name;
|
|
60
60
|
if (registration._tag === "QueueDefinition") {
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
|
-
await client
|
|
63
|
+
await registerWorker(client, name, queue.workerOptions, (job) => runQueueWorker(registration, job, context), scope);
|
|
64
64
|
}
|
|
65
|
-
async function registerSchedule(client, worker, context) {
|
|
65
|
+
async function registerSchedule(client, worker, context, scope) {
|
|
66
66
|
const { schedule } = worker;
|
|
67
|
-
await client
|
|
67
|
+
await registerWorker(client, schedule.name, schedule.workerOptions, (job) => Effect.provide(traceJob(worker.effect, job, schedule.name), context), scope);
|
|
68
68
|
await client.schedule(schedule.name, schedule.cron, null, schedule.scheduleOptions);
|
|
69
69
|
}
|
|
70
70
|
export const registrationNames = (registrations) => {
|
|
@@ -74,7 +74,7 @@ export const registrationNames = (registrations) => {
|
|
|
74
74
|
}
|
|
75
75
|
return names;
|
|
76
76
|
};
|
|
77
|
-
export const registerJobs = (client, registrations, context, replaceWorkers) => Effect.tryPromise({
|
|
77
|
+
export const registerJobs = (client, registrations, context, replaceWorkers) => Effect.flatMap(Effect.scope, (scope) => Effect.tryPromise({
|
|
78
78
|
catch: (error) => (error instanceof PgBossQueueOptionsError || error instanceof PgBossError ? error : toPgBossError("register", error)),
|
|
79
79
|
try: async () => {
|
|
80
80
|
registrationNames(registrations);
|
|
@@ -82,12 +82,12 @@ export const registerJobs = (client, registrations, context, replaceWorkers) =>
|
|
|
82
82
|
const provided = workerContext(context);
|
|
83
83
|
for (const registration of registrations) {
|
|
84
84
|
if (isQueueWorker(registration) || isQueueDefinition(registration)) {
|
|
85
|
-
await registerQueue(client, registration, provided);
|
|
85
|
+
await registerQueue(client, registration, provided, scope);
|
|
86
86
|
}
|
|
87
87
|
else if (isScheduledWorker(registration)) {
|
|
88
|
-
await registerSchedule(client, registration, provided);
|
|
88
|
+
await registerSchedule(client, registration, provided, scope);
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
},
|
|
92
|
-
});
|
|
92
|
+
}));
|
|
93
93
|
//# sourceMappingURL=register.js.map
|
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"register.js","sourceRoot":"","sources":["../../../src/server/internal/register.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Effect, type Scope } from "effect";
|
|
2
|
+
import type { Job, WorkOptions } from "pg-boss";
|
|
3
|
+
import type { PgBossClient } from "#client.ts";
|
|
4
|
+
export declare function registerWorker(client: PgBossClient, name: string, options: WorkOptions, run: (job: Job<unknown>) => Effect.Effect<unknown, unknown>, scope: Scope.Scope): Promise<string>;
|
|
5
|
+
//# sourceMappingURL=registerWorker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registerWorker.d.ts","sourceRoot":"","sources":["../../../src/server/internal/registerWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,wBAAgB,cAAc,CAC7B,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,OAAO,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,EAC3D,KAAK,EAAE,KAAK,CAAC,KAAK,GAChB,OAAO,CAAC,MAAM,CAAC,CA8BjB"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Clock, Effect } from "effect";
|
|
2
|
+
import { batchHandler } from "#internal/batchHandler.ts";
|
|
3
|
+
export function registerWorker(client, name, options, run, scope) {
|
|
4
|
+
const registration = client.work(name, { ...options, includeMetadata: true }, batchHandler(client, name, run, async (attempt) => {
|
|
5
|
+
if (client.findJobs === undefined || client.notifyWorker === undefined) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const job = (await client.findJobs(name, { id: attempt.id }))[0];
|
|
9
|
+
if (job?.state !== "retry") {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const workId = await registration;
|
|
13
|
+
await Effect.runPromise(Effect.gen(function* () {
|
|
14
|
+
const now = yield* Clock.currentTimeMillis;
|
|
15
|
+
// PostgreSQL timestamps retain sub-millisecond precision that Date drops.
|
|
16
|
+
yield* Effect.sleep(Math.max(0, job.startAfter.getTime() + 1 - now));
|
|
17
|
+
const workerIds = client
|
|
18
|
+
.getWipData?.()
|
|
19
|
+
.filter((worker) => worker.workId === workId)
|
|
20
|
+
.map((worker) => worker.id) ?? [workId];
|
|
21
|
+
for (const workerId of workerIds) {
|
|
22
|
+
client.notifyWorker?.(workerId);
|
|
23
|
+
}
|
|
24
|
+
}).pipe(Effect.forkIn(scope)));
|
|
25
|
+
}));
|
|
26
|
+
return registration;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=registerWorker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registerWorker.js","sourceRoot":"","sources":["../../../src/server/internal/registerWorker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,EAAc,MAAM,QAAQ,CAAC;AAGnD,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAEzD,MAAM,UAAU,cAAc,CAC7B,MAAoB,EACpB,IAAY,EACZ,OAAoB,EACpB,GAA2D,EAC3D,KAAkB;IAElB,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAC/B,IAAI,EACJ,EAAE,GAAG,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,EACrC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QACjD,IAAI,MAAM,CAAC,QAAQ,KAAK,SAAS,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACxE,OAAO;QACR,CAAC;QACD,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACjE,IAAI,GAAG,EAAE,KAAK,KAAK,OAAO,EAAE,CAAC;YAC5B,OAAO;QACR,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC;QAClC,MAAM,MAAM,CAAC,UAAU,CACtB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;YACnB,MAAM,GAAG,GAAG,KAAK,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC;YAC3C,0EAA0E;YAC1E,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YACrE,MAAM,SAAS,GAAG,MAAM;iBACtB,UAAU,EAAE,EAAE;iBACd,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC;iBAC5C,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;gBAClC,MAAM,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,CAAC;YACjC,CAAC;QACF,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAC7B,CAAC;IACH,CAAC,CAAC,CACF,CAAC;IACF,OAAO,YAAY,CAAC;AACrB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/effect-pg-boss",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Effect-native jobs and lifecycle management for pg-boss",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/effect-pg-boss#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
],
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@shivaedev/effect-test": "0.6.0",
|
|
45
|
-
"@shivaedev/effect-test-sql": "0.
|
|
46
|
-
"@shivaedev/quality": "0.27.
|
|
47
|
-
"@shivaedev/test-story": "0.
|
|
45
|
+
"@shivaedev/effect-test-sql": "0.6.0",
|
|
46
|
+
"@shivaedev/quality": "0.27.1",
|
|
47
|
+
"@shivaedev/test-story": "0.10.0",
|
|
48
48
|
"@types/node": "24.19.2",
|
|
49
49
|
"effect": "4.0.4",
|
|
50
50
|
"pg-boss": "12.37.1",
|
package/src/server/client.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface PgBossClient {
|
|
|
19
19
|
readonly findJobs?: (name: string, options?: FindJobsOptions) => Promise<readonly JobWithMetadata<unknown>[]>;
|
|
20
20
|
readonly getDb?: PgBoss["getDb"];
|
|
21
21
|
readonly getQueue: (name: string) => Promise<QueueResult | null>;
|
|
22
|
+
readonly getWipData?: PgBoss["getWipData"];
|
|
23
|
+
readonly notifyWorker?: PgBoss["notifyWorker"];
|
|
22
24
|
readonly off: (event: "error", listener: (error: Error) => void) => unknown;
|
|
23
25
|
readonly offWork: (name: string) => Promise<void>;
|
|
24
26
|
readonly on: (event: "error", listener: (error: Error) => void) => unknown;
|
|
@@ -8,7 +8,12 @@ function failureOutput(cause: Cause.Cause<unknown>): object {
|
|
|
8
8
|
return typeof error === "object" && error !== null ? error : { message: String(error) };
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
export function batchHandler(
|
|
11
|
+
export function batchHandler(
|
|
12
|
+
client: PgBossClient,
|
|
13
|
+
name: string,
|
|
14
|
+
run: (job: Job<unknown>) => Effect.Effect<unknown, unknown>,
|
|
15
|
+
afterFailure?: (job: Job<unknown>) => Promise<void>,
|
|
16
|
+
) {
|
|
12
17
|
const complete = client.complete?.bind(client);
|
|
13
18
|
const fail = client.fail?.bind(client);
|
|
14
19
|
if (complete === undefined || fail === undefined) {
|
|
@@ -37,6 +42,7 @@ export function batchHandler(client: PgBossClient, name: string, run: (job: Job<
|
|
|
37
42
|
await complete(name, job);
|
|
38
43
|
} else {
|
|
39
44
|
await fail(name, job, failureOutput(exit.cause));
|
|
45
|
+
await afterFailure?.(job);
|
|
40
46
|
}
|
|
41
47
|
}
|
|
42
48
|
if (expired) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Context, Effect, Redacted, Schema } from "effect";
|
|
1
|
+
import { type Context, Effect, Redacted, Schema, type Scope } from "effect";
|
|
2
2
|
import type { Job } from "pg-boss";
|
|
3
3
|
import type { PgBossClient } from "#client.ts";
|
|
4
4
|
import {
|
|
@@ -10,8 +10,8 @@ import {
|
|
|
10
10
|
type ScheduledWorker,
|
|
11
11
|
} from "#definition.ts";
|
|
12
12
|
import { PgBossError, PgBossPayloadError, PgBossQueueOptionsError, toPgBossError } from "#error.ts";
|
|
13
|
-
import { batchHandler } from "#internal/batchHandler.ts";
|
|
14
13
|
import { ensureQueue } from "#internal/ensureQueue.ts";
|
|
14
|
+
import { registerWorker } from "#internal/registerWorker.ts";
|
|
15
15
|
import { payloadOf, traceJob } from "#internal/tracing.ts";
|
|
16
16
|
|
|
17
17
|
function isQueueWorker(registration: JobRegistration): registration is QueueWorker {
|
|
@@ -81,25 +81,28 @@ function runQueueWorker(worker: QueueWorker, job: Job<unknown>, context: Context
|
|
|
81
81
|
);
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
async function registerQueue(
|
|
84
|
+
async function registerQueue(
|
|
85
|
+
client: PgBossClient,
|
|
86
|
+
registration: QueueWorker | QueueDefinition,
|
|
87
|
+
context: Context.Context<unknown>,
|
|
88
|
+
scope: Scope.Scope,
|
|
89
|
+
): Promise<void> {
|
|
85
90
|
const queue = registration._tag === "QueueWorker" ? registration.queue : registration;
|
|
86
91
|
const name = queue.name;
|
|
87
92
|
if (registration._tag === "QueueDefinition") {
|
|
88
93
|
return;
|
|
89
94
|
}
|
|
90
|
-
await client.
|
|
91
|
-
name,
|
|
92
|
-
{ ...queue.workerOptions, includeMetadata: true },
|
|
93
|
-
batchHandler(client, name, (job) => runQueueWorker(registration, job, context)),
|
|
94
|
-
);
|
|
95
|
+
await registerWorker(client, name, queue.workerOptions, (job) => runQueueWorker(registration, job, context), scope);
|
|
95
96
|
}
|
|
96
97
|
|
|
97
|
-
async function registerSchedule(client: PgBossClient, worker: ScheduledWorker, context: Context.Context<unknown
|
|
98
|
+
async function registerSchedule(client: PgBossClient, worker: ScheduledWorker, context: Context.Context<unknown>, scope: Scope.Scope): Promise<void> {
|
|
98
99
|
const { schedule } = worker;
|
|
99
|
-
await
|
|
100
|
+
await registerWorker(
|
|
101
|
+
client,
|
|
100
102
|
schedule.name,
|
|
101
|
-
|
|
102
|
-
|
|
103
|
+
schedule.workerOptions,
|
|
104
|
+
(job) => Effect.provide(traceJob(worker.effect, job, schedule.name), context),
|
|
105
|
+
scope,
|
|
103
106
|
);
|
|
104
107
|
await client.schedule(schedule.name, schedule.cron, null, schedule.scheduleOptions);
|
|
105
108
|
}
|
|
@@ -117,19 +120,21 @@ export const registerJobs = <R>(
|
|
|
117
120
|
registrations: readonly JobRegistration[],
|
|
118
121
|
context: Context.Context<R>,
|
|
119
122
|
replaceWorkers: boolean,
|
|
120
|
-
): Effect.Effect<void, PgBossError | PgBossQueueOptionsError> =>
|
|
121
|
-
Effect.
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
123
|
+
): Effect.Effect<void, PgBossError | PgBossQueueOptionsError, Scope.Scope> =>
|
|
124
|
+
Effect.flatMap(Effect.scope, (scope) =>
|
|
125
|
+
Effect.tryPromise({
|
|
126
|
+
catch: (error) => (error instanceof PgBossQueueOptionsError || error instanceof PgBossError ? error : toPgBossError("register", error)),
|
|
127
|
+
try: async () => {
|
|
128
|
+
registrationNames(registrations);
|
|
129
|
+
await prepareQueues(client, registrations, replaceWorkers);
|
|
130
|
+
const provided = workerContext(context);
|
|
131
|
+
for (const registration of registrations) {
|
|
132
|
+
if (isQueueWorker(registration) || isQueueDefinition(registration)) {
|
|
133
|
+
await registerQueue(client, registration, provided, scope);
|
|
134
|
+
} else if (isScheduledWorker(registration)) {
|
|
135
|
+
await registerSchedule(client, registration, provided, scope);
|
|
136
|
+
}
|
|
132
137
|
}
|
|
133
|
-
}
|
|
134
|
-
},
|
|
135
|
-
|
|
138
|
+
},
|
|
139
|
+
}),
|
|
140
|
+
);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Clock, Effect, type Scope } from "effect";
|
|
2
|
+
import type { Job, WorkOptions } from "pg-boss";
|
|
3
|
+
import type { PgBossClient } from "#client.ts";
|
|
4
|
+
import { batchHandler } from "#internal/batchHandler.ts";
|
|
5
|
+
|
|
6
|
+
export function registerWorker(
|
|
7
|
+
client: PgBossClient,
|
|
8
|
+
name: string,
|
|
9
|
+
options: WorkOptions,
|
|
10
|
+
run: (job: Job<unknown>) => Effect.Effect<unknown, unknown>,
|
|
11
|
+
scope: Scope.Scope,
|
|
12
|
+
): Promise<string> {
|
|
13
|
+
const registration = client.work(
|
|
14
|
+
name,
|
|
15
|
+
{ ...options, includeMetadata: true },
|
|
16
|
+
batchHandler(client, name, run, async (attempt) => {
|
|
17
|
+
if (client.findJobs === undefined || client.notifyWorker === undefined) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const job = (await client.findJobs(name, { id: attempt.id }))[0];
|
|
21
|
+
if (job?.state !== "retry") {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const workId = await registration;
|
|
25
|
+
await Effect.runPromise(
|
|
26
|
+
Effect.gen(function* () {
|
|
27
|
+
const now = yield* Clock.currentTimeMillis;
|
|
28
|
+
// PostgreSQL timestamps retain sub-millisecond precision that Date drops.
|
|
29
|
+
yield* Effect.sleep(Math.max(0, job.startAfter.getTime() + 1 - now));
|
|
30
|
+
const workerIds = client
|
|
31
|
+
.getWipData?.()
|
|
32
|
+
.filter((worker) => worker.workId === workId)
|
|
33
|
+
.map((worker) => worker.id) ?? [workId];
|
|
34
|
+
for (const workerId of workerIds) {
|
|
35
|
+
client.notifyWorker?.(workerId);
|
|
36
|
+
}
|
|
37
|
+
}).pipe(Effect.forkIn(scope)),
|
|
38
|
+
);
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
41
|
+
return registration;
|
|
42
|
+
}
|