@pikku/queue-bullmq 0.12.8 → 0.12.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,23 @@
1
+ ## 0.12.9
2
+
3
+ ### Patch Changes
4
+
5
+ - de9af6a: RPCs for Pikku Studio's migrated screens. Runtime state that must be visible on a deployed app lives in `@pikku/addon-admin`; local-copy tools stay in `@pikku/addon-console`.
6
+
7
+ `@pikku/addon-admin`:
8
+
9
+ - `admin:getSchedulerHistory` returns each scheduled task's last run, next run and recent runs, from a new `SchedulerService.getTaskRuns()` (empty by default). `InMemorySchedulerService` records the last 50 runs per cron task with status, duration and error. Scope `admin:schedules:read`.
10
+ - `admin:getQueueHistory({ queueNames?, limit? })` returns live counts and recent jobs per queue, from a new optional `QueueService.inspect(queueName, { limit })`, implemented by `InMemoryQueueService` and `BullQueueService` and forwarded by `SignedQueueService`. Scope `admin:queues:read`.
11
+ - `admin:listIncomingWebhookReceipts` / `admin:getIncomingWebhookReceipt` expose received webhooks, backed by a new `IncomingWebhookService.getReceipt(receiptId)` (null by default; implemented by `KyselyIncomingWebhookService`). Scope `admin:webhooks:read`.
12
+
13
+ `@pikku/addon-console`:
14
+
15
+ - `console:variableGet` / `console:variableSet` read and write a project variable, gated on `pikku:console:variables:read` / `:write`.
16
+ - `console:runScenarios({ names?, environment? })` starts `pikku scenario run` as a detached child process and returns `{ runId }` to follow through `listScenarioRuns` / `getScenarioRun`, gated on the new `pikku:console:scenarios:run` scope. `pikku scenario run` takes `--run-id <id>` to record under a caller-chosen id.
17
+
18
+ - Updated dependencies [de9af6a]
19
+ - @pikku/core@0.12.143
20
+
1
21
  ## 0.12.8
2
22
 
3
23
  ### Patch Changes
@@ -1,9 +1,10 @@
1
1
  import type { ConnectionOptions, JobsOptions } from 'bullmq';
2
2
  import type Bull from 'bullmq';
3
3
  import { Queue, QueueEvents } from 'bullmq';
4
- import type { QueueJob, QueueService } from '@pikku/core/queue';
4
+ import type { QueueInspection, QueueJob, QueueJobRecord, QueueJobStatus, QueueService } from '@pikku/core/queue';
5
5
  import type { JobOptions } from '@pikku/core/queue';
6
6
  export declare const mapPikkuJobToBull: (options?: JobOptions) => JobsOptions;
7
+ export declare const mapBullJobToRecord: (job: Bull.Job, status: QueueJobStatus) => QueueJobRecord;
7
8
  /**
8
9
  * Bull/Redis queue service implementation
9
10
  * Supports job results, retries, and most queue features
@@ -12,8 +13,8 @@ export declare class BullQueueService implements QueueService {
12
13
  private redisConnectionOptions;
13
14
  readonly name = "bull";
14
15
  readonly supportsResults = true;
15
- protected queues: Map<string, Queue<any, any, string, any, any, string, Bull.RedisQueueBackend>>;
16
- protected queueEvents: Map<string, QueueEvents<any>>;
16
+ protected queues: Map<string, Queue<any, any, string, any, any, string, Bull.RedisQueueBackend, ConnectionOptions>>;
17
+ protected queueEvents: Map<string, QueueEvents<any, Bull.RedisQueueBackend, ConnectionOptions>>;
17
18
  constructor(redisConnectionOptions?: ConnectionOptions);
18
19
  /**
19
20
  * Create a Bull queue with translated configuration
@@ -23,6 +24,9 @@ export declare class BullQueueService implements QueueService {
23
24
  * Add a job to the queue
24
25
  */
25
26
  add<In>(queueName: string, data: In, options?: JobOptions): Promise<string>;
27
+ inspect(queueName: string, opts?: {
28
+ limit?: number;
29
+ }): Promise<QueueInspection>;
26
30
  /**
27
31
  * Get job by ID
28
32
  */
@@ -30,6 +30,24 @@ export const mapPikkuJobToBull = (options) => {
30
30
  }
31
31
  return bullOptions;
32
32
  };
