@nest-boot/queue-api 0.0.0-stage → 8.1.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.
Files changed (36) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -2
  3. package/dist/connections/job.connection-definition.d.ts +9 -0
  4. package/dist/connections/job.connection-definition.js +50 -0
  5. package/dist/connections/job.connection-definition.js.map +1 -0
  6. package/dist/decorators/queue-visible.decorator.d.ts +14 -0
  7. package/dist/decorators/queue-visible.decorator.js +20 -0
  8. package/dist/decorators/queue-visible.decorator.js.map +1 -0
  9. package/dist/entities/index.d.ts +4 -0
  10. package/dist/entities/index.js +5 -0
  11. package/dist/entities/index.js.map +1 -0
  12. package/dist/entities/job.entity.d.ts +24 -0
  13. package/dist/entities/job.entity.js +128 -0
  14. package/dist/entities/job.entity.js.map +1 -0
  15. package/dist/enums/job-status.enum.d.ts +19 -0
  16. package/dist/enums/job-status.enum.js +23 -0
  17. package/dist/enums/job-status.enum.js.map +1 -0
  18. package/dist/index.d.ts +7 -0
  19. package/dist/index.js +8 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/processors/job.processor.d.ts +18 -0
  22. package/dist/processors/job.processor.js +111 -0
  23. package/dist/processors/job.processor.js.map +1 -0
  24. package/dist/queue-api.module.d.ts +3 -0
  25. package/dist/queue-api.module.js +25 -0
  26. package/dist/queue-api.module.js.map +1 -0
  27. package/dist/queues/job.queue.d.ts +32 -0
  28. package/dist/queues/job.queue.js +65 -0
  29. package/dist/queues/job.queue.js.map +1 -0
  30. package/dist/resolvers/job.resolver.d.ts +54 -0
  31. package/dist/resolvers/job.resolver.js +145 -0
  32. package/dist/resolvers/job.resolver.js.map +1 -0
  33. package/dist/services/job.service.d.ts +77 -0
  34. package/dist/services/job.service.js +276 -0
  35. package/dist/services/job.service.js.map +1 -0
  36. package/package.json +115 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 nest-boot
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,116 @@
1
- # Temporary Holding Version
1
+ # @nest-boot/queue-api
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Optional Job history and authenticated GraphQL queries for
4
+ [`@nest-boot/queue`](../queue/README.md). Redis remains responsible for queue state
5
+ and processing; the database stores asynchronous history snapshots.
6
+
7
+ ## Setup and visibility
8
+
9
+ Configure the application's global DatabaseModule, GraphQLModule and AuthModule,
10
+ then import QueueApiModule. It reuses those configured modules, imports QueueModule
11
+ and does not depend on `@nest-boot/schedule`. Register JobEntity in both runtime
12
+ and MikroORM CLI entity lists and create its table through application migrations.
13
+ The database generates UUID IDs; `(queue, jobId)` identifies the source Redis job.
14
+
15
+ Register queue providers in the API application and mark each visible queue:
16
+
17
+ ```ts
18
+ import { BaseQueue, Queue } from "@nest-boot/queue";
19
+ import { QueueApiModule, QueueVisible } from "@nest-boot/queue-api";
20
+ import { Module } from "@nestjs/common";
21
+
22
+ @QueueVisible()
23
+ @Queue()
24
+ export class EmailQueue extends BaseQueue {}
25
+
26
+ @Module({
27
+ imports: [QueueApiModule],
28
+ providers: [EmailQueue],
29
+ })
30
+ export class EmailModule {}
31
+ ```
32
+
33
+ `@QueueVisible()` takes no arguments. Each concrete class needs its own marker;
34
+ subclasses do not inherit visibility. Unmarked or unregistered queues are excluded
35
+ from single-record reads, page nodes and counts, including explicit client
36
+ filters. An empty visible set returns no records. Visibility does not change
37
+ synchronization, retention or authorization.
38
+
39
+ ## Queries and authorization
40
+
41
+ Every query uses AuthGuard. JobService reads trusted request identity and applies
42
+ the same visibility and ownership constraints to single records, pages and counts:
43
+
44
+ | Query | Access scope |
45
+ | -------------------------------- | ----------------------------------------------------------------------------------------- |
46
+ | `userJob` / `userJobs` | `data.userId` matches the current user |
47
+ | `workspaceJob` / `workspaceJobs` | `data.workspaceId` matches the selected workspace after membership and read authorization |
48
+ | `systemJob` / `systemJobs` | Both owner fields are absent or JSON null, with administrator authorization |
49
+
50
+ System reads use AuthModule's configured `user.adminRoles`. API keys do not inherit
51
+ their owner's administrator access. Empty strings count as present owner values.
52
+ User and workspace scopes can overlap when a task carries both IDs. Missing
53
+ identity or unauthorized workspace access is rejected.
54
+
55
+ JobService exposes `getUserJob`, `getWorkspaceJob`, `getSystemJob` and their
56
+ `get*JobConnection` variants. It injects EntityManager directly and exposes no
57
+ generic CRUD or unscoped query. Job history has no database RLS; direct ORM access
58
+ is a trusted internal operation, so request handlers use the scoped methods.
59
+
60
+ GraphQL exposes `id`, `queue`, `name`, `status`, finite numeric `progress`,
61
+ `createdAt`, `startedAt` and `finishedAt`. Other progress values return null.
62
+ Payloads, results, errors, native job IDs and event versions remain private.
63
+ Connections support queue, name, status and creation-time filters. CREATED_AT is
64
+ the only selectable sort key and defaults to descending; UUID breaks timestamp
65
+ ties internally. User/workspace expression indexes and a partial system index
66
+ support these scoped cursor reads.
67
+
68
+ ## Synchronization and retention
69
+
70
+ JobService subscribes to registered queues before their event readers start,
71
+ including producer-only instances. It forwards snapshots to the built-in `job`
72
+ queue, deduplicating qualified source names and Redis Stream IDs for 24 hours.
73
+ The Job worker compares bigint `(lastEventMs, lastEventSeq)` pairs atomically and
74
+ only applies newer events. Events from its own queue are excluded to prevent
75
+ recursion. Database write failures retry up to 20 times with exponential backoff.
76
+
77
+ Readers use BullMQ's default starting position without startup replay. Connection
78
+ readiness does not guarantee that the first stream read has started. Retain source
79
+ jobs long enough to capture full snapshots; when a source job is already removed,
80
+ only metadata carried by the event remains available.
81
+
82
+ Start all registered consumers with `nb queue:start`, or use
83
+ `nb queue:start --queue job` for synchronization and cleanup alone. When filtering,
84
+ select `job` explicitly in the process intended to persist history. Shutdown drains
85
+ source Workers, then event readers and pending submissions, then the Job Worker.
86
+
87
+ The built-in JobQueue handles `sync` and `cleanup`. One shared BullMQ scheduler on
88
+ the `job` queue runs cleanup daily at 00:00 UTC. Cleanup deletes records inactive
89
+ for more than 30 days in guarded batches of 1000, regardless of status. Records
90
+ without an applied event use `createdAt`. Redis jobs remain intact; later events
91
+ recreate deleted records with a new UUID. Cleanup requires the Job Worker.
92
+
93
+ ## Tests
94
+
95
+ Unit tests sit beside their source files. End-to-end suites live in `test/`:
96
+
97
+ - `job.resolver`: visibility, ownership, authorization, filters and cursors through HTTP.
98
+ - `job-queries`: synchronized Redis history through the GraphQL API.
99
+ - `job.processor`: atomic event ordering and retention against PostgreSQL.
100
+ - `job.service`: producer-only event forwarding without historical replay.
101
+ - `job.entity`: schema, UUID defaults, bigint columns and query indexes.
102
+ - `queue-api`: multiple application instances, deduplication, retries and shutdown.
103
+
104
+ Build before running end-to-end tests because they import the package output:
105
+
106
+ ```bash
107
+ pnpm --filter @nest-boot/queue-api build
108
+ pnpm --filter @nest-boot/queue-api test
109
+ REDIS_URL=redis://localhost:6379 \
110
+ QUEUE_TEST_DATABASE_URL=postgresql://postgres:postgres@localhost:5432/postgres \
111
+ pnpm --filter @nest-boot/queue-api test:e2e
112
+ ```
113
+
114
+ Each database suite creates and removes its own database; the PostgreSQL test user
115
+ needs permission to create databases and the shared `authenticated` test role.
116
+ Redis suites use isolated prefixes and remove their own keys.
@@ -0,0 +1,9 @@
1
+ import { Job as JobEntity } from "../entities/job.entity.js";
2
+ declare const Connection: import("@nestjs/common").Type<import("@nest-boot/graphql-connection").ConnectionInterface<JobEntity>>, ConnectionArgs: import("@nestjs/common").Type<import("@nest-boot/graphql-connection").ConnectionArgsInterface<JobEntity>>;
3
+ /** Cursor pagination, filters and creation-time ordering for visible jobs. */
4
+ export declare class JobConnectionArgs extends ConnectionArgs {
5
+ }
6
+ /** Cross-queue Job records within the current authorized scope. */
7
+ export declare class JobConnection extends Connection {
8
+ }
9
+ export {};
@@ -0,0 +1,50 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { ArgsType, ObjectType } from "@nest-boot/graphql";
8
+ import { ConnectionBuilder } from "@nest-boot/graphql-connection";
9
+ import { Job as JobEntity } from "../entities/job.entity.js";
10
+ const { Connection, ConnectionArgs } = new ConnectionBuilder(JobEntity)
11
+ .addField({ field: "id", type: "string", sortable: false })
12
+ .addField({
13
+ field: "queue",
14
+ type: "string",
15
+ filterable: true,
16
+ })
17
+ .addField({
18
+ field: "name",
19
+ type: "string",
20
+ filterable: true,
21
+ searchable: true,
22
+ })
23
+ .addField({
24
+ field: "status",
25
+ type: "string",
26
+ filterable: true,
27
+ })
28
+ .addField({
29
+ field: "created_at",
30
+ replacement: "createdAt",
31
+ type: "date",
32
+ filterable: true,
33
+ sortable: true,
34
+ })
35
+ .build();
36
+ /** Cursor pagination, filters and creation-time ordering for visible jobs. */
37
+ let JobConnectionArgs = class JobConnectionArgs extends ConnectionArgs {
38
+ };
39
+ JobConnectionArgs = __decorate([
40
+ ArgsType()
41
+ ], JobConnectionArgs);
42
+ export { JobConnectionArgs };
43
+ /** Cross-queue Job records within the current authorized scope. */
44
+ let JobConnection = class JobConnection extends Connection {
45
+ };
46
+ JobConnection = __decorate([
47
+ ObjectType()
48
+ ], JobConnection);
49
+ export { JobConnection };
50
+ //# sourceMappingURL=job.connection-definition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.connection-definition.js","sourceRoot":"","sources":["../../src/connections/job.connection-definition.ts"],"names":[],"mappings":";;;;;;AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAElE,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAE7D,MAAM,EAAE,UAAU,EAAE,cAAc,EAAE,GAAG,IAAI,iBAAiB,CAAC,SAAS,CAAC;KACpE,QAAQ,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;KAC1D,QAAQ,CAAC;IACR,KAAK,EAAE,OAAO;IACd,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,IAAI;CACjB,CAAC;KACD,QAAQ,CAAC;IACR,KAAK,EAAE,MAAM;IACb,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,IAAI;IAChB,UAAU,EAAE,IAAI;CACjB,CAAC;KACD,QAAQ,CAAC;IACR,KAAK,EAAE,QAAQ;IACf,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,IAAI;CACjB,CAAC;KACD,QAAQ,CAAC;IACR,KAAK,EAAE,YAAY;IACnB,WAAW,EAAE,WAAW;IACxB,IAAI,EAAE,MAAM;IACZ,UAAU,EAAE,IAAI;IAChB,QAAQ,EAAE,IAAI;CACf,CAAC;KACD,KAAK,EAAE,CAAC;AAEX,8EAA8E;AAEvE,IAAM,iBAAiB,GAAvB,MAAM,iBAAkB,SAAQ,cAAc;CAAG,CAAA;AAA3C,iBAAiB;IAD7B,QAAQ,EAAE;GACE,iBAAiB,CAA0B;;AAExD,mEAAmE;AAE5D,IAAM,aAAa,GAAnB,MAAM,aAAc,SAAQ,UAAU;CAAG,CAAA;AAAnC,aAAa;IADzB,UAAU,EAAE;GACA,aAAa,CAAsB"}
@@ -0,0 +1,14 @@
1
+ import type { BaseQueue } from "@nest-boot/queue";
2
+ import type { Type } from "@nestjs/common";
3
+ /**
4
+ * Allows a registered queue's Job records to appear in scoped API queries.
5
+ * @returns Queue class decorator. Authorization still applies to every query.
6
+ */
7
+ export declare function QueueVisible(): (target: Type<BaseQueue>) => void;
8
+ /**
9
+ * Checks whether a queue class explicitly enables API queries.
10
+ * @param queue - Registered queue instance.
11
+ * @returns Whether the concrete queue class has its own visibility marker.
12
+ * @internal
13
+ */
14
+ export declare function isQueueVisible(queue: BaseQueue): boolean;
@@ -0,0 +1,20 @@
1
+ const QUEUE_VISIBLE = Symbol("QUEUE_VISIBLE");
2
+ /**
3
+ * Allows a registered queue's Job records to appear in scoped API queries.
4
+ * @returns Queue class decorator. Authorization still applies to every query.
5
+ */
6
+ export function QueueVisible() {
7
+ return (target) => {
8
+ Reflect.defineMetadata(QUEUE_VISIBLE, true, target);
9
+ };
10
+ }
11
+ /**
12
+ * Checks whether a queue class explicitly enables API queries.
13
+ * @param queue - Registered queue instance.
14
+ * @returns Whether the concrete queue class has its own visibility marker.
15
+ * @internal
16
+ */
17
+ export function isQueueVisible(queue) {
18
+ return Reflect.getOwnMetadata(QUEUE_VISIBLE, queue.constructor) === true;
19
+ }
20
+ //# sourceMappingURL=queue-visible.decorator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-visible.decorator.js","sourceRoot":"","sources":["../../src/decorators/queue-visible.decorator.ts"],"names":[],"mappings":"AAGA,MAAM,aAAa,GAAG,MAAM,CAAC,eAAe,CAAC,CAAC;AAE9C;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,CAAC,MAAuB,EAAQ,EAAE;QACvC,OAAO,CAAC,cAAc,CAAC,aAAa,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACtD,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,KAAgB;IAC7C,OAAO,OAAO,CAAC,cAAc,CAAC,aAAa,EAAE,KAAK,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;AAC3E,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { Job as JobEntity } from "./job.entity.js";
2
+ export { Job as JobEntity } from "./job.entity.js";
3
+ /** Job history entities; Redis owns all queue operational state. */
4
+ export declare const entities: (typeof JobEntity)[];
@@ -0,0 +1,5 @@
1
+ import { Job as JobEntity } from "./job.entity.js";
2
+ export { Job as JobEntity } from "./job.entity.js";
3
+ /** Job history entities; Redis owns all queue operational state. */
4
+ export const entities = [JobEntity];
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/entities/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACnD,OAAO,EAAE,GAAG,IAAI,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAEnD,oEAAoE;AACpE,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { JobProgress } from "bullmq";
2
+ import { JobStatus } from "../enums/job-status.enum.js";
3
+ /** Database history synchronized from Redis QueueEvents by the Job worker. */
4
+ export declare class Job {
5
+ /** Database-generated UUID, stable across synchronization events. */
6
+ id: string;
7
+ /** Queue name of the source Redis job. */
8
+ queue: string;
9
+ /** Original BullMQ identifier, unique within its queue. */
10
+ jobId: string;
11
+ name: string;
12
+ data: Record<string, unknown>;
13
+ status: JobStatus;
14
+ progress: JobProgress | null;
15
+ returnValue: unknown;
16
+ failedReason: string | null;
17
+ createdAt: Date;
18
+ startedAt: Date | null;
19
+ finishedAt: Date | null;
20
+ /** Millisecond component of the latest applied Redis Stream ID. */
21
+ lastEventMs: bigint;
22
+ /** Sequence component of the latest applied Redis Stream ID. */
23
+ lastEventSeq: bigint;
24
+ }
@@ -0,0 +1,128 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ /* eslint-disable @nest-boot/graphql-field-config-from-types -- Persist arbitrary progress but expose only numeric values via the resolver. */
11
+ /* eslint-disable @nest-boot/entity-property-config-from-types -- History uses explicit SQL UUID, JSON and bigint types. */
12
+ import { BigIntType, t } from "@mikro-orm/core";
13
+ import { Entity, Enum, Index, PrimaryKey, Property, Unique, } from "@mikro-orm/decorators/legacy";
14
+ import { Field, Float, HideField, ID, ObjectType } from "@nest-boot/graphql";
15
+ import { JobStatus } from "../enums/job-status.enum.js";
16
+ /** Database history synchronized from Redis QueueEvents by the Job worker. */
17
+ let Job = class Job {
18
+ /** Database-generated UUID, stable across synchronization events. */
19
+ id;
20
+ /** Queue name of the source Redis job. */
21
+ queue;
22
+ /** Original BullMQ identifier, unique within its queue. */
23
+ jobId;
24
+ name;
25
+ data;
26
+ status;
27
+ progress;
28
+ returnValue;
29
+ failedReason;
30
+ createdAt;
31
+ startedAt;
32
+ finishedAt;
33
+ /** Millisecond component of the latest applied Redis Stream ID. */
34
+ lastEventMs;
35
+ /** Sequence component of the latest applied Redis Stream ID. */
36
+ lastEventSeq;
37
+ };
38
+ __decorate([
39
+ PrimaryKey({ type: t.uuid, defaultRaw: "gen_random_uuid()" }),
40
+ Field(() => ID),
41
+ __metadata("design:type", String)
42
+ ], Job.prototype, "id", void 0);
43
+ __decorate([
44
+ Property({ type: t.text }),
45
+ Field(() => String),
46
+ __metadata("design:type", String)
47
+ ], Job.prototype, "queue", void 0);
48
+ __decorate([
49
+ Property({ type: t.text }),
50
+ HideField(),
51
+ __metadata("design:type", String)
52
+ ], Job.prototype, "jobId", void 0);
53
+ __decorate([
54
+ Property({ type: t.text }),
55
+ Field(() => String),
56
+ __metadata("design:type", String)
57
+ ], Job.prototype, "name", void 0);
58
+ __decorate([
59
+ Property({ type: t.json, defaultRaw: "'{}'::jsonb" }),
60
+ HideField(),
61
+ __metadata("design:type", Object)
62
+ ], Job.prototype, "data", void 0);
63
+ __decorate([
64
+ Enum({ items: () => JobStatus }),
65
+ Field(() => JobStatus),
66
+ __metadata("design:type", String)
67
+ ], Job.prototype, "status", void 0);
68
+ __decorate([
69
+ Property({ type: t.json, nullable: true }),
70
+ Field(() => Float, { nullable: true }),
71
+ __metadata("design:type", Object)
72
+ ], Job.prototype, "progress", void 0);
73
+ __decorate([
74
+ Property({ type: t.json, nullable: true }),
75
+ HideField(),
76
+ __metadata("design:type", Object)
77
+ ], Job.prototype, "returnValue", void 0);
78
+ __decorate([
79
+ Property({ type: t.text, nullable: true }),
80
+ HideField(),
81
+ __metadata("design:type", Object)
82
+ ], Job.prototype, "failedReason", void 0);
83
+ __decorate([
84
+ Property({ type: t.datetime }),
85
+ Field(() => Date),
86
+ __metadata("design:type", Date)
87
+ ], Job.prototype, "createdAt", void 0);
88
+ __decorate([
89
+ Property({ type: t.datetime, nullable: true }),
90
+ Field(() => Date, { nullable: true }),
91
+ __metadata("design:type", Object)
92
+ ], Job.prototype, "startedAt", void 0);
93
+ __decorate([
94
+ Property({ type: t.datetime, nullable: true }),
95
+ Field(() => Date, { nullable: true }),
96
+ __metadata("design:type", Object)
97
+ ], Job.prototype, "finishedAt", void 0);
98
+ __decorate([
99
+ Property({ type: new BigIntType("bigint"), default: 0 }),
100
+ HideField(),
101
+ __metadata("design:type", BigInt)
102
+ ], Job.prototype, "lastEventMs", void 0);
103
+ __decorate([
104
+ Property({ type: new BigIntType("bigint"), default: 0 }),
105
+ HideField(),
106
+ __metadata("design:type", BigInt)
107
+ ], Job.prototype, "lastEventSeq", void 0);
108
+ Job = __decorate([
109
+ ObjectType(),
110
+ Entity(),
111
+ Unique({ properties: ["queue", "jobId"] }),
112
+ Index({
113
+ columns: [{ name: "data.userId" }, { name: "createdAt" }, { name: "id" }],
114
+ }),
115
+ Index({
116
+ columns: [
117
+ { name: "data.workspaceId" },
118
+ { name: "createdAt" },
119
+ { name: "id" },
120
+ ],
121
+ }),
122
+ Index({
123
+ properties: ["createdAt", "id"],
124
+ where: `"data"->>'userId' is null and "data"->>'workspaceId' is null`,
125
+ })
126
+ ], Job);
127
+ export { Job };
128
+ //# sourceMappingURL=job.entity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.entity.js","sourceRoot":"","sources":["../../src/entities/job.entity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ /** BullMQ job state values, shared by the entity and GraphQL API. */
2
+ export declare enum JobStatus {
3
+ /** Job is waiting in the Redis prioritized set. */
4
+ PRIORITIZED = "prioritized",
5
+ /** No source job state could be recovered from Redis. */
6
+ UNKNOWN = "unknown",
7
+ /** Job is waiting to be processed, without a priority. */
8
+ WAITING = "waiting",
9
+ /** Job is actively being processed. */
10
+ ACTIVE = "active",
11
+ /** Job has completed successfully. */
12
+ COMPLETED = "completed",
13
+ /** Job has failed; it may be retried according to its retry policy. */
14
+ FAILED = "failed",
15
+ /** Job is delayed and will be processed later. */
16
+ DELAYED = "delayed",
17
+ /** Job is waiting for its child jobs to complete. */
18
+ WAITING_CHILDREN = "waiting-children"
19
+ }
@@ -0,0 +1,23 @@
1
+ import { registerEnumType } from "@nest-boot/graphql";
2
+ /** BullMQ job state values, shared by the entity and GraphQL API. */
3
+ export var JobStatus;
4
+ (function (JobStatus) {
5
+ /** Job is waiting in the Redis prioritized set. */
6
+ JobStatus["PRIORITIZED"] = "prioritized";
7
+ /** No source job state could be recovered from Redis. */
8
+ JobStatus["UNKNOWN"] = "unknown";
9
+ /** Job is waiting to be processed, without a priority. */
10
+ JobStatus["WAITING"] = "waiting";
11
+ /** Job is actively being processed. */
12
+ JobStatus["ACTIVE"] = "active";
13
+ /** Job has completed successfully. */
14
+ JobStatus["COMPLETED"] = "completed";
15
+ /** Job has failed; it may be retried according to its retry policy. */
16
+ JobStatus["FAILED"] = "failed";
17
+ /** Job is delayed and will be processed later. */
18
+ JobStatus["DELAYED"] = "delayed";
19
+ /** Job is waiting for its child jobs to complete. */
20
+ JobStatus["WAITING_CHILDREN"] = "waiting-children";
21
+ })(JobStatus || (JobStatus = {}));
22
+ registerEnumType(JobStatus, { name: "JobStatus" });
23
+ //# sourceMappingURL=job-status.enum.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-status.enum.js","sourceRoot":"","sources":["../../src/enums/job-status.enum.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,qEAAqE;AACrE,MAAM,CAAN,IAAY,SAiBX;AAjBD,WAAY,SAAS;IACnB,mDAAmD;IACnD,wCAA2B,CAAA;IAC3B,yDAAyD;IACzD,gCAAmB,CAAA;IACnB,0DAA0D;IAC1D,gCAAmB,CAAA;IACnB,uCAAuC;IACvC,8BAAiB,CAAA;IACjB,sCAAsC;IACtC,oCAAuB,CAAA;IACvB,uEAAuE;IACvE,8BAAiB,CAAA;IACjB,kDAAkD;IAClD,gCAAmB,CAAA;IACnB,qDAAqD;IACrD,kDAAqC,CAAA;AACvC,CAAC,EAjBW,SAAS,KAAT,SAAS,QAiBpB;AAED,gBAAgB,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export * from "./connections/job.connection-definition.js";
2
+ export { QueueVisible } from "./decorators/queue-visible.decorator.js";
3
+ export * from "./entities/index.js";
4
+ export { JobStatus } from "./enums/job-status.enum.js";
5
+ export { QueueApiModule } from "./queue-api.module.js";
6
+ export { JobResolver } from "./resolvers/job.resolver.js";
7
+ export { JobService } from "./services/job.service.js";
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export * from "./connections/job.connection-definition.js";
2
+ export { QueueVisible } from "./decorators/queue-visible.decorator.js";
3
+ export * from "./entities/index.js";
4
+ export { JobStatus } from "./enums/job-status.enum.js";
5
+ export { QueueApiModule } from "./queue-api.module.js";
6
+ export { JobResolver } from "./resolvers/job.resolver.js";
7
+ export { JobService } from "./services/job.service.js";
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,4CAA4C,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AACvE,cAAc,qBAAqB,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { EntityManager } from "@mikro-orm/core";
2
+ import { BaseProcessor, type Job } from "@nest-boot/queue";
3
+ import { JobQueue } from "../queues/job.queue.js";
4
+ /** Synchronizes Job records and removes expired records. */
5
+ export declare class JobProcessor extends BaseProcessor {
6
+ private readonly em;
7
+ constructor(em: EntityManager);
8
+ /**
9
+ * Deletes records inactive for 30 days, falling back to their creation time.
10
+ * @param _job - Scheduled cleanup task.
11
+ */
12
+ processCleanup(_job: Job<JobQueue, "cleanup">): Promise<void>;
13
+ /**
14
+ * Inserts new history and applies only strictly newer events.
15
+ * @param job - Deduplicated synchronization job.
16
+ */
17
+ processSync(job: Job<JobQueue, "sync">): Promise<void>;
18
+ }
@@ -0,0 +1,111 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { EntityManager, } from "@mikro-orm/core";
11
+ import { BaseProcessor, Processor } from "@nest-boot/queue";
12
+ import { pick } from "lodash-es";
13
+ import { Job as JobEntity } from "../entities/job.entity.js";
14
+ import { JobStatus } from "../enums/job-status.enum.js";
15
+ import { JobQueue } from "../queues/job.queue.js";
16
+ /** Synchronizes Job records and removes expired records. */
17
+ let JobProcessor = class JobProcessor extends BaseProcessor {
18
+ em;
19
+ constructor(em) {
20
+ super();
21
+ this.em = em;
22
+ }
23
+ /**
24
+ * Deletes records inactive for 30 days, falling back to their creation time.
25
+ * @param _job - Scheduled cleanup task.
26
+ */
27
+ async processCleanup(_job) {
28
+ const em = this.em.fork({ disableContextResolution: true });
29
+ const cutoff = Date.now() - 30 * 24 * 60 * 60 * 1000;
30
+ const where = {
31
+ $or: [
32
+ { lastEventMs: { $gt: 0n, $lt: BigInt(cutoff) } },
33
+ { lastEventMs: 0n, createdAt: { $lt: new Date(cutoff) } },
34
+ ],
35
+ };
36
+ let lastId;
37
+ while (true) {
38
+ const rows = await em.find(JobEntity, { $and: [where, ...(lastId ? [{ id: { $gt: lastId } }] : [])] }, {
39
+ fields: ["id"],
40
+ orderBy: { id: "asc" },
41
+ limit: 1000,
42
+ disableIdentityMap: true,
43
+ });
44
+ if (!rows.length) {
45
+ return;
46
+ }
47
+ lastId = rows[rows.length - 1].id;
48
+ // Recheck eligibility so a concurrent event cannot delete a refreshed job.
49
+ await em.nativeDelete(JobEntity, {
50
+ $and: [where, { id: { $in: rows.map(({ id }) => id) } }],
51
+ });
52
+ }
53
+ }
54
+ /**
55
+ * Inserts new history and applies only strictly newer events.
56
+ * @param job - Deduplicated synchronization job.
57
+ */
58
+ async processSync(job) {
59
+ const { eventId, data: snapshot } = job.data;
60
+ const [ms, seq] = eventId.split("-");
61
+ const data = {
62
+ ...pick(snapshot, [
63
+ "queue",
64
+ "jobId",
65
+ "name",
66
+ "data",
67
+ "status",
68
+ "progress",
69
+ "returnValue",
70
+ "failedReason",
71
+ ]),
72
+ lastEventMs: BigInt(ms),
73
+ lastEventSeq: BigInt(seq),
74
+ };
75
+ for (const field of ["createdAt", "startedAt", "finishedAt"]) {
76
+ const timestamp = snapshot[field];
77
+ if (timestamp !== undefined) {
78
+ data[field] = timestamp === null ? null : new Date(timestamp);
79
+ }
80
+ }
81
+ const em = this.em.fork({ disableContextResolution: true });
82
+ // A concurrent insert must never overwrite an already newer version.
83
+ await em.upsert(JobEntity, {
84
+ name: "",
85
+ data: {},
86
+ status: JobStatus.UNKNOWN,
87
+ createdAt: new Date(Number(ms)),
88
+ ...data,
89
+ }, {
90
+ onConflictFields: ["queue", "jobId"],
91
+ onConflictAction: "ignore",
92
+ });
93
+ await em.nativeUpdate(JobEntity, {
94
+ queue: data.queue,
95
+ jobId: data.jobId,
96
+ $or: [
97
+ { lastEventMs: { $lt: data.lastEventMs } },
98
+ {
99
+ lastEventMs: data.lastEventMs,
100
+ lastEventSeq: { $lt: data.lastEventSeq },
101
+ },
102
+ ],
103
+ }, data);
104
+ }
105
+ };
106
+ JobProcessor = __decorate([
107
+ Processor(JobQueue),
108
+ __metadata("design:paramtypes", [EntityManager])
109
+ ], JobProcessor);
110
+ export { JobProcessor };
111
+ //# sourceMappingURL=job.processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job.processor.js","sourceRoot":"","sources":["../../src/processors/job.processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ /** Authenticated Job APIs using the application's global database and auth configuration. */
2
+ export declare class QueueApiModule {
3
+ }