@rvoh/psychic-workers 2.6.0 → 2.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.
Files changed (36) hide show
  1. package/dist/cjs/src/background/BaseBackgroundedModel.js +49 -25
  2. package/dist/cjs/src/background/BaseBackgroundedService.js +24 -12
  3. package/dist/cjs/src/background/BaseScheduledService.js +1 -1
  4. package/dist/cjs/src/background/index.js +383 -98
  5. package/dist/cjs/src/error/background/DebouncedJobOutpacesRateLimit.js +64 -0
  6. package/dist/cjs/src/error/background/DebouncedJobRequiresMinimumDelay.js +52 -0
  7. package/dist/cjs/src/error/background/NamedWorkstreamRateLimitMissingMaxOrDuration.js +31 -0
  8. package/dist/cjs/src/error/background/RateLimitedPsychicJob.js +82 -0
  9. package/dist/cjs/src/error/background/RateLimitedPsychicJobThrownFromWorkerWithoutLimiter.js +51 -0
  10. package/dist/cjs/src/package-exports/errors.js +7 -0
  11. package/dist/cjs/src/test-utils/WorkerTestUtils.js +78 -13
  12. package/dist/esm/src/background/BaseBackgroundedModel.js +49 -25
  13. package/dist/esm/src/background/BaseBackgroundedService.js +24 -12
  14. package/dist/esm/src/background/BaseScheduledService.js +1 -1
  15. package/dist/esm/src/background/index.js +383 -98
  16. package/dist/esm/src/error/background/DebouncedJobOutpacesRateLimit.js +64 -0
  17. package/dist/esm/src/error/background/DebouncedJobRequiresMinimumDelay.js +52 -0
  18. package/dist/esm/src/error/background/NamedWorkstreamRateLimitMissingMaxOrDuration.js +31 -0
  19. package/dist/esm/src/error/background/RateLimitedPsychicJob.js +82 -0
  20. package/dist/esm/src/error/background/RateLimitedPsychicJobThrownFromWorkerWithoutLimiter.js +51 -0
  21. package/dist/esm/src/package-exports/errors.js +7 -0
  22. package/dist/esm/src/test-utils/WorkerTestUtils.js +78 -13
  23. package/dist/types/src/background/BaseBackgroundedModel.d.ts +49 -25
  24. package/dist/types/src/background/BaseBackgroundedService.d.ts +24 -12
  25. package/dist/types/src/background/BaseScheduledService.d.ts +1 -1
  26. package/dist/types/src/background/index.d.ts +109 -5
  27. package/dist/types/src/error/background/DebouncedJobOutpacesRateLimit.d.ts +31 -0
  28. package/dist/types/src/error/background/DebouncedJobRequiresMinimumDelay.d.ts +23 -0
  29. package/dist/types/src/error/background/NamedWorkstreamRateLimitMissingMaxOrDuration.d.ts +16 -0
  30. package/dist/types/src/error/background/RateLimitedPsychicJob.d.ts +73 -0
  31. package/dist/types/src/error/background/RateLimitedPsychicJobThrownFromWorkerWithoutLimiter.d.ts +16 -0
  32. package/dist/types/src/package-exports/errors.d.ts +1 -0
  33. package/dist/types/src/psychic-app-workers/index.d.ts +102 -53
  34. package/dist/types/src/test-utils/WorkerTestUtils.d.ts +32 -1
  35. package/dist/types/src/types/background.d.ts +88 -6
  36. package/package.json +1 -1
@@ -29,14 +29,73 @@ export interface BackgroundJobData {
29
29
  */
30
30
  globalName?: string;
31
31
  }
32
- export type DelayedJobOpts = DelayedJobDuration & {
32
+ /**
33
+ * the delay to hold a job for and, when a `jobId` is provided, the debounce
34
+ * that delay drives.
35
+ *
36
+ * Calling a delayed background method repeatedly with the same `jobId`
37
+ * collapses those calls into a **single execution**. Each call slides the
38
+ * pending job's fire time further out, and the job runs once, after the last
39
+ * call, when the delay has finally elapsed without another call arriving.
40
+ *
41
+ * ```ts
42
+ * // ten calls in quick succession; the report is generated once,
43
+ * // ten seconds after the last of them
44
+ * await Report.backgroundWith({ delay: { seconds: 10, jobId: `report-${user.id}` } }, 'generate', user.id)
45
+ * ```
46
+ *
47
+ * A delay object must carry at least one of `seconds`, `minutes`, `hours` or
48
+ * `days`. `{}` and `{ jobId: 'my-job' }` are compile errors, since a delay with
49
+ * no duration delays nothing and a `jobId` with no duration debounces
50
+ * nothing.
51
+ */
52
+ export type DelayedJobOpts = AtLeastOneDelayedJobDuration & {
33
53
  /**
34
- * a unique identifier for your job. this identifier will be
35
- * used to debounce, leveraging the internal throttling mechanisms
36
- * provided by BullMQ
54
+ * a **deduplication key**, which debounces repeated calls: calls carrying the
55
+ * same `jobId` collapse into a single execution, which runs once the delay
56
+ * has elapsed without another call arriving. The window runs from the last
57
+ * call, not the first, so a burst is collapsed however long it lasts.
58
+ *
59
+ * Despite the name, this is not the BullMQ job id of the enqueued job, and
60
+ * `queue.getJob(jobId)` will not resolve the debounced job through it. BullMQ
61
+ * stores it as a separate Redis key; the matching read is
62
+ * `queue.getDeduplicationJobId(jobId)`.
63
+ *
64
+ * A delay carrying a `jobId` must be **at least three seconds**, and a
65
+ * shorter one is refused at enqueue.
66
+ *
67
+ * On a rate-limited workstream the delay must also clear the limiter's
68
+ * spacing: `delay - 1s >= duration / max`, so a workstream limited to one job
69
+ * a minute needs a 61-second delay. A delay that does not is refused at
70
+ * enqueue, naming the queue, both limiter numbers and a delay that would
71
+ * pass.
37
72
  */
38
73
  jobId?: string;
39
74
  };
75
+ /**
76
+ * `DelayedJobDuration`, but at least one field has to be there. Every field is
77
+ * optional on its own, so `{}` would otherwise compile and delay nothing.
78
+ * TypeScript has no "at least one of these" operator, so this spells out the
79
+ * four ways to satisfy it and joins them with `|`:
80
+ *
81
+ * ```ts
82
+ * | { seconds: number; minutes?: number; hours?: number; days?: number }
83
+ * | { minutes: number; seconds?: number; hours?: number; days?: number }
84
+ * | { hours: number; seconds?: number; minutes?: number; days?: number }
85
+ * | { days: number; seconds?: number; minutes?: number; hours?: number }
86
+ * ```
87
+ *
88
+ * A value has to match one of those, which means carrying that line's required
89
+ * field. `{ seconds: 30 }` matches the first. `{}` matches none, and neither
90
+ * does `{ jobId: 'my-job' }`.
91
+ *
92
+ * Not exported: it exists only to narrow `DelayedJobOpts`. `DelayedJobDuration`
93
+ * itself stays all-optional because it is also the parameter type of the shared
94
+ * `durationToSeconds` helper.
95
+ */
96
+ type AtLeastOneDelayedJobDuration = {
97
+ [Field in keyof DelayedJobDuration]-?: Required<Pick<DelayedJobDuration, Field>> & Partial<Omit<DelayedJobDuration, Field>>;
98
+ }[keyof DelayedJobDuration];
40
99
  export interface DelayedJobDuration {
41
100
  seconds?: number;
42
101
  minutes?: number;
@@ -49,8 +108,15 @@ export interface BackgroundWithOpts {
49
108
  /**
50
109
  * an optional delay to hold off the job for a certain amount of
51
110
  * time after it is entered into the queue. Accepts the same options
52
- * as `backgroundWithDelay`, including an optional `jobId` which
53
- * debounces repeated calls within the delay window.
111
+ * as `backgroundWithDelay`, and must carry at least one of `seconds`,
112
+ * `minutes`, `hours` or `days`.
113
+ *
114
+ * Adding a `jobId` turns the delay into a **debounce**: repeated calls
115
+ * carrying the same `jobId` collapse into a single execution, which runs
116
+ * once the delay has elapsed without another call arriving. `jobId` is a
117
+ * deduplication key rather than a BullMQ job id.
118
+ *
119
+ * See {@link DelayedJobOpts.jobId}.
54
120
  */
55
121
  delay?: DelayedJobOpts;
56
122
  /**
@@ -71,4 +137,20 @@ export interface QueueBackgroundJobConfig<T extends BaseScheduledService | BaseB
71
137
  }
72
138
  export type BackgroundJobConfig<T extends BaseScheduledService | BaseBackgroundedService> = Either<WorkstreamBackgroundJobConfig<T>, QueueBackgroundJobConfig<T>>;
73
139
  export type PsychicBackgroundOptions = (PsychicBackgroundSimpleOptions & Partial<Record<Exclude<keyof PsychicBackgroundNativeBullMQOptions, keyof PsychicBackgroundSimpleOptions>, never>>) | (PsychicBackgroundNativeBullMQOptions & Partial<Record<Exclude<keyof PsychicBackgroundSimpleOptions, keyof PsychicBackgroundNativeBullMQOptions>, never>>);
140
+ /**
141
+ * @internal
142
+ *
143
+ * how a queue was configured, as far as the misconfiguration message needs to
144
+ * know in order to name the fix that applies to the worker that threw
145
+ */
146
+ export interface WorkerQueueDescription {
147
+ /** simple (workstream) configuration or native BullMQ configuration */
148
+ mode: 'simple' | 'native';
149
+ /** the default workstream/queue, as opposed to a named one */
150
+ isDefaultQueue: boolean;
151
+ /** the workstream or queue name as configured (not the formatted Redis queue name) */
152
+ configuredName: string;
153
+ /** a workstream declared under `transitionalWorkstreams` */
154
+ transitional: boolean;
155
+ }
74
156
  export {};
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "type": "module",
3
3
  "name": "@rvoh/psychic-workers",
4
4
  "description": "Background job system for Psychic applications",
5
- "version": "2.6.0",
5
+ "version": "2.7.0",
6
6
  "author": "RVO Health",
7
7
  "publishConfig": {
8
8
  "access": "public"