@appweaver/create-weaver-app 1.0.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/LICENSE +1 -0
- package/README.md +7 -0
- package/create-weaver-app.d.ts +2 -0
- package/create-weaver-app.js +266 -0
- package/package.json +37 -0
- package/skill/GUIDELINES.md +298 -0
- package/skill/SKILL.md +593 -0
- package/skill/references/cache.md +207 -0
- package/skill/references/cli.md +213 -0
- package/skill/references/client.md +507 -0
- package/skill/references/configuration.md +402 -0
- package/skill/references/database.md +134 -0
- package/skill/references/dependency-injection.md +214 -0
- package/skill/references/events.md +152 -0
- package/skill/references/mailer.md +235 -0
- package/skill/references/queue.md +196 -0
- package/skill/references/resources.md +961 -0
- package/skill/references/scheduler.md +184 -0
- package/skill/references/security.md +694 -0
- package/skill/references/storage.md +251 -0
- package/templates/default/.dockerignore +5 -0
- package/templates/default/.env.tpl +1 -0
- package/templates/default/.prettierignore +3 -0
- package/templates/default/.prettierrc +7 -0
- package/templates/default/Dockerfile +56 -0
- package/templates/default/Dockerfile.bun +56 -0
- package/templates/default/README.md.tpl +7 -0
- package/templates/default/appweaver.dev.json.tpl +9 -0
- package/templates/default/appweaver.json.bun.tpl +17 -0
- package/templates/default/appweaver.json.tpl +16 -0
- package/templates/default/appweaver.test.json.tpl +30 -0
- package/templates/default/bunfig.toml.bun +8 -0
- package/templates/default/database/client.ts.tpl +7 -0
- package/templates/default/database/schema.prisma +13 -0
- package/templates/default/database/seeders/001-create-admin-user.ts.tpl +39 -0
- package/templates/default/eslint.config.mjs +55 -0
- package/templates/default/eslint.config.mjs.bun +53 -0
- package/templates/default/jest.config.json.node +23 -0
- package/templates/default/package.json.bun.tpl +39 -0
- package/templates/default/package.json.tpl +44 -0
- package/templates/default/prisma.config.ts.tpl +14 -0
- package/templates/default/public/favicon.ico +0 -0
- package/templates/default/public/robots.txt +2 -0
- package/templates/default/src/features/index.ts.tpl +0 -0
- package/templates/default/src/main.ts.tpl +7 -0
- package/templates/default/src/resources/user/model.ts.tpl +28 -0
- package/templates/default/src/resources/user/policy.ts.tpl +3 -0
- package/templates/default/src/resources/user/routes.ts.tpl +3 -0
- package/templates/default/src/resources/user/service.ts.tpl +16 -0
- package/templates/default/src/types/generated.ts.tpl +1 -0
- package/templates/default/src/types/index.ts.tpl +1 -0
- package/templates/default/start.sh +26 -0
- package/templates/default/start.sh.bun +26 -0
- package/templates/default/swc.config.json.node +13 -0
- package/templates/default/test/e2e/jest.e2e-config.json.node +22 -0
- package/templates/default/test/e2e/main.test.ts.tpl +24 -0
- package/templates/default/test/e2e/support/each.ts.tpl +13 -0
- package/templates/default/test/e2e/support/preload.ts.bun +13 -0
- package/templates/default/test/e2e/support/setup.ts.tpl +13 -0
- package/templates/default/test/e2e/support/teardown.ts.tpl +13 -0
- package/templates/default/test/unit/sample.test.ts.tpl +5 -0
- package/templates/default/tsconfig.build.json +10 -0
- package/templates/default/tsconfig.json +27 -0
- package/templates/default/tsconfig.json.bun +28 -0
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
# Queue
|
|
2
|
+
|
|
3
|
+
The queue module provides background job processing with support for workers, retries, and lifecycle event hooks. The
|
|
4
|
+
default implementation (`BullQueue`) uses [BullMQ](https://docs.bullmq.io/) backed by Redis. A `MemoryQueue` is
|
|
5
|
+
available for development and testing without a Redis dependency.
|
|
6
|
+
|
|
7
|
+
## Injecting Queue
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { inject } from '@appweaver/core';
|
|
11
|
+
import { Queue } from '@appweaver/common';
|
|
12
|
+
|
|
13
|
+
const queue = inject(Queue);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## `Queue` — manager
|
|
19
|
+
|
|
20
|
+
#### `queue.get<Data, Response>(name)`
|
|
21
|
+
|
|
22
|
+
Returns a `QueueProcessor` for the named queue. Creates the queue if it does not exist yet.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const emailQueue = queue.get<EmailJobData, void>('emails');
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
#### `queue.close(name)`
|
|
29
|
+
|
|
30
|
+
Closes a named queue and releases its resources. Returns `true` if closed.
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
await queue.close('emails');
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
#### `queue.closeAll()`
|
|
37
|
+
|
|
38
|
+
Closes all open queues.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
await queue.closeAll();
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
#### `queue.checkHealth()`
|
|
45
|
+
|
|
46
|
+
Returns a `HealthCheckResult` indicating whether the underlying queue backend is reachable.
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## `QueueProcessor` — per-queue API
|
|
51
|
+
|
|
52
|
+
Obtained via `queue.get(name)`.
|
|
53
|
+
|
|
54
|
+
#### `processor.sendJob(data, name?, options?)`
|
|
55
|
+
|
|
56
|
+
Enqueues a single job. Returns the created `QueueJob`.
|
|
57
|
+
|
|
58
|
+
| Parameter | Type | Description |
|
|
59
|
+
|-----------|--------------|------------------------------------------------|
|
|
60
|
+
| `data` | `Data` | Job payload |
|
|
61
|
+
| `name` | `string` | Optional job name/type label |
|
|
62
|
+
| `options` | `JobOptions` | Provider-specific options (delay, priority, …) |
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
const job = await emailQueue.sendJob({ to: 'alice@example.com', template: 'welcome' });
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### `processor.sendBulkJobs(jobs)`
|
|
69
|
+
|
|
70
|
+
Enqueues multiple jobs in a single call. Returns an array of created `QueueJob` instances.
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
await emailQueue.sendBulkJobs([
|
|
74
|
+
{ data: { to: 'alice@example.com', template: 'welcome' } },
|
|
75
|
+
{ data: { to: 'bob@example.com', template: 'welcome' } }
|
|
76
|
+
]);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
#### `processor.addWorker(processor, options?)`
|
|
80
|
+
|
|
81
|
+
Registers a worker function that processes jobs from the queue. Returns the created worker handle.
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
emailQueue.addWorker(async (job) => {
|
|
85
|
+
await sendEmail(job.data.to, job.data.template);
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
#### `processor.removeWorker(id)`
|
|
90
|
+
|
|
91
|
+
Removes a registered worker by ID.
|
|
92
|
+
|
|
93
|
+
```ts
|
|
94
|
+
await emailQueue.removeWorker(workerId);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### `processor.close()`
|
|
98
|
+
|
|
99
|
+
Closes this processor and its workers.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Event listeners
|
|
104
|
+
|
|
105
|
+
Each listener registration method returns a listener ID. Pass it to `removeListener` to unsubscribe.
|
|
106
|
+
|
|
107
|
+
| Method | Trigger |
|
|
108
|
+
|------------------------|----------------------------------------|
|
|
109
|
+
| `onCompleted(handler)` | Job finished successfully |
|
|
110
|
+
| `onFailed(handler)` | Job failed (after all retries) |
|
|
111
|
+
| `onError(handler)` | Worker or queue error |
|
|
112
|
+
| `onProgress(handler)` | Job reported progress |
|
|
113
|
+
| `onActive(handler)` | Job moved from waiting to active |
|
|
114
|
+
| `onStalled(handler)` | Job stalled (worker did not heartbeat) |
|
|
115
|
+
| `onDrained(handler)` | Queue became empty |
|
|
116
|
+
| `onReady(handler)` | Queue is ready to process jobs |
|
|
117
|
+
| `onPaused(handler)` | Queue was paused |
|
|
118
|
+
| `onResumed(handler)` | Queue was resumed |
|
|
119
|
+
| `onClosing(handler)` | Queue is closing |
|
|
120
|
+
| `onClosed(handler)` | Queue closed |
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
const listenerId = emailQueue.onCompleted((job, result) => {
|
|
124
|
+
logger.info(`Email job ${job.id} completed`);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
emailQueue.onFailed((job, err) => {
|
|
128
|
+
logger.error(err, `Email job failed:`);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Unsubscribe later
|
|
132
|
+
emailQueue.removeListener(listenerId);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
## `QueueJob` shape
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
type QueueJob<Data, Response> = {
|
|
141
|
+
id?: string;
|
|
142
|
+
name: string;
|
|
143
|
+
data: Data;
|
|
144
|
+
returnvalue: Response;
|
|
145
|
+
};
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Configuration
|
|
151
|
+
|
|
152
|
+
| Key | Type | Default | Description |
|
|
153
|
+
|------------------------------|----------|--------------------------------------|----------------------------------------------------|
|
|
154
|
+
| `QUEUE_PROVIDER` | `string` | `'@appweaver/core/queue/bull-queue'` | Path to the Queue implementation |
|
|
155
|
+
| `QUEUE_KEEP_COMPLETED_COUNT` | `int` | `0` | How many completed jobs to retain (0 = remove all) |
|
|
156
|
+
| `QUEUE_KEEP_FAILED_COUNT` | `int` | `50` | How many failed jobs to retain for inspection |
|
|
157
|
+
| `QUEUE_RETRY_ATTEMPTS` | `int` | `3` | Number of retry attempts on failure |
|
|
158
|
+
| `QUEUE_RETRY_BACKOFF` | `int` | `3000` | Backoff delay in milliseconds |
|
|
159
|
+
| `QUEUE_RETRY_BACKOFF_TYPE` | `enum` | `'fixed'` | `fixed` or `exponential` |
|
|
160
|
+
|
|
161
|
+
**Use `MemoryQueue` for local development:**
|
|
162
|
+
|
|
163
|
+
```json
|
|
164
|
+
{
|
|
165
|
+
"QUEUE_PROVIDER": "@appweaver/core/queue/memory-queue"
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Real-world example
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { inject } from '@appweaver/core';
|
|
175
|
+
import { logger, Queue } from '@appweaver/common';
|
|
176
|
+
|
|
177
|
+
type ReportJob = { userId: number; reportType: string };
|
|
178
|
+
|
|
179
|
+
export class ReportService {
|
|
180
|
+
private readonly _processor = inject(Queue).get<ReportJob, void>('reports');
|
|
181
|
+
|
|
182
|
+
constructor() {
|
|
183
|
+
this._processor.addWorker(async (job) => {
|
|
184
|
+
await generateReport(job.data.userId, job.data.reportType);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
this._processor.onFailed((job, err) => {
|
|
188
|
+
logger.error(err, `Report generation failed for user ${job?.data.userId}:`);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
async requestReport(userId: number, reportType: string): Promise<void> {
|
|
193
|
+
await this._processor.sendJob({ userId, reportType });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|