@bull-board/nestjs 8.0.2 → 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.
package/README.md
CHANGED
|
@@ -144,10 +144,32 @@ export class FeatureModule {}
|
|
|
144
144
|
|
|
145
145
|
The `forFeature` method registers the given queues to the bull-board instance.
|
|
146
146
|
The following options are available.
|
|
147
|
-
- `name` the queue name to
|
|
147
|
+
- `name` the queue name to resolve from the Nest DI container.
|
|
148
|
+
- `queue` a queue instance to register directly, instead of resolving it by `name`.
|
|
148
149
|
- `adapter` either `BullAdapter` or `BullMQAdapter` depending on which package you use.
|
|
149
150
|
- `options` queue adapter options as found in the bull-board package, such as `readOnlyMode`, `description` etc.
|
|
150
151
|
|
|
152
|
+
Provide either `name` or `queue`.
|
|
153
|
+
|
|
154
|
+
### Registering queue instances directly
|
|
155
|
+
|
|
156
|
+
`@nestjs/bullmq` generates the DI token for a queue from its `name` only, ignoring the
|
|
157
|
+
`prefix`. Two queues that share a name but use different prefixes therefore collapse onto a
|
|
158
|
+
single DI token, and a `name`-based lookup cannot tell them apart. Pass the queue instances
|
|
159
|
+
directly via `queue` to register them as distinct board entries:
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
@Module({
|
|
163
|
+
imports: [
|
|
164
|
+
BullBoardModule.forFeature(
|
|
165
|
+
{ queue: emailsTenantA, adapter: BullMQAdapter, options: { prefix: 'tenant-a:' } },
|
|
166
|
+
{ queue: emailsTenantB, adapter: BullMQAdapter, options: { prefix: 'tenant-b:' } },
|
|
167
|
+
),
|
|
168
|
+
],
|
|
169
|
+
})
|
|
170
|
+
export class FeatureModule {}
|
|
171
|
+
```
|
|
172
|
+
|
|
151
173
|
## Using the bull-board instance in your controllers and/or services.
|
|
152
174
|
The created bull-board instance is available via the `@InjectBullBoard()` decorator.
|
|
153
175
|
For example in a controller:
|
|
@@ -24,8 +24,9 @@ let BullBoardFeatureModule = class BullBoardFeatureModule {
|
|
|
24
24
|
this.board = board;
|
|
25
25
|
}
|
|
26
26
|
onModuleInit() {
|
|
27
|
+
var _a;
|
|
27
28
|
for (const queueOption of this.queues) {
|
|
28
|
-
const queue = this.moduleRef.get((0, bull_shared_1.getQueueToken)(queueOption.name), { strict: false });
|
|
29
|
+
const queue = (_a = queueOption.queue) !== null && _a !== void 0 ? _a : this.moduleRef.get((0, bull_shared_1.getQueueToken)(queueOption.name), { strict: false });
|
|
29
30
|
const queueAdapter = new queueOption.adapter(queue, queueOption.options);
|
|
30
31
|
this.board.addQueue(queueAdapter);
|
|
31
32
|
}
|
|
@@ -16,13 +16,29 @@ export type BullBoardModuleAsyncOptions = {
|
|
|
16
16
|
imports?: ModuleMetadata['imports'];
|
|
17
17
|
inject?: Array<InjectionToken | OptionalFactoryDependency>;
|
|
18
18
|
};
|
|
19
|
-
|
|
20
|
-
name: string;
|
|
19
|
+
type BullBoardQueueCommonOptions = {
|
|
21
20
|
adapter: {
|
|
22
21
|
new (queue: any, options?: Partial<QueueAdapterOptions>): BaseAdapter;
|
|
23
22
|
};
|
|
24
23
|
options?: Partial<QueueAdapterOptions>;
|
|
25
24
|
};
|
|
25
|
+
export type BullBoardQueueOptions = BullBoardQueueCommonOptions & ({
|
|
26
|
+
/**
|
|
27
|
+
* The queue name to resolve from the Nest DI container (via `getQueueToken`).
|
|
28
|
+
*/
|
|
29
|
+
name: string;
|
|
30
|
+
queue?: undefined;
|
|
31
|
+
} | {
|
|
32
|
+
/**
|
|
33
|
+
* A queue instance to register directly, bypassing the DI container lookup.
|
|
34
|
+
*
|
|
35
|
+
* Use this when the name-based lookup cannot disambiguate the queue — e.g. two
|
|
36
|
+
* queues sharing the same name but using different prefixes, which `@nestjs/bullmq`
|
|
37
|
+
* collapses onto a single DI token.
|
|
38
|
+
*/
|
|
39
|
+
queue: unknown;
|
|
40
|
+
name?: string;
|
|
41
|
+
});
|
|
26
42
|
export type BullBoardServerAdapter = IServerAdapter & {
|
|
27
43
|
setBasePath(path: string): any;
|
|
28
44
|
};
|
|
@@ -32,3 +48,4 @@ export type BullBoardFastifyAdapter = BullBoardServerAdapter & {
|
|
|
32
48
|
export type BullBoardExpressAdapter = BullBoardServerAdapter & {
|
|
33
49
|
getRouter(): any;
|
|
34
50
|
};
|
|
51
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bull-board/nestjs",
|
|
3
|
-
"version": "8.0
|
|
3
|
+
"version": "8.1.0",
|
|
4
4
|
"description": "A NestJS module for Bull-Board dashboard.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bull",
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"test": "jest"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@bull-board/api": "^8.0
|
|
32
|
-
"@bull-board/express": "^8.0
|
|
33
|
-
"@bull-board/fastify": "^8.0
|
|
31
|
+
"@bull-board/api": "^8.1.0",
|
|
32
|
+
"@bull-board/express": "^8.1.0",
|
|
33
|
+
"@bull-board/fastify": "^8.1.0",
|
|
34
34
|
"@bull-board/test-utils": "workspace:*",
|
|
35
35
|
"@nestjs/bull-shared": "^11.0.4",
|
|
36
36
|
"@nestjs/bullmq": "^11.0.4",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"typescript": "^5.9.3"
|
|
50
50
|
},
|
|
51
51
|
"peerDependencies": {
|
|
52
|
-
"@bull-board/api": "^8.0
|
|
52
|
+
"@bull-board/api": "^8.1.0",
|
|
53
53
|
"@nestjs/bull-shared": "^10.0.0 || ^11.0.0",
|
|
54
54
|
"@nestjs/common": "^9.0.0 || ^10.0.0 || ^11.0.0",
|
|
55
55
|
"@nestjs/core": "^9.0.0 || ^10.0.0 || ^11.0.0",
|
|
@@ -15,7 +15,9 @@ export class BullBoardFeatureModule implements OnModuleInit {
|
|
|
15
15
|
|
|
16
16
|
onModuleInit(): any {
|
|
17
17
|
for (const queueOption of this.queues) {
|
|
18
|
-
const queue =
|
|
18
|
+
const queue =
|
|
19
|
+
queueOption.queue ??
|
|
20
|
+
this.moduleRef.get<Queue>(getQueueToken(queueOption.name), { strict: false });
|
|
19
21
|
const queueAdapter = new queueOption.adapter(queue, queueOption.options);
|
|
20
22
|
this.board.addQueue(queueAdapter);
|
|
21
23
|
}
|
package/src/bull-board.types.ts
CHANGED
|
@@ -22,12 +22,33 @@ export type BullBoardModuleAsyncOptions = {
|
|
|
22
22
|
inject?: Array<InjectionToken | OptionalFactoryDependency>;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
name: string;
|
|
25
|
+
type BullBoardQueueCommonOptions = {
|
|
27
26
|
adapter: { new (queue: any, options?: Partial<QueueAdapterOptions>): BaseAdapter };
|
|
28
27
|
options?: Partial<QueueAdapterOptions>;
|
|
29
28
|
};
|
|
30
29
|
|
|
30
|
+
export type BullBoardQueueOptions = BullBoardQueueCommonOptions &
|
|
31
|
+
(
|
|
32
|
+
| {
|
|
33
|
+
/**
|
|
34
|
+
* The queue name to resolve from the Nest DI container (via `getQueueToken`).
|
|
35
|
+
*/
|
|
36
|
+
name: string;
|
|
37
|
+
queue?: undefined;
|
|
38
|
+
}
|
|
39
|
+
| {
|
|
40
|
+
/**
|
|
41
|
+
* A queue instance to register directly, bypassing the DI container lookup.
|
|
42
|
+
*
|
|
43
|
+
* Use this when the name-based lookup cannot disambiguate the queue — e.g. two
|
|
44
|
+
* queues sharing the same name but using different prefixes, which `@nestjs/bullmq`
|
|
45
|
+
* collapses onto a single DI token.
|
|
46
|
+
*/
|
|
47
|
+
queue: unknown;
|
|
48
|
+
name?: string;
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
|
|
31
52
|
//create our own types with the needed functions, so we don't need to include express/fastify libraries here.
|
|
32
53
|
export type BullBoardServerAdapter = IServerAdapter & { setBasePath(path: string): any };
|
|
33
54
|
export type BullBoardFastifyAdapter = BullBoardServerAdapter & { registerPlugin(): any };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import 'reflect-metadata';
|
|
2
|
+
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
|
|
3
|
+
import { ExpressAdapter as BullBoardExpressAdapter } from '@bull-board/express';
|
|
4
|
+
import { uiFixtureBasePath } from '@bull-board/test-utils';
|
|
5
|
+
import { BullModule } from '@nestjs/bullmq';
|
|
6
|
+
import { INestApplication, Module } from '@nestjs/common';
|
|
7
|
+
import { NestFactory } from '@nestjs/core';
|
|
8
|
+
import { ExpressAdapter } from '@nestjs/platform-express';
|
|
9
|
+
import { Queue } from 'bullmq';
|
|
10
|
+
import request from 'supertest';
|
|
11
|
+
import { BullBoardModule } from '../src';
|
|
12
|
+
|
|
13
|
+
const connection = {
|
|
14
|
+
host: process.env.REDIS_HOST || 'localhost',
|
|
15
|
+
port: +(process.env.REDIS_PORT || 6379),
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
describe('forFeature with queue instances (same name, different prefix)', () => {
|
|
19
|
+
const queues: Queue[] = [];
|
|
20
|
+
let app: INestApplication | undefined;
|
|
21
|
+
|
|
22
|
+
afterEach(async () => {
|
|
23
|
+
if (app) {
|
|
24
|
+
await app.close();
|
|
25
|
+
app = undefined;
|
|
26
|
+
}
|
|
27
|
+
await Promise.all(queues.map((queue) => queue.close()));
|
|
28
|
+
queues.length = 0;
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('registers both queues as distinct board entries', async () => {
|
|
32
|
+
const emailsA = new Queue('emails', { connection, prefix: 'tenant-a' });
|
|
33
|
+
const emailsB = new Queue('emails', { connection, prefix: 'tenant-b' });
|
|
34
|
+
queues.push(emailsA, emailsB);
|
|
35
|
+
|
|
36
|
+
@Module({
|
|
37
|
+
imports: [
|
|
38
|
+
BullBoardModule.forRoot({
|
|
39
|
+
route: '/queues',
|
|
40
|
+
adapter: BullBoardExpressAdapter,
|
|
41
|
+
boardOptions: { uiBasePath: uiFixtureBasePath },
|
|
42
|
+
}),
|
|
43
|
+
BullBoardModule.forFeature(
|
|
44
|
+
{ queue: emailsA, adapter: BullMQAdapter, options: { prefix: 'tenant-a:' } },
|
|
45
|
+
{ queue: emailsB, adapter: BullMQAdapter, options: { prefix: 'tenant-b:' } }
|
|
46
|
+
),
|
|
47
|
+
],
|
|
48
|
+
})
|
|
49
|
+
class AppModule {}
|
|
50
|
+
|
|
51
|
+
app = await NestFactory.create(AppModule, new ExpressAdapter(), { logger: false });
|
|
52
|
+
await app.init();
|
|
53
|
+
|
|
54
|
+
const res = await request(app.getHttpServer()).get('/queues/api/queues').expect(200);
|
|
55
|
+
const names = (JSON.parse(res.text).queues as Array<{ name: string }>)
|
|
56
|
+
.map((queue) => queue.name)
|
|
57
|
+
.sort();
|
|
58
|
+
|
|
59
|
+
expect(names).toEqual(['tenant-a:emails', 'tenant-b:emails']);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('still resolves a queue from the DI container when only a name is given', async () => {
|
|
63
|
+
@Module({
|
|
64
|
+
imports: [
|
|
65
|
+
BullModule.forRoot({ connection }),
|
|
66
|
+
BullModule.registerQueue({ name: 'reports' }),
|
|
67
|
+
BullBoardModule.forRoot({
|
|
68
|
+
route: '/queues',
|
|
69
|
+
adapter: BullBoardExpressAdapter,
|
|
70
|
+
boardOptions: { uiBasePath: uiFixtureBasePath },
|
|
71
|
+
}),
|
|
72
|
+
BullBoardModule.forFeature({ name: 'reports', adapter: BullMQAdapter }),
|
|
73
|
+
],
|
|
74
|
+
})
|
|
75
|
+
class AppModule {}
|
|
76
|
+
|
|
77
|
+
app = await NestFactory.create(AppModule, new ExpressAdapter(), { logger: false });
|
|
78
|
+
await app.init();
|
|
79
|
+
|
|
80
|
+
const res = await request(app.getHttpServer()).get('/queues/api/queues').expect(200);
|
|
81
|
+
const names = (JSON.parse(res.text).queues as Array<{ name: string }>).map(
|
|
82
|
+
(queue) => queue.name
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
expect(names).toEqual(['reports']);
|
|
86
|
+
});
|
|
87
|
+
});
|