33
+ const INSPECTED_STATES = [
34
+ 'waiting',
35
+ 'active',
36
+ 'delayed',
37
+ 'completed',
38
+ 'failed',
39
+ ];
40
+ export const mapBullJobToRecord = (job, status) => ({
41
+ jobId: job.id,
42
+ status,
43
+ attemptsMade: job.attemptsMade,
44
+ maxAttempts: job.opts.attempts ?? 1,
45
+ createdAt: new Date(job.timestamp),
46
+ processedAt: job.processedOn ? new Date(job.processedOn) : null,
47
+ finishedAt: job.finishedOn ? new Date(job.finishedOn) : null,
48
+ durationMs: job.finishedOn && job.processedOn ? job.finishedOn - job.processedOn : null,
49
+ error: job.failedReason || null,
50
+ });
33
51
  /**
34
52
  * Bull/Redis queue service implementation
35
53
  * Supports job results, retries, and most queue features
@@ -76,6 +94,16 @@ export class BullQueueService {
76
94
  }
77
95
  return bullJob.id;
78
96
  }
97
+ async inspect(queueName, opts) {
98
+ const queue = await this.createQueue(queueName);
99
+ const limit = opts?.limit ?? 50;
100
+ const counts = (await queue.getJobCounts(...INSPECTED_STATES));
101
+ const recent = (await Promise.all(INSPECTED_STATES.map(async (status) => (await queue.getJobs([status], 0, limit - 1)).map((job) => mapBullJobToRecord(job, status)))))
102
+ .flat()
103
+ .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())
104
+ .slice(0, limit);
105
+ return { counts, recent };
106
+ }
79
107
  /**
80
108
  * Get job by ID
81
109
  */
@@ -0,0 +1,31 @@
1
+ ---
2
+ type: decision
3
+ title: A delayed RPC job carries the caller's session in its data, and a recurring job carries none
4
+ description: BullSchedulerService stores the session in the job data and returns it from getTask, while the recurring worker runs the task by name alone
5
+ tags: bullmq, scheduler, sessions, rpc
6
+ ---
7
+
8
+ # A delayed RPC job carries the caller's session in its data, and a recurring job carries none
9
+
10
+ `BullSchedulerService` in `packages/services/queue-bullmq/src/bull-scheduler-service.ts` defines the job data
11
+ as `{ rpcName, data?, session? }` (lines 17-21).
12
+
13
+ **Delayed.** `scheduleRPC` takes an optional `session` (line 56) and puts it in the job data (lines 62-66). The
14
+ job is added to the `pikku-remote-internal-rpc` queue with the delay (lines 69-72). `getTask` returns the stored
15
+ `session` (line 116). `getAllTasks` returns only the id, rpc name and time (lines 133-137). The session is
16
+ therefore stored in Redis with the job.
17
+
18
+ **What runs it.** This file has no worker for that queue. The CLI generates one, `remoteRPCHandler`, whose
19
+ function destructures only `{ rpcName, data }` and calls `rpc.invoke(rpcName, data)`
20
+ (`packages/cli/src/functions/wirings/rpc/serialize-remote-rpc.ts:37-39`). It is wired to the queue at lines
21
+ 43-47 of the same file. Nothing in that handler reads the job's `session`.
22
+
23
+ **Recurring.** `start` creates a worker on `pikku-recurring-scheduled-task` (lines 161-169) that calls
24
+ `runScheduledTask({ name: rpcName })` (line 166). The job data written for each task is `{ rpcName: name }`
25
+ (line 179), so there is no session to carry.
26
+
27
+ The same question for the in-memory scheduler is open in
28
+ [does-a-delayed-rpc-run-as-the-session-it-was-scheduled-with](../../../../core/knowledge/questions/does-a-delayed-rpc-run-as-the-session-it-was-scheduled-with.md).
29
+
30
+ **What this rules out:** reading `getTask().session` as evidence that the delayed run executes as that user,
31
+ and putting anything secret in a session passed to `scheduleRPC`, since it is stored in the job data.
@@ -0,0 +1,12 @@
1
+ ---
2
+ type: overview
3
+ title: Decisions
4
+ ---
5
+
6
+ # Decisions
7
+
8
+ A rule that was chosen, and what it rules out.
9
+
10
+ <!-- pikku:knowledge-index -->
11
+ - [A delayed RPC job carries the caller's session in its data, and a recurring job carries none](a-delayed-rpc-job-carries-the-callers-session-and-a-recurring-job-carries-none.md) — BullSchedulerService stores the session in the job data and returns it from getTask, while the recurring worker runs the task by name alone
12
+ <!-- /pikku:knowledge-index -->
@@ -0,0 +1,13 @@
1
+ ---
2
+ type: overview
3
+ title: Knowledge
4
+ description: What identity a BullMQ job carries when it runs
5
+ ---
6
+
7
+ # Knowledge
8
+
9
+ The BullMQ scheduler runs delayed and recurring jobs. These notes record which of them carry a caller's session.
10
+
11
+ <!-- pikku:knowledge-index -->
12
+ - [decisions](decisions/index.md) — a rule that was chosen, and what it rules out
13
+ <!-- /pikku:knowledge-index -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pikku/queue-bullmq",
3
- "version": "0.12.8",
3
+ "version": "0.12.9",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/pikkujs/pikku.git",
@@ -21,7 +21,7 @@
21
21
  "prepublishOnly": "bun run build"
22
22
  },
23
23
  "peerDependencies": {
24
- "@pikku/core": "^0.12.108"
24
+ "@pikku/core": "^0.12.143"
25
25
  },
26
26
  "dependencies": {
27
27
  "bullmq": "^6.1.1",