@aphexcms/cms-core 9.6.0 → 9.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/dist/api/documents.d.ts +28 -0
- package/dist/api/documents.d.ts.map +1 -1
- package/dist/api/documents.js +18 -0
- package/dist/api/schemas/documents.d.ts +19 -0
- package/dist/api/schemas/documents.d.ts.map +1 -1
- package/dist/api/schemas/documents.js +18 -0
- package/dist/client/ui.d.ts +1 -0
- package/dist/client/ui.d.ts.map +1 -1
- package/dist/client/ui.js +2 -0
- package/dist/components/admin/ActivityView.svelte +227 -0
- package/dist/components/admin/ActivityView.svelte.d.ts +4 -0
- package/dist/components/admin/ActivityView.svelte.d.ts.map +1 -0
- package/dist/components/admin/DocumentEditor.svelte +196 -10
- package/dist/components/admin/DocumentEditor.svelte.d.ts.map +1 -1
- package/dist/components/admin/ScheduleDialog.svelte +174 -0
- package/dist/components/admin/ScheduleDialog.svelte.d.ts +20 -0
- package/dist/components/admin/ScheduleDialog.svelte.d.ts.map +1 -0
- package/dist/components/layout/OrganizationSwitcher.svelte +3 -3
- package/dist/components/layout/sidebar/NavUser.svelte +5 -5
- package/dist/db/interfaces/events.d.ts +55 -0
- package/dist/db/interfaces/events.d.ts.map +1 -0
- package/dist/db/interfaces/events.js +1 -0
- package/dist/db/interfaces/index.d.ts +10 -2
- package/dist/db/interfaces/index.d.ts.map +1 -1
- package/dist/db/interfaces/plugin-storage.d.ts +39 -0
- package/dist/db/interfaces/plugin-storage.d.ts.map +1 -0
- package/dist/db/interfaces/plugin-storage.js +1 -0
- package/dist/events/catalog.d.ts +8 -0
- package/dist/events/catalog.d.ts.map +1 -0
- package/dist/events/catalog.js +11 -0
- package/dist/events/consumer.d.ts +79 -0
- package/dist/events/consumer.d.ts.map +1 -0
- package/dist/events/consumer.js +76 -0
- package/dist/events/define-event.d.ts +17 -0
- package/dist/events/define-event.d.ts.map +1 -0
- package/dist/events/define-event.js +7 -0
- package/dist/events/emit.d.ts +11 -0
- package/dist/events/emit.d.ts.map +1 -0
- package/dist/events/emit.js +20 -0
- package/dist/events/index.d.ts +4 -0
- package/dist/events/index.d.ts.map +1 -0
- package/dist/events/index.js +3 -0
- package/dist/field-validation/rule.d.ts.map +1 -1
- package/dist/field-validation/rule.js +15 -0
- package/dist/forms/define-form.d.ts +25 -0
- package/dist/forms/define-form.d.ts.map +1 -0
- package/dist/forms/define-form.js +22 -0
- package/dist/forms/index.d.ts +4 -0
- package/dist/forms/index.d.ts.map +1 -0
- package/dist/forms/index.js +5 -0
- package/dist/forms/types.d.ts +49 -0
- package/dist/forms/types.d.ts.map +1 -0
- package/dist/forms/types.js +1 -0
- package/dist/forms/validate.d.ts +9 -0
- package/dist/forms/validate.d.ts.map +1 -0
- package/dist/forms/validate.js +18 -0
- package/dist/hooks.d.ts.map +1 -1
- package/dist/hooks.js +15 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/jobs/document-jobs.d.ts +27 -0
- package/dist/jobs/document-jobs.d.ts.map +1 -0
- package/dist/jobs/document-jobs.js +42 -0
- package/dist/jobs/embedded-runner.d.ts +25 -0
- package/dist/jobs/embedded-runner.d.ts.map +1 -0
- package/dist/jobs/embedded-runner.js +46 -0
- package/dist/jobs/index.d.ts +7 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +8 -0
- package/dist/jobs/relay.d.ts +27 -0
- package/dist/jobs/relay.d.ts.map +1 -0
- package/dist/jobs/relay.js +60 -0
- package/dist/jobs/run-batch.d.ts +52 -0
- package/dist/jobs/run-batch.d.ts.map +1 -0
- package/dist/jobs/run-batch.js +61 -0
- package/dist/jobs/run-due-jobs.d.ts +30 -0
- package/dist/jobs/run-due-jobs.d.ts.map +1 -0
- package/dist/jobs/run-due-jobs.js +69 -0
- package/dist/jobs/types.d.ts +18 -0
- package/dist/jobs/types.d.ts.map +1 -0
- package/dist/jobs/types.js +1 -0
- package/dist/lib/api/documents.d.ts +28 -0
- package/dist/lib/api/documents.d.ts.map +1 -1
- package/dist/lib/api/documents.js +18 -0
- package/dist/lib/api/documents.js.map +1 -1
- package/dist/lib/api/schemas/documents.d.ts +19 -0
- package/dist/lib/api/schemas/documents.d.ts.map +1 -1
- package/dist/lib/api/schemas/documents.js +18 -0
- package/dist/lib/api/schemas/documents.js.map +1 -1
- package/dist/lib/client/ui.d.ts +1 -0
- package/dist/lib/client/ui.d.ts.map +1 -1
- package/dist/lib/client/ui.js +2 -0
- package/dist/lib/client/ui.js.map +1 -1
- package/dist/lib/db/interfaces/events.d.ts +55 -0
- package/dist/lib/db/interfaces/events.d.ts.map +1 -0
- package/dist/lib/db/interfaces/events.js +2 -0
- package/dist/lib/db/interfaces/events.js.map +1 -0
- package/dist/lib/db/interfaces/index.d.ts +10 -2
- package/dist/lib/db/interfaces/index.d.ts.map +1 -1
- package/dist/lib/db/interfaces/plugin-storage.d.ts +39 -0
- package/dist/lib/db/interfaces/plugin-storage.d.ts.map +1 -0
- package/dist/lib/db/interfaces/plugin-storage.js +2 -0
- package/dist/lib/db/interfaces/plugin-storage.js.map +1 -0
- package/dist/lib/events/catalog.d.ts +8 -0
- package/dist/lib/events/catalog.d.ts.map +1 -0
- package/dist/lib/events/catalog.js +12 -0
- package/dist/lib/events/catalog.js.map +1 -0
- package/dist/lib/events/consumer.d.ts +79 -0
- package/dist/lib/events/consumer.d.ts.map +1 -0
- package/dist/lib/events/consumer.js +77 -0
- package/dist/lib/events/consumer.js.map +1 -0
- package/dist/lib/events/define-event.d.ts +17 -0
- package/dist/lib/events/define-event.d.ts.map +1 -0
- package/dist/lib/events/define-event.js +8 -0
- package/dist/lib/events/define-event.js.map +1 -0
- package/dist/lib/events/emit.d.ts +11 -0
- package/dist/lib/events/emit.d.ts.map +1 -0
- package/dist/lib/events/emit.js +21 -0
- package/dist/lib/events/emit.js.map +1 -0
- package/dist/lib/events/index.d.ts +4 -0
- package/dist/lib/events/index.d.ts.map +1 -0
- package/dist/lib/events/index.js +4 -0
- package/dist/lib/events/index.js.map +1 -0
- package/dist/lib/field-validation/rule.d.ts.map +1 -1
- package/dist/lib/field-validation/rule.js +15 -0
- package/dist/lib/field-validation/rule.js.map +1 -1
- package/dist/lib/forms/define-form.d.ts +25 -0
- package/dist/lib/forms/define-form.d.ts.map +1 -0
- package/dist/lib/forms/define-form.js +23 -0
- package/dist/lib/forms/define-form.js.map +1 -0
- package/dist/lib/forms/index.d.ts +4 -0
- package/dist/lib/forms/index.d.ts.map +1 -0
- package/dist/lib/forms/index.js +6 -0
- package/dist/lib/forms/index.js.map +1 -0
- package/dist/lib/forms/types.d.ts +49 -0
- package/dist/lib/forms/types.d.ts.map +1 -0
- package/dist/lib/forms/types.js +2 -0
- package/dist/lib/forms/types.js.map +1 -0
- package/dist/lib/forms/validate.d.ts +9 -0
- package/dist/lib/forms/validate.d.ts.map +1 -0
- package/dist/lib/forms/validate.js +19 -0
- package/dist/lib/forms/validate.js.map +1 -0
- package/dist/lib/hooks.d.ts.map +1 -1
- package/dist/lib/hooks.js +15 -0
- package/dist/lib/hooks.js.map +1 -1
- package/dist/lib/index.d.ts +2 -0
- package/dist/lib/index.d.ts.map +1 -1
- package/dist/lib/index.js +6 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/jobs/document-jobs.d.ts +27 -0
- package/dist/lib/jobs/document-jobs.d.ts.map +1 -0
- package/dist/lib/jobs/document-jobs.js +43 -0
- package/dist/lib/jobs/document-jobs.js.map +1 -0
- package/dist/lib/jobs/embedded-runner.d.ts +25 -0
- package/dist/lib/jobs/embedded-runner.d.ts.map +1 -0
- package/dist/lib/jobs/embedded-runner.js +47 -0
- package/dist/lib/jobs/embedded-runner.js.map +1 -0
- package/dist/lib/jobs/index.d.ts +7 -0
- package/dist/lib/jobs/index.d.ts.map +1 -0
- package/dist/lib/jobs/index.js +9 -0
- package/dist/lib/jobs/index.js.map +1 -0
- package/dist/lib/jobs/relay.d.ts +27 -0
- package/dist/lib/jobs/relay.d.ts.map +1 -0
- package/dist/lib/jobs/relay.js +61 -0
- package/dist/lib/jobs/relay.js.map +1 -0
- package/dist/lib/jobs/run-batch.d.ts +52 -0
- package/dist/lib/jobs/run-batch.d.ts.map +1 -0
- package/dist/lib/jobs/run-batch.js +62 -0
- package/dist/lib/jobs/run-batch.js.map +1 -0
- package/dist/lib/jobs/run-due-jobs.d.ts +30 -0
- package/dist/lib/jobs/run-due-jobs.d.ts.map +1 -0
- package/dist/lib/jobs/run-due-jobs.js +70 -0
- package/dist/lib/jobs/run-due-jobs.js.map +1 -0
- package/dist/lib/jobs/types.d.ts +18 -0
- package/dist/lib/jobs/types.d.ts.map +1 -0
- package/dist/lib/jobs/types.js +2 -0
- package/dist/lib/jobs/types.js.map +1 -0
- package/dist/lib/local-api/collection-api.d.ts +42 -0
- package/dist/lib/local-api/collection-api.d.ts.map +1 -1
- package/dist/lib/local-api/collection-api.js +179 -20
- package/dist/lib/local-api/collection-api.js.map +1 -1
- package/dist/lib/plugins/resolver.d.ts +12 -1
- package/dist/lib/plugins/resolver.d.ts.map +1 -1
- package/dist/lib/plugins/resolver.js +4 -1
- package/dist/lib/plugins/resolver.js.map +1 -1
- package/dist/lib/plugins/types.d.ts +47 -2
- package/dist/lib/plugins/types.d.ts.map +1 -1
- package/dist/lib/plugins/types.js.map +1 -1
- package/dist/lib/server/api/index.d.ts.map +1 -1
- package/dist/lib/server/api/index.js +8 -0
- package/dist/lib/server/api/index.js.map +1 -1
- package/dist/lib/server/api/routes/documents-publish.d.ts.map +1 -1
- package/dist/lib/server/api/routes/documents-publish.js +110 -0
- package/dist/lib/server/api/routes/documents-publish.js.map +1 -1
- package/dist/lib/server/api/routes/jobs.d.ts +4 -0
- package/dist/lib/server/api/routes/jobs.d.ts.map +1 -0
- package/dist/lib/server/api/routes/jobs.js +93 -0
- package/dist/lib/server/api/routes/jobs.js.map +1 -0
- package/dist/lib/server/api/routes/workers-run.d.ts +4 -0
- package/dist/lib/server/api/routes/workers-run.d.ts.map +1 -0
- package/dist/lib/server/api/routes/workers-run.js +41 -0
- package/dist/lib/server/api/routes/workers-run.js.map +1 -0
- package/dist/lib/server/index.d.ts +1 -0
- package/dist/lib/server/index.d.ts.map +1 -1
- package/dist/lib/server/index.js +2 -0
- package/dist/lib/server/index.js.map +1 -1
- package/dist/lib/services/version-service.d.ts +16 -0
- package/dist/lib/services/version-service.d.ts.map +1 -1
- package/dist/lib/services/version-service.js +68 -66
- package/dist/lib/services/version-service.js.map +1 -1
- package/dist/lib/types/config.d.ts +43 -0
- package/dist/lib/types/config.d.ts.map +1 -1
- package/dist/lib/types/events.d.ts +134 -0
- package/dist/lib/types/events.d.ts.map +1 -0
- package/dist/lib/types/events.js +4 -0
- package/dist/lib/types/events.js.map +1 -0
- package/dist/lib/types/index.d.ts +1 -0
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/types/index.js +1 -0
- package/dist/lib/types/index.js.map +1 -1
- package/dist/lib/utils/index.d.ts +1 -1
- package/dist/lib/utils/index.d.ts.map +1 -1
- package/dist/lib/utils/index.js.map +1 -1
- package/dist/local-api/collection-api.d.ts +42 -0
- package/dist/local-api/collection-api.d.ts.map +1 -1
- package/dist/local-api/collection-api.js +179 -20
- package/dist/plugins/resolver.d.ts +12 -1
- package/dist/plugins/resolver.d.ts.map +1 -1
- package/dist/plugins/resolver.js +4 -1
- package/dist/plugins/types.d.ts +47 -2
- package/dist/plugins/types.d.ts.map +1 -1
- package/dist/server/api/index.d.ts.map +1 -1
- package/dist/server/api/index.js +8 -0
- package/dist/server/api/routes/documents-publish.d.ts.map +1 -1
- package/dist/server/api/routes/documents-publish.js +110 -0
- package/dist/server/api/routes/jobs.d.ts +4 -0
- package/dist/server/api/routes/jobs.d.ts.map +1 -0
- package/dist/server/api/routes/jobs.js +92 -0
- package/dist/server/api/routes/workers-run.d.ts +4 -0
- package/dist/server/api/routes/workers-run.d.ts.map +1 -0
- package/dist/server/api/routes/workers-run.js +40 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +2 -0
- package/dist/services/version-service.d.ts +16 -0
- package/dist/services/version-service.d.ts.map +1 -1
- package/dist/services/version-service.js +68 -66
- package/dist/types/config.d.ts +43 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/events.d.ts +134 -0
- package/dist/types/events.d.ts.map +1 -0
- package/dist/types/events.js +3 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Job execution — the durable spine's runner. Plain TS (no Svelte), safe to import
|
|
2
|
+
// from the server barrel. Handlers and scheduling are wired via `CMSConfig.jobs`.
|
|
3
|
+
export * from './types.js';
|
|
4
|
+
export * from './run-due-jobs.js';
|
|
5
|
+
export * from './relay.js';
|
|
6
|
+
export * from './run-batch.js';
|
|
7
|
+
export * from './document-jobs.js';
|
|
8
|
+
export * from './embedded-runner.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/lib/jobs/index.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,kFAAkF;AAClF,cAAc,SAAS,CAAC;AACxB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,SAAS,CAAC;AACxB,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Logger } from '../utils/logger.js';
|
|
2
|
+
import type { DatabaseAdapter } from '../db/interfaces/index.js';
|
|
3
|
+
import type { PartResolver } from '../plugins/resolver.js';
|
|
4
|
+
/** The slice of the service container the relay needs — a structural subset of `JobRunnerServices`. */
|
|
5
|
+
export interface RelayServices {
|
|
6
|
+
databaseAdapter: DatabaseAdapter;
|
|
7
|
+
logger: Logger;
|
|
8
|
+
partResolver: PartResolver;
|
|
9
|
+
}
|
|
10
|
+
export interface RelayOutboxOptions {
|
|
11
|
+
/** Scope to one tenant; omit to relay across all orgs (worker context, override access). */
|
|
12
|
+
organizationId?: string;
|
|
13
|
+
/** Max outbox rows drained this pass. Default 100 (fan-out is cheap; relay generously). */
|
|
14
|
+
batchSize?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface RelayOutboxResult {
|
|
17
|
+
/** Outbox rows processed this pass. */
|
|
18
|
+
relayed: number;
|
|
19
|
+
/** Delivery jobs enqueued (deduped enqueues still count as one each). */
|
|
20
|
+
enqueued: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Drain one bounded batch of the outbox, fanning each event out to its subscribed consumers.
|
|
24
|
+
* Runs one pass and returns — the caller (the same tick as `runJobsBatch`) owns cadence.
|
|
25
|
+
*/
|
|
26
|
+
export declare function relayOutbox(services: RelayServices, options?: RelayOutboxOptions): Promise<RelayOutboxResult>;
|
|
27
|
+
//# sourceMappingURL=relay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/relay.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGxD,uGAAuG;AACvG,MAAM,WAAW,aAAa;IAC7B,eAAe,EAAE,eAAe,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IAClC,4FAA4F;IAC5F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,QAAQ,EAAE,MAAM,CAAC;CACjB;AAID;;;GAGG;AACH,wBAAsB,WAAW,CAChC,QAAQ,EAAE,aAAa,EACvB,OAAO,GAAE,kBAAuB,GAC9B,OAAO,CAAC,iBAAiB,CAAC,CA6D5B"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { consumerJobType, toDeliveryPayload } from '../events/consumer.js';
|
|
2
|
+
const DEFAULT_RELAY_BATCH_SIZE = 100;
|
|
3
|
+
/**
|
|
4
|
+
* Drain one bounded batch of the outbox, fanning each event out to its subscribed consumers.
|
|
5
|
+
* Runs one pass and returns — the caller (the same tick as `runJobsBatch`) owns cadence.
|
|
6
|
+
*/
|
|
7
|
+
export async function relayOutbox(services, options = {}) {
|
|
8
|
+
const { databaseAdapter, logger, partResolver } = services;
|
|
9
|
+
const batchSize = options.batchSize ?? DEFAULT_RELAY_BATCH_SIZE;
|
|
10
|
+
const rows = await databaseAdapter.listUnprocessedOutbox({
|
|
11
|
+
organizationId: options.organizationId,
|
|
12
|
+
limit: batchSize
|
|
13
|
+
});
|
|
14
|
+
const result = { relayed: 0, enqueued: 0 };
|
|
15
|
+
for (const row of rows) {
|
|
16
|
+
const consumers = partResolver.consumersForEvent(row.eventType);
|
|
17
|
+
// A row with no subscribers is still marked processed — the relay's contract is "every
|
|
18
|
+
// event is considered", not "every event produces a job". Nobody listening is a valid
|
|
19
|
+
// outcome, and leaving it pending would re-scan it forever.
|
|
20
|
+
const event = {
|
|
21
|
+
id: row.eventId,
|
|
22
|
+
type: row.eventType,
|
|
23
|
+
organizationId: row.organizationId,
|
|
24
|
+
payload: row.payload,
|
|
25
|
+
correlationId: row.correlationId,
|
|
26
|
+
causationId: row.causationId,
|
|
27
|
+
createdBy: row.createdBy,
|
|
28
|
+
createdAt: row.createdAt
|
|
29
|
+
};
|
|
30
|
+
const payload = toDeliveryPayload(event);
|
|
31
|
+
try {
|
|
32
|
+
await databaseAdapter.withTransaction(async (tx) => {
|
|
33
|
+
for (const consumer of consumers) {
|
|
34
|
+
await tx.scheduleJob({
|
|
35
|
+
organizationId: row.organizationId,
|
|
36
|
+
type: consumerJobType(consumer.id),
|
|
37
|
+
payload,
|
|
38
|
+
// Exactly-once per (event, consumer): a repeated key returns the existing job.
|
|
39
|
+
idempotencyKey: `evt:${row.eventId}:${consumer.id}`,
|
|
40
|
+
maxAttempts: consumer.maxAttempts,
|
|
41
|
+
correlationId: row.correlationId,
|
|
42
|
+
// The event is the cause of every delivery it spawns — chain it for tracing.
|
|
43
|
+
causationId: row.eventId,
|
|
44
|
+
createdBy: row.createdBy
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
await tx.markOutboxProcessed(row.organizationId, row.id);
|
|
48
|
+
});
|
|
49
|
+
result.relayed++;
|
|
50
|
+
result.enqueued += consumers.length;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
// Leave the row unprocessed; the next pass retries it. Idempotent enqueue makes a
|
|
54
|
+
// partial failure safe to redo. Log and continue so one bad row can't stall the batch.
|
|
55
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
56
|
+
logger.error('[relay]', `Failed to relay event ${row.eventId} (${row.eventType}); will retry next pass: ${message}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=relay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relay.js","sourceRoot":"","sources":["../../../src/lib/jobs/relay.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAsB,MAAM,oBAAoB,CAAC;AAuB5F,MAAM,wBAAwB,GAAG,GAAG,CAAC;AAErC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,QAAuB,EACvB,UAA8B,EAAE;IAEhC,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,QAAQ,CAAC;IAC3D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,wBAAwB,CAAC;IAEhE,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,qBAAqB,CAAC;QACxD,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,KAAK,EAAE,SAAS;KAChB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAsB,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAE9D,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,YAAY,CAAC,iBAAiB,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAEhE,uFAAuF;QACvF,sFAAsF;QACtF,4DAA4D;QAC5D,MAAM,KAAK,GAAkB;YAC5B,EAAE,EAAE,GAAG,CAAC,OAAO;YACf,IAAI,EAAE,GAAG,CAAC,SAAS;YACnB,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,aAAa,EAAE,GAAG,CAAC,aAAa;YAChC,WAAW,EAAE,GAAG,CAAC,WAAW;YAC5B,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,SAAS,EAAE,GAAG,CAAC,SAAS;SACxB,CAAC;QACF,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;QAEzC,IAAI,CAAC;YACJ,MAAM,eAAe,CAAC,eAAe,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;gBAClD,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;oBAClC,MAAM,EAAE,CAAC,WAAW,CAAC;wBACpB,cAAc,EAAE,GAAG,CAAC,cAAc;wBAClC,IAAI,EAAE,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;wBAClC,OAAO;wBACP,+EAA+E;wBAC/E,cAAc,EAAE,OAAO,GAAG,CAAC,OAAO,IAAI,QAAQ,CAAC,EAAE,EAAE;wBACnD,WAAW,EAAE,QAAQ,CAAC,WAAW;wBACjC,aAAa,EAAE,GAAG,CAAC,aAAa;wBAChC,6EAA6E;wBAC7E,WAAW,EAAE,GAAG,CAAC,OAAO;wBACxB,SAAS,EAAE,GAAG,CAAC,SAAS;qBACxB,CAAC,CAAC;gBACJ,CAAC;gBACD,MAAM,EAAE,CAAC,mBAAmB,CAAC,GAAG,CAAC,cAAc,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;YAC1D,CAAC,CAAC,CAAC;YACH,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,CAAC,QAAQ,IAAI,SAAS,CAAC,MAAM,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,kFAAkF;YAClF,uFAAuF;YACvF,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,MAAM,CAAC,KAAK,CACX,SAAS,EACT,yBAAyB,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,SAAS,4BAA4B,OAAO,EAAE,CAC3F,CAAC;QACH,CAAC;IACF,CAAC;IAED,OAAO,MAAM,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from '../db/interfaces/index.js';
|
|
2
|
+
import type { EmailAdapter } from '../email/interfaces/email.js';
|
|
3
|
+
import type { Logger } from '../utils/logger.js';
|
|
4
|
+
import type { CMSConfig } from '../types/config.js';
|
|
5
|
+
import type { LocalAPI } from '../local-api/index.js';
|
|
6
|
+
import type { PartResolver } from '../plugins/resolver.js';
|
|
7
|
+
import { type RunDueJobsResult } from './run-due-jobs.js';
|
|
8
|
+
import { type RelayOutboxResult } from './relay.js';
|
|
9
|
+
import { type PluginSettingsReader } from '../events/consumer.js';
|
|
10
|
+
/**
|
|
11
|
+
* The slice of the CMS service container the runner needs. Structurally a subset
|
|
12
|
+
* of `CMSInstances`, so callers can pass `event.locals.aphexCMS` (or `c.var.aphexCMS`)
|
|
13
|
+
* straight through — no adapter, no cast.
|
|
14
|
+
*/
|
|
15
|
+
export interface JobRunnerServices {
|
|
16
|
+
config: CMSConfig;
|
|
17
|
+
databaseAdapter: DatabaseAdapter;
|
|
18
|
+
logger: Logger;
|
|
19
|
+
localAPI: LocalAPI;
|
|
20
|
+
partResolver: PartResolver;
|
|
21
|
+
/** Injected into event-consumer deliveries so a consumer can read its own decrypted settings. */
|
|
22
|
+
pluginSettingsService: PluginSettingsReader;
|
|
23
|
+
/** Handed to event consumers that send notifications; `null`/absent when email isn't configured. */
|
|
24
|
+
emailAdapter?: EmailAdapter | null;
|
|
25
|
+
}
|
|
26
|
+
export interface RunJobsBatchOptions {
|
|
27
|
+
/** Lease-owner label written to `cms_jobs.lease_owner` (crash-recovery visibility). */
|
|
28
|
+
workerId?: string;
|
|
29
|
+
/** Scope to one tenant; omit to claim across all orgs (worker context, override access). */
|
|
30
|
+
organizationId?: string;
|
|
31
|
+
}
|
|
32
|
+
/** One tick's combined outcome: the relay fan-out plus the job execution that followed. */
|
|
33
|
+
export interface RunJobsBatchResult extends RunDueJobsResult {
|
|
34
|
+
/** Outbox fan-out done at the top of this tick (events → delivery jobs). */
|
|
35
|
+
relay: RelayOutboxResult;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Run one full worker tick: relay the outbox, then run one bounded batch of due jobs with the
|
|
39
|
+
* fully-assembled handler map.
|
|
40
|
+
*
|
|
41
|
+
* Relaying FIRST means a delivery job an event spawns this tick is already `pending` when the
|
|
42
|
+
* job pass runs, so a just-published document's consumers can fire in the same tick rather than
|
|
43
|
+
* waiting for the next — at the cost of nothing, since a slow consumer is still its own job.
|
|
44
|
+
*
|
|
45
|
+
* Handler precedence (later wins): core's built-in handlers (scheduled publish/unpublish) →
|
|
46
|
+
* plugin event-consumer deliveries (`aphex/consumer:<id>`) → plugin job handlers
|
|
47
|
+
* (`aphex/job/handler`) → the app's `config.jobs.handlers`. So an app can override a plugin,
|
|
48
|
+
* and a plugin can override a built-in — the app always has the final say. Consumer delivery
|
|
49
|
+
* types are namespaced, so they can't actually collide with the others.
|
|
50
|
+
*/
|
|
51
|
+
export declare function runJobsBatch(services: JobRunnerServices, options?: RunJobsBatchOptions): Promise<RunJobsBatchResult>;
|
|
52
|
+
//# sourceMappingURL=run-batch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-batch.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/run-batch.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAExD,OAAO,EAAc,KAAK,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAe,KAAK,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE9D,OAAO,EAGN,KAAK,oBAAoB,EACzB,MAAM,oBAAoB,CAAC;AAE5B;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,SAAS,CAAC;IAClB,eAAe,EAAE,eAAe,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,YAAY,CAAC;IAC3B,iGAAiG;IACjG,qBAAqB,EAAE,oBAAoB,CAAC;IAC5C,oGAAoG;IACpG,YAAY,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;CACnC;AAED,MAAM,WAAW,mBAAmB;IACnC,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,4FAA4F;IAC5F,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,2FAA2F;AAC3F,MAAM,WAAW,kBAAmB,SAAQ,gBAAgB;IAC3D,4EAA4E;IAC5E,KAAK,EAAE,iBAAiB,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CACjC,QAAQ,EAAE,iBAAiB,EAC3B,OAAO,GAAE,mBAAwB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CAqC7B"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// The shared job-runner seam. Both the protected HTTP endpoint
|
|
2
|
+
// (`POST /api/internal/workers/run`) and the embedded in-process poll loop call
|
|
3
|
+
// THIS — never `runDueJobs` directly — so the handler wiring (built-in document
|
|
4
|
+
// jobs + app-registered handlers) is constructed in exactly one place and can
|
|
5
|
+
// never drift between the two invocation modes.
|
|
6
|
+
//
|
|
7
|
+
// `runDueJobs` is the pure engine (claim → run → settle, one batch). This wrapper
|
|
8
|
+
// is the only thing that knows *which* handlers exist and pulls the per-run knobs
|
|
9
|
+
// off `CMSConfig.jobs`.
|
|
10
|
+
import { randomUUID } from 'node:crypto';
|
|
11
|
+
import { runDueJobs } from './run-due-jobs.js';
|
|
12
|
+
import { relayOutbox } from './relay.js';
|
|
13
|
+
import { createDocumentJobHandlers } from './document-jobs.js';
|
|
14
|
+
import { consumerJobType, toConsumerJobHandler } from '../events/consumer.js';
|
|
15
|
+
/**
|
|
16
|
+
* Run one full worker tick: relay the outbox, then run one bounded batch of due jobs with the
|
|
17
|
+
* fully-assembled handler map.
|
|
18
|
+
*
|
|
19
|
+
* Relaying FIRST means a delivery job an event spawns this tick is already `pending` when the
|
|
20
|
+
* job pass runs, so a just-published document's consumers can fire in the same tick rather than
|
|
21
|
+
* waiting for the next — at the cost of nothing, since a slow consumer is still its own job.
|
|
22
|
+
*
|
|
23
|
+
* Handler precedence (later wins): core's built-in handlers (scheduled publish/unpublish) →
|
|
24
|
+
* plugin event-consumer deliveries (`aphex/consumer:<id>`) → plugin job handlers
|
|
25
|
+
* (`aphex/job/handler`) → the app's `config.jobs.handlers`. So an app can override a plugin,
|
|
26
|
+
* and a plugin can override a built-in — the app always has the final say. Consumer delivery
|
|
27
|
+
* types are namespaced, so they can't actually collide with the others.
|
|
28
|
+
*/
|
|
29
|
+
export async function runJobsBatch(services, options = {}) {
|
|
30
|
+
const { config, databaseAdapter, logger, localAPI, partResolver, pluginSettingsService } = services;
|
|
31
|
+
const emailAdapter = services.emailAdapter ?? null;
|
|
32
|
+
const relay = await relayOutbox(services, {
|
|
33
|
+
organizationId: options.organizationId,
|
|
34
|
+
batchSize: config.jobs?.relayBatchSize
|
|
35
|
+
});
|
|
36
|
+
// Turn each registered consumer into a delivery job handler, keyed by its reserved job type.
|
|
37
|
+
// Built here (not in the resolver) because the wrapper injects live services — the settings
|
|
38
|
+
// reader that lets a consumer read its own decrypted config.
|
|
39
|
+
const consumerHandlers = {};
|
|
40
|
+
for (const consumer of partResolver.eventConsumers()) {
|
|
41
|
+
consumerHandlers[consumerJobType(consumer.id)] = toConsumerJobHandler(consumer.handler, {
|
|
42
|
+
pluginSettingsService,
|
|
43
|
+
emailAdapter
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
const jobs = await runDueJobs({
|
|
47
|
+
databaseAdapter,
|
|
48
|
+
handlers: {
|
|
49
|
+
...createDocumentJobHandlers({ localAPI }),
|
|
50
|
+
...consumerHandlers,
|
|
51
|
+
...partResolver.jobHandlers(),
|
|
52
|
+
...(config.jobs?.handlers ?? {})
|
|
53
|
+
},
|
|
54
|
+
logger,
|
|
55
|
+
workerId: options.workerId ?? `runner-${randomUUID()}`,
|
|
56
|
+
organizationId: options.organizationId,
|
|
57
|
+
batchSize: config.jobs?.batchSize,
|
|
58
|
+
leaseMs: config.jobs?.leaseMs
|
|
59
|
+
});
|
|
60
|
+
return { ...jobs, relay };
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=run-batch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-batch.js","sourceRoot":"","sources":["../../../src/lib/jobs/run-batch.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,gFAAgF;AAChF,gFAAgF;AAChF,8EAA8E;AAC9E,gDAAgD;AAChD,EAAE;AACF,kFAAkF;AAClF,kFAAkF;AAClF,wBAAwB;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQzC,OAAO,EAAE,UAAU,EAAyB,MAAM,gBAAgB,CAAC;AACnE,OAAO,EAAE,WAAW,EAA0B,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EACN,eAAe,EACf,oBAAoB,EAEpB,MAAM,oBAAoB,CAAC;AAgC5B;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CACjC,QAA2B,EAC3B,UAA+B,EAAE;IAEjC,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,EAAE,qBAAqB,EAAE,GACvF,QAAQ,CAAC;IACV,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,IAAI,IAAI,CAAC;IAEnD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE;QACzC,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,cAAc;KACtC,CAAC,CAAC;IAEH,6FAA6F;IAC7F,4FAA4F;IAC5F,6DAA6D;IAC7D,MAAM,gBAAgB,GAAkB,EAAE,CAAC;IAC3C,KAAK,MAAM,QAAQ,IAAI,YAAY,CAAC,cAAc,EAAE,EAAE,CAAC;QACtD,gBAAgB,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,GAAG,oBAAoB,CAAC,QAAQ,CAAC,OAAO,EAAE;YACvF,qBAAqB;YACrB,YAAY;SACZ,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,UAAU,CAAC;QAC7B,eAAe;QACf,QAAQ,EAAE;YACT,GAAG,yBAAyB,CAAC,EAAE,QAAQ,EAAE,CAAC;YAC1C,GAAG,gBAAgB;YACnB,GAAG,YAAY,CAAC,WAAW,EAAE;YAC7B,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,IAAI,EAAE,CAAC;SAChC;QACD,MAAM;QACN,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,UAAU,UAAU,EAAE,EAAE;QACtD,cAAc,EAAE,OAAO,CAAC,cAAc;QACtC,SAAS,EAAE,MAAM,CAAC,IAAI,EAAE,SAAS;QACjC,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO;KAC7B,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from '../db/interfaces/index.js';
|
|
2
|
+
import type { Logger } from '../utils/logger.js';
|
|
3
|
+
import type { JobHandlerMap } from './types.js';
|
|
4
|
+
export interface RunDueJobsOptions {
|
|
5
|
+
databaseAdapter: DatabaseAdapter;
|
|
6
|
+
handlers: JobHandlerMap;
|
|
7
|
+
logger: Logger;
|
|
8
|
+
/** Identifies the lease owner in `cms_jobs.lease_owner` (for crash-recovery visibility). */
|
|
9
|
+
workerId: string;
|
|
10
|
+
/** Scope to one tenant; omit to claim across all orgs (worker context, override access). */
|
|
11
|
+
organizationId?: string;
|
|
12
|
+
/** Max jobs claimed this batch. Default 10. */
|
|
13
|
+
batchSize?: number;
|
|
14
|
+
/** Lease duration (ms) before a claimed-but-unfinished job is reclaimable. Default 30000. */
|
|
15
|
+
leaseMs?: number;
|
|
16
|
+
/** First-retry delay (ms); doubles per attempt. Default 1000. */
|
|
17
|
+
baseBackoffMs?: number;
|
|
18
|
+
/** Backoff ceiling (ms). Default 1h. */
|
|
19
|
+
maxBackoffMs?: number;
|
|
20
|
+
/** Injectable clock (tests). Default `new Date()`. */
|
|
21
|
+
now?: Date;
|
|
22
|
+
}
|
|
23
|
+
export interface RunDueJobsResult {
|
|
24
|
+
claimed: number;
|
|
25
|
+
completed: number;
|
|
26
|
+
retried: number;
|
|
27
|
+
failed: number;
|
|
28
|
+
}
|
|
29
|
+
export declare function runDueJobs(options: RunDueJobsOptions): Promise<RunDueJobsResult>;
|
|
30
|
+
//# sourceMappingURL=run-due-jobs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-due-jobs.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/run-due-jobs.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,MAAM,WAAW,iBAAiB;IACjC,eAAe,EAAE,eAAe,CAAC;IACjC,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,4FAA4F;IAC5F,QAAQ,EAAE,MAAM,CAAC;IACjB,4FAA4F;IAC5F,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6FAA6F;IAC7F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sDAAsD;IACtD,GAAG,CAAC,EAAE,IAAI,CAAC;CACX;AAED,MAAM,WAAW,gBAAgB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CACf;AAkBD,wBAAsB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAmEtF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const DEFAULT_BATCH_SIZE = 10;
|
|
2
|
+
const DEFAULT_LEASE_MS = 30_000;
|
|
3
|
+
const DEFAULT_BASE_BACKOFF_MS = 1_000;
|
|
4
|
+
const DEFAULT_MAX_BACKOFF_MS = 60 * 60 * 1_000;
|
|
5
|
+
/**
|
|
6
|
+
* Exponential backoff with jitter. `attempts` is 1-based (the claim already bumped it),
|
|
7
|
+
* so the first retry waits ~base, the second ~2×base, capped at `max`. Up to 25% of
|
|
8
|
+
* extra jitter spreads retries so a batch that failed together doesn't re-thunder as one.
|
|
9
|
+
*/
|
|
10
|
+
function backoffMs(attempts, base, max) {
|
|
11
|
+
const exp = Math.min(max, base * 2 ** (attempts - 1));
|
|
12
|
+
const jitter = Math.random() * exp * 0.25;
|
|
13
|
+
return Math.min(max, exp + jitter);
|
|
14
|
+
}
|
|
15
|
+
export async function runDueJobs(options) {
|
|
16
|
+
const { databaseAdapter, handlers, logger, workerId, organizationId } = options;
|
|
17
|
+
const batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
18
|
+
const leaseMs = options.leaseMs ?? DEFAULT_LEASE_MS;
|
|
19
|
+
const baseBackoffMs = options.baseBackoffMs ?? DEFAULT_BASE_BACKOFF_MS;
|
|
20
|
+
const maxBackoffMs = options.maxBackoffMs ?? DEFAULT_MAX_BACKOFF_MS;
|
|
21
|
+
const now = options.now ?? new Date();
|
|
22
|
+
const claimed = await databaseAdapter.claimDueJobs({
|
|
23
|
+
organizationId,
|
|
24
|
+
limit: batchSize,
|
|
25
|
+
workerId,
|
|
26
|
+
leaseMs,
|
|
27
|
+
now
|
|
28
|
+
});
|
|
29
|
+
const result = {
|
|
30
|
+
claimed: claimed.length,
|
|
31
|
+
completed: 0,
|
|
32
|
+
retried: 0,
|
|
33
|
+
failed: 0
|
|
34
|
+
};
|
|
35
|
+
for (const job of claimed) {
|
|
36
|
+
const handler = handlers[job.type];
|
|
37
|
+
// Unknown type can never become runnable — dead-letter it now rather than burn retries.
|
|
38
|
+
if (!handler) {
|
|
39
|
+
logger.error('[jobs]', `No handler registered for job type "${job.type}" (job ${job.id}); dead-lettering.`);
|
|
40
|
+
await databaseAdapter.failJob(job.organizationId, job.id, {
|
|
41
|
+
error: `No handler registered for job type "${job.type}"`
|
|
42
|
+
});
|
|
43
|
+
result.failed++;
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
await handler({ job, databaseAdapter, logger });
|
|
48
|
+
await databaseAdapter.completeJob(job.organizationId, job.id);
|
|
49
|
+
result.completed++;
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
53
|
+
// `attempts` was incremented by the claim, so it already counts this run.
|
|
54
|
+
if (job.attempts >= job.maxAttempts) {
|
|
55
|
+
logger.error('[jobs]', `Job ${job.id} (${job.type}) failed permanently after ${job.attempts}/${job.maxAttempts} attempts: ${message}`);
|
|
56
|
+
await databaseAdapter.failJob(job.organizationId, job.id, { error: message });
|
|
57
|
+
result.failed++;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const delay = backoffMs(job.attempts, baseBackoffMs, maxBackoffMs);
|
|
61
|
+
const runAt = new Date(now.getTime() + delay);
|
|
62
|
+
logger.warn('[jobs]', `Job ${job.id} (${job.type}) failed (attempt ${job.attempts}/${job.maxAttempts}); retrying in ${Math.round(delay)}ms: ${message}`);
|
|
63
|
+
await databaseAdapter.retryJob(job.organizationId, job.id, { runAt, error: message });
|
|
64
|
+
result.retried++;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=run-due-jobs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-due-jobs.js","sourceRoot":"","sources":["../../../src/lib/jobs/run-due-jobs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from '../db/interfaces/index.js';
|
|
2
|
+
import type { Job } from '../types/events.js';
|
|
3
|
+
import type { Logger } from '../utils/logger.js';
|
|
4
|
+
/** What a job handler receives. `databaseAdapter` is the live adapter (org-scoped calls still take an org id). */
|
|
5
|
+
export interface JobContext {
|
|
6
|
+
job: Job;
|
|
7
|
+
databaseAdapter: DatabaseAdapter;
|
|
8
|
+
logger: Logger;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Runs one job. Resolve to complete it; throw to signal failure — the runner
|
|
12
|
+
* then retries with backoff (attempts remain) or dead-letters it (attempts exhausted).
|
|
13
|
+
* Handlers must be idempotent: at-least-once delivery means a job can run more than once.
|
|
14
|
+
*/
|
|
15
|
+
export type JobHandler = (ctx: JobContext) => Promise<void>;
|
|
16
|
+
/** Map of job `type` → handler. A claimed job whose type has no handler is dead-lettered. */
|
|
17
|
+
export type JobHandlerMap = Record<string, JobHandler>;
|
|
18
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/lib/jobs/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAE9C,kHAAkH;AAClH,MAAM,WAAW,UAAU;IAC1B,GAAG,EAAE,GAAG,CAAC;IACT,eAAe,EAAE,eAAe,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE5D,6FAA6F;AAC7F,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/lib/jobs/types.ts"],"names":[],"mappings":""}
|
|
@@ -9,6 +9,7 @@ import type { LocalAPIContext } from './types.js';
|
|
|
9
9
|
import type { SchemaType } from '../types/schemas.js';
|
|
10
10
|
import { PermissionChecker } from './permissions.js';
|
|
11
11
|
import { type DocumentValidationResult } from '../field-validation/utils.js';
|
|
12
|
+
import type { Job } from '../types/events.js';
|
|
12
13
|
/**
|
|
13
14
|
* Result from create/update operations that includes validation
|
|
14
15
|
*/
|
|
@@ -182,6 +183,13 @@ export declare class CollectionAPI<T = Document> {
|
|
|
182
183
|
* );
|
|
183
184
|
* ```
|
|
184
185
|
*/
|
|
186
|
+
/**
|
|
187
|
+
* Publish without a version snapshot — the branch taken when there's no version service or
|
|
188
|
+
* the caller passed `skipVersioning`. Still emits `document.published` (and its outbox row)
|
|
189
|
+
* atomically with the publish, so the domain fact fires on EVERY publish path, not only the
|
|
190
|
+
* versioned one. The versioned branch emits the same event from `versionService.publishTx`.
|
|
191
|
+
*/
|
|
192
|
+
private publishWithoutVersion;
|
|
185
193
|
publish(context: LocalAPIContext, id: string): Promise<T | null>;
|
|
186
194
|
/**
|
|
187
195
|
* Unpublish a document
|
|
@@ -195,5 +203,39 @@ export declare class CollectionAPI<T = Document> {
|
|
|
195
203
|
* ```
|
|
196
204
|
*/
|
|
197
205
|
unpublish(context: LocalAPIContext, id: string): Promise<T | null>;
|
|
206
|
+
/**
|
|
207
|
+
* Pending scheduled publish/unpublish jobs for one document. Scheduled jobs are few
|
|
208
|
+
* and `pending` is a small set, so filtering the org's pending jobs by documentId in
|
|
209
|
+
* memory is cheap and avoids a dialect-specific JSON query on the hot editor path.
|
|
210
|
+
*/
|
|
211
|
+
private pendingScheduledFor;
|
|
212
|
+
/**
|
|
213
|
+
* Cancel any pending schedule of ONE direction for a document — used when a manual
|
|
214
|
+
* publish/unpublish supersedes a schedule of the same kind. Only same-direction is
|
|
215
|
+
* cancelled on purpose: "publish now, auto-unpublish Friday" and "unpublish now,
|
|
216
|
+
* republish Monday" are legitimate future transitions, so a manual publish leaves a
|
|
217
|
+
* pending unpublish (and vice versa) alone. Without this, the queued job would fire at
|
|
218
|
+
* `runAt` and re-run the same transition — re-emitting `document.published`/`unpublished`
|
|
219
|
+
* and firing every consumer a second time (duplicate notifications, webhooks, cache busts).
|
|
220
|
+
*/
|
|
221
|
+
private cancelPendingScheduleOfType;
|
|
222
|
+
/**
|
|
223
|
+
* Schedule a publish for a future `runAt`. Enqueues a `document.publish` job; the
|
|
224
|
+
* worker runs `publish()` at that time (re-validating, guarding references, emitting
|
|
225
|
+
* `document.published`). The permission check happens NOW — you must be able to publish
|
|
226
|
+
* to schedule one — so an unauthorized caller can't queue work to run later as the system.
|
|
227
|
+
* Actual publish-time validation still runs then, so a doc that goes invalid before
|
|
228
|
+
* `runAt` simply fails/retries rather than publishing bad content.
|
|
229
|
+
*
|
|
230
|
+
* Replace semantics: any existing pending schedule for this document is cancelled first,
|
|
231
|
+
* so a document has at most one pending schedule (rescheduling can't double-publish).
|
|
232
|
+
*/
|
|
233
|
+
schedulePublish(context: LocalAPIContext, id: string, runAt: Date): Promise<Job>;
|
|
234
|
+
/** Schedule an unpublish for a future `runAt`. Permission-checked now; replaces any existing pending schedule. */
|
|
235
|
+
scheduleUnpublish(context: LocalAPIContext, id: string, runAt: Date): Promise<Job>;
|
|
236
|
+
/** Pending scheduled publish/unpublish jobs for a document (read-gated) — for the editor's schedule indicator. */
|
|
237
|
+
getScheduled(context: LocalAPIContext, id: string): Promise<Job[]>;
|
|
238
|
+
/** Cancel all pending scheduled publish/unpublish jobs for a document. Returns how many were cancelled. */
|
|
239
|
+
cancelScheduled(context: LocalAPIContext, id: string): Promise<number>;
|
|
198
240
|
}
|
|
199
241
|
//# sourceMappingURL=collection-api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"collection-api.d.ts","sourceRoot":"","sources":["../../../src/lib/local-api/collection-api.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAwB,KAAK,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"collection-api.d.ts","sourceRoot":"","sources":["../../../src/lib/local-api/collection-api.ts"],"names":[],"mappings":"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"}
|