@strav/queue 0.3.19 → 0.3.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strav/queue",
3
- "version": "0.3.19",
3
+ "version": "0.3.21",
4
4
  "type": "module",
5
5
  "description": "Background job processing and task scheduling for the Strav framework",
6
6
  "license": "MIT",
@@ -28,8 +28,8 @@
28
28
  "./providers/*": "./src/providers/*.ts"
29
29
  },
30
30
  "peerDependencies": {
31
- "@strav/kernel": "0.3.19",
32
- "@strav/database": "0.3.19"
31
+ "@strav/kernel": "0.3.21",
32
+ "@strav/database": "0.3.21"
33
33
  },
34
34
  "scripts": {
35
35
  "test": "bun test tests/",
@@ -38,6 +38,7 @@ export class Schedule {
38
38
 
39
39
  private _cron: CronExpression | null = null
40
40
  private _noOverlap = false
41
+ private _runImmediately = false
41
42
 
42
43
  private _sporadicMin: number | null = null
43
44
  private _sporadicMax: number | null = null
@@ -179,6 +180,22 @@ export class Schedule {
179
180
  return this
180
181
  }
181
182
 
183
+ /**
184
+ * Execute this task immediately upon registration, then follow the configured schedule.
185
+ * Useful for bootstrap tasks, cache warming, or ensuring tasks run on deployment.
186
+ */
187
+ runImmediately(): this {
188
+ this._runImmediately = true
189
+
190
+ // Execute the handler immediately
191
+ this.executeHandler().catch(error => {
192
+ const message = error instanceof Error ? error.message : String(error)
193
+ console.error(`[scheduler] Immediate execution of "${this.name}" failed: ${message}`)
194
+ })
195
+
196
+ return this
197
+ }
198
+
182
199
  // ── Internal ──────────────────────────────────────────────────────────────
183
200
 
184
201
  /** Check if this task is due at the given Date (evaluated in UTC). */
@@ -201,6 +218,11 @@ export class Schedule {
201
218
  return this._noOverlap
202
219
  }
203
220
 
221
+ /** Whether this task should run immediately upon registration. */
222
+ get shouldRunImmediately(): boolean {
223
+ return this._runImmediately
224
+ }
225
+
204
226
  /** The parsed cron expression (for testing/debugging). */
205
227
  get expression(): CronExpression | null {
206
228
  return this._cron
@@ -211,6 +233,14 @@ export class Schedule {
211
233
  return this._nextRunAt
212
234
  }
213
235
 
236
+ /** Execute the task handler, handling both sync and async cases. */
237
+ private async executeHandler(): Promise<void> {
238
+ const result = this.handler()
239
+ if (result instanceof Promise) {
240
+ await result
241
+ }
242
+ }
243
+
214
244
  /** Compute the next random run time from a reference point. */
215
245
  private computeNextRun(from: Date): Date {
216
246
  const ms = unitToMs(this._sporadicUnit!)
@@ -40,6 +40,30 @@ export default class Scheduler {
40
40
  return Scheduler._tasks.filter(t => t.isDue(date))
41
41
  }
42
42
 
43
+ /**
44
+ * Manually execute a task by name immediately.
45
+ *
46
+ * @param name The name of the task to execute
47
+ * @returns Promise that resolves when the task completes
48
+ * @throws Error if task is not found
49
+ */
50
+ static async runNow(name: string): Promise<void> {
51
+ const task = Scheduler._tasks.find(t => t.name === name)
52
+ if (!task) {
53
+ throw new Error(`Task "${name}" not found. Available tasks: ${Scheduler._tasks.map(t => t.name).join(', ')}`)
54
+ }
55
+
56
+ try {
57
+ const result = task.handler()
58
+ if (result instanceof Promise) {
59
+ await result
60
+ }
61
+ } catch (error) {
62
+ const message = error instanceof Error ? error.message : String(error)
63
+ throw new Error(`Manual execution of task "${name}" failed: ${message}`)
64
+ }
65
+ }
66
+
43
67
  /** Clear all registered tasks. For testing. */
44
68
  static reset(): void {
45
69
  Scheduler._tasks = []