@twin.org/background-task-scheduler 0.0.3-next.1 → 0.0.3-next.10

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
@@ -1,6 +1,6 @@
1
1
  # TWIN Background Task Scheduler
2
2
 
3
- Schedule background tasks to run at a specific interval or time.
3
+ This package is part of the background task toolkit and helps build reliable asynchronous workflows in TWIN applications.
4
4
 
5
5
  ## Installation
6
6
 
@@ -0,0 +1,29 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { entity, property } from "@twin.org/entity";
4
+ /**
5
+ * Class defining a scheduled task.
6
+ */
7
+ let ScheduledTask = class ScheduledTask {
8
+ /**
9
+ * The id.
10
+ */
11
+ id;
12
+ /**
13
+ * The last run time of the task, if undefined waiting for next run.
14
+ */
15
+ lastRunTime;
16
+ };
17
+ __decorate([
18
+ property({ type: "string", isPrimary: true }),
19
+ __metadata("design:type", String)
20
+ ], ScheduledTask.prototype, "id", void 0);
21
+ __decorate([
22
+ property({ type: "integer", optional: true, format: "uint64" }),
23
+ __metadata("design:type", Number)
24
+ ], ScheduledTask.prototype, "lastRunTime", void 0);
25
+ ScheduledTask = __decorate([
26
+ entity()
27
+ ], ScheduledTask);
28
+ export { ScheduledTask };
29
+ //# sourceMappingURL=scheduledTask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduledTask.js","sourceRoot":"","sources":["../../../src/entities/scheduledTask.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;GAEG;AAEI,IAAM,aAAa,GAAnB,MAAM,aAAa;IACzB;;OAEG;IAEI,EAAE,CAAU;IAEnB;;OAEG;IAEI,WAAW,CAAU;CAC5B,CAAA;AAPO;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;;yCAC3B;AAMZ;IADN,QAAQ,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;;kDACpC;AAXhB,aAAa;IADzB,MAAM,EAAE;GACI,aAAa,CAYzB","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { entity, property } from \"@twin.org/entity\";\n\n/**\n * Class defining a scheduled task.\n */\n@entity()\nexport class ScheduledTask {\n\t/**\n\t * The id.\n\t */\n\t@property({ type: \"string\", isPrimary: true })\n\tpublic id!: string;\n\n\t/**\n\t * The last run time of the task, if undefined waiting for next run.\n\t */\n\t@property({ type: \"integer\", optional: true, format: \"uint64\" })\n\tpublic lastRunTime?: number;\n}\n"]}
package/dist/es/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  // Copyright 2024 IOTA Stiftung.
2
2
  // SPDX-License-Identifier: Apache-2.0.
3
+ export * from "./entities/scheduledTask.js";
3
4
  export * from "./models/ITaskSchedulerConfig.js";
4
5
  export * from "./models/ITaskSchedulerConstructorOptions.js";
6
+ export * from "./schema.js";
5
7
  export * from "./taskSchedulerService.js";
6
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,kCAAkC,CAAC;AACjD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,2BAA2B,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./models/ITaskSchedulerConfig.js\";\nexport * from \"./models/ITaskSchedulerConstructorOptions.js\";\nexport * from \"./taskSchedulerService.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,kCAAkC,CAAC;AACjD,cAAc,8CAA8C,CAAC;AAC7D,cAAc,aAAa,CAAC;AAC5B,cAAc,2BAA2B,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nexport * from \"./entities/scheduledTask.js\";\nexport * from \"./models/ITaskSchedulerConfig.js\";\nexport * from \"./models/ITaskSchedulerConstructorOptions.js\";\nexport * from \"./schema.js\";\nexport * from \"./taskSchedulerService.js\";\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ITaskSchedulerConfig.js","sourceRoot":"","sources":["../../../src/models/ITaskSchedulerConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Interface for the task scheduler configuration.\n */\nexport interface ITaskSchedulerConfig {\n\t/**\n\t * The interval between checks for running tasks, defaults to 1 minute since that is the resolution of the tasks.\n\t * @default 60000\n\t */\n\toverrideInterval?: number;\n}\n"]}
1
+ {"version":3,"file":"ITaskSchedulerConfig.js","sourceRoot":"","sources":["../../../src/models/ITaskSchedulerConfig.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\n\n/**\n * Interface for the task scheduler configuration.\n */\nexport interface ITaskSchedulerConfig {\n\t/**\n\t * The interval between checks for running tasks, defaults to 1 minute since that is the resolution of the tasks.\n\t * @default 60000\n\t */\n\tintervalMs?: number;\n\n\t/**\n\t * The time in milliseconds after which a task that is still marked as running is considered stalled and can be run again.\n\t * @default 300000\n\t */\n\tstalledTaskTimeoutMs?: number;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ITaskSchedulerConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/ITaskSchedulerConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITaskSchedulerConfig } from \"./ITaskSchedulerConfig.js\";\n\n/**\n * Options for the task scheduler constructor.\n */\nexport interface ITaskSchedulerConstructorOptions {\n\t/**\n\t * The logging component type.\n\t * @default logging\n\t */\n\tloggingComponentType?: string;\n\n\t/**\n\t * The configuration for the task scheduler.\n\t */\n\tconfig?: ITaskSchedulerConfig;\n}\n"]}
1
+ {"version":3,"file":"ITaskSchedulerConstructorOptions.js","sourceRoot":"","sources":["../../../src/models/ITaskSchedulerConstructorOptions.ts"],"names":[],"mappings":"","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type { ITaskSchedulerConfig } from \"./ITaskSchedulerConfig.js\";\n\n/**\n * Options for the task scheduler constructor.\n */\nexport interface ITaskSchedulerConstructorOptions {\n\t/**\n\t * The logging component type.\n\t * @default logging\n\t */\n\tloggingComponentType?: string;\n\n\t/**\n\t * The scheduled task entity storage connector type.\n\t * @default scheduled-task\n\t */\n\tscheduledTaskEntityStorageType?: string;\n\n\t/**\n\t * The configuration for the task scheduler.\n\t */\n\tconfig?: ITaskSchedulerConfig;\n}\n"]}
@@ -0,0 +1,11 @@
1
+ // Copyright 2024 IOTA Stiftung.
2
+ // SPDX-License-Identifier: Apache-2.0.
3
+ import { EntitySchemaFactory, EntitySchemaHelper } from "@twin.org/entity";
4
+ import { ScheduledTask } from "./entities/scheduledTask.js";
5
+ /**
6
+ * Initialize the schema for the scheduled task service entity storage.
7
+ */
8
+ export function initSchema() {
9
+ EntitySchemaFactory.register("ScheduledTask", () => EntitySchemaHelper.getSchema(ScheduledTask));
10
+ }
11
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/schema.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,uCAAuC;AACvC,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAE3E,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE5D;;GAEG;AACH,MAAM,UAAU,UAAU;IACzB,mBAAmB,CAAC,QAAQ,kBAA0B,GAAG,EAAE,CAC1D,kBAAkB,CAAC,SAAS,CAAC,aAAa,CAAC,CAC3C,CAAC;AACH,CAAC","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport { EntitySchemaFactory, EntitySchemaHelper } from \"@twin.org/entity\";\nimport { nameof } from \"@twin.org/nameof\";\nimport { ScheduledTask } from \"./entities/scheduledTask.js\";\n\n/**\n * Initialize the schema for the scheduled task service entity storage.\n */\nexport function initSchema(): void {\n\tEntitySchemaFactory.register(nameof<ScheduledTask>(), () =>\n\t\tEntitySchemaHelper.getSchema(ScheduledTask)\n\t);\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import { BaseError, ComponentFactory, Is } from "@twin.org/core";
2
+ import { EntityStorageConnectorFactory } from "@twin.org/entity-storage-models";
2
3
  /**
3
4
  * Class for scheduling tasks.
4
5
  */
@@ -12,16 +13,31 @@ export class TaskSchedulerService {
12
13
  * @internal
13
14
  */
14
15
  _logging;
16
+ /**
17
+ * The entity storage for the scheduled tasks.
18
+ * @internal
19
+ */
20
+ _scheduledTaskEntityStorageConnector;
15
21
  /**
16
22
  * The interval in milliseconds at which the tasks are checked.
17
23
  * @internal
18
24
  */
19
- _tickInterval;
25
+ _tickIntervalMs;
26
+ /**
27
+ * The timeout in milliseconds after which an in-progress task is considered stalled.
28
+ * @internal
29
+ */
30
+ _stalledTaskTimeoutMs;
20
31
  /**
21
32
  * The tasks that are scheduled.
22
33
  * @internal
23
34
  */
24
35
  _tasks;
36
+ /**
37
+ * The tasks currently running in this scheduler instance.
38
+ * @internal
39
+ */
40
+ _runningTasks;
25
41
  /**
26
42
  * The timer for running scheduled tasks.
27
43
  * @internal
@@ -32,9 +48,12 @@ export class TaskSchedulerService {
32
48
  * @param options The options for the scheduler.
33
49
  */
34
50
  constructor(options) {
51
+ this._scheduledTaskEntityStorageConnector = EntityStorageConnectorFactory.get(options?.scheduledTaskEntityStorageType ?? "scheduled-task");
35
52
  this._logging = ComponentFactory.getIfExists(options?.loggingComponentType ?? "logging");
36
53
  this._tasks = {};
37
- this._tickInterval = options?.config?.overrideInterval ?? 60 * 1000; // Default to 1 minute
54
+ this._runningTasks = [];
55
+ this._tickIntervalMs = options?.config?.intervalMs ?? 60 * 1000; // 1 minute
56
+ this._stalledTaskTimeoutMs = options?.config?.stalledTaskTimeoutMs ?? 5 * 60 * 1000; // 5 minutes
38
57
  }
39
58
  /**
40
59
  * Returns the class name of the component.
@@ -50,6 +69,15 @@ export class TaskSchedulerService {
50
69
  */
51
70
  async stop(nodeLoggingComponentType) {
52
71
  this.stopTimer();
72
+ // If we had any running tasks, we reset their last run time to allow them to be
73
+ // triggered by other components
74
+ for (const taskId of this._runningTasks) {
75
+ await this._scheduledTaskEntityStorageConnector.set({
76
+ id: taskId,
77
+ lastRunTime: undefined
78
+ });
79
+ }
80
+ this._runningTasks = [];
53
81
  }
54
82
  /**
55
83
  * Add a task to the scheduler.
@@ -145,7 +173,7 @@ export class TaskSchedulerService {
145
173
  // Trigger immediately to catch up on any missed tasks
146
174
  await this.triggerScheduledTasks();
147
175
  // Set the timer to run at the specified interval
148
- this._timer = setInterval(async () => this.triggerScheduledTasks(), this._tickInterval);
176
+ this._timer = setInterval(async () => this.triggerScheduledTasks(), this._tickIntervalMs);
149
177
  }
150
178
  }
151
179
  /**
@@ -168,18 +196,48 @@ export class TaskSchedulerService {
168
196
  const task = this._tasks[taskId];
169
197
  for (const taskTime of task.times) {
170
198
  if (!Is.empty(taskTime.nextTriggerTime) && taskTime.nextTriggerTime <= now) {
171
- await this._logging?.log({
172
- level: "info",
173
- source: TaskSchedulerService.CLASS_NAME,
174
- ts: Date.now(),
175
- message: "taskTriggered",
176
- data: {
177
- id: taskId,
178
- time: new Date(taskTime.nextTriggerTime).toISOString()
179
- }
180
- });
199
+ let taskStarted = false;
181
200
  try {
182
- await task.taskCallback();
201
+ const scheduledTask = await this._scheduledTaskEntityStorageConnector.get(taskId);
202
+ const lastRunTime = scheduledTask?.lastRunTime;
203
+ const taskInProgress = !Is.empty(lastRunTime);
204
+ const taskStalled = taskInProgress && now - lastRunTime >= this._stalledTaskTimeoutMs;
205
+ if (taskStalled) {
206
+ await this._logging?.log({
207
+ level: "warn",
208
+ source: TaskSchedulerService.CLASS_NAME,
209
+ ts: Date.now(),
210
+ message: "taskStalled",
211
+ data: {
212
+ id: taskId,
213
+ lastRunTime,
214
+ stalledForMs: now - (lastRunTime ?? now),
215
+ stalledTaskTimeoutMs: this._stalledTaskTimeoutMs
216
+ }
217
+ });
218
+ }
219
+ if (!taskInProgress || taskStalled) {
220
+ await this._logging?.log({
221
+ level: "info",
222
+ source: TaskSchedulerService.CLASS_NAME,
223
+ ts: Date.now(),
224
+ message: "taskTriggered",
225
+ data: {
226
+ id: taskId,
227
+ time: new Date(taskTime.nextTriggerTime).toISOString()
228
+ }
229
+ });
230
+ // Update the last run time of the task to prevent multiple triggers in case of long running tasks
231
+ await this._scheduledTaskEntityStorageConnector.set({
232
+ id: taskId,
233
+ lastRunTime: Date.now()
234
+ });
235
+ if (!this._runningTasks.includes(taskId)) {
236
+ this._runningTasks.push(taskId);
237
+ }
238
+ taskStarted = true;
239
+ await task.taskCallback();
240
+ }
183
241
  }
184
242
  catch (error) {
185
243
  await this._logging?.log({
@@ -193,6 +251,20 @@ export class TaskSchedulerService {
193
251
  error: BaseError.fromError(error)
194
252
  });
195
253
  }
254
+ finally {
255
+ if (taskStarted) {
256
+ // Reset the last run time to allow future triggers, even if the task callback fails
257
+ await this._scheduledTaskEntityStorageConnector.set({
258
+ id: taskId,
259
+ lastRunTime: undefined
260
+ });
261
+ // Remove the task from the running tasks list
262
+ const index = this._runningTasks.indexOf(taskId);
263
+ if (index >= 0) {
264
+ this._runningTasks.splice(index, 1);
265
+ }
266
+ }
267
+ }
196
268
  // If the intervals are empty, we do not recalculate a next run time
197
269
  if (Is.empty(taskTime.intervalDays) &&
198
270
  Is.empty(taskTime.intervalHours) &&
@@ -1 +1 @@
1
- {"version":3,"file":"taskSchedulerService.js","sourceRoot":"","sources":["../../src/taskSchedulerService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIScheduledTaskInfo,\n\tIScheduledTaskTime,\n\tITaskSchedulerComponent\n} from \"@twin.org/background-task-models\";\nimport { BaseError, ComponentFactory, Is } from \"@twin.org/core\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { ITaskSchedulerConstructorOptions } from \"./models/ITaskSchedulerConstructorOptions.js\";\n\n/**\n * Class for scheduling tasks.\n */\nexport class TaskSchedulerService implements ITaskSchedulerComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TaskSchedulerService>();\n\n\t/**\n\t * The logger for the task service.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The interval in milliseconds at which the tasks are checked.\n\t * @internal\n\t */\n\tprivate readonly _tickInterval: number;\n\n\t/**\n\t * The tasks that are scheduled.\n\t * @internal\n\t */\n\tprivate readonly _tasks: {\n\t\t[id: string]: {\n\t\t\ttimes: IScheduledTaskTime[];\n\t\t\ttaskCallback: () => Promise<void>;\n\t\t};\n\t};\n\n\t/**\n\t * The timer for running scheduled tasks.\n\t * @internal\n\t */\n\tprivate _timer?: NodeJS.Timeout;\n\n\t/**\n\t * Create a new instance of TaskSchedulerComponent.\n\t * @param options The options for the scheduler.\n\t */\n\tconstructor(options?: ITaskSchedulerConstructorOptions) {\n\t\tthis._logging = ComponentFactory.getIfExists(options?.loggingComponentType ?? \"logging\");\n\t\tthis._tasks = {};\n\t\tthis._tickInterval = options?.config?.overrideInterval ?? 60 * 1000; // Default to 1 minute\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn TaskSchedulerService.CLASS_NAME;\n\t}\n\n\t/**\n\t * The component needs to be stopped when the node is closed.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns Nothing.\n\t */\n\tpublic async stop(nodeLoggingComponentType?: string): Promise<void> {\n\t\tthis.stopTimer();\n\t}\n\n\t/**\n\t * Add a task to the scheduler.\n\t * @param taskId The id of the task to add.\n\t * @param times The times at which the task should be scheduled.\n\t * @param taskCallback The callback to execute when the task is scheduled.\n\t * @returns Nothing.\n\t */\n\tpublic async addTask(\n\t\ttaskId: string,\n\t\ttimes: IScheduledTaskTime[],\n\t\ttaskCallback: () => Promise<void>\n\t): Promise<void> {\n\t\tthis._tasks[taskId] = {\n\t\t\ttimes: times.map(time => ({\n\t\t\t\t...time,\n\t\t\t\tnextTriggerTime: Is.empty(time.nextTriggerTime)\n\t\t\t\t\t? this.calculateNextTriggerTime(time)\n\t\t\t\t\t: time.nextTriggerTime\n\t\t\t})),\n\t\t\ttaskCallback\n\t\t};\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: TaskSchedulerService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"taskAdded\",\n\t\t\tdata: {\n\t\t\t\tid: taskId\n\t\t\t}\n\t\t});\n\n\t\tawait this.startTimer();\n\t}\n\n\t/**\n\t * Remove a task from the scheduler.\n\t * @param taskId The id of the task to remove.\n\t * @returns Nothing.\n\t */\n\tpublic async removeTask(taskId: string): Promise<void> {\n\t\tif (!Is.empty(this._tasks[taskId])) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: TaskSchedulerService.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"taskRemoved\",\n\t\t\t\tdata: {\n\t\t\t\t\tid: taskId\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tdelete this._tasks[taskId];\n\n\t\t\tif (Object.keys(this._tasks).length === 0) {\n\t\t\t\tthis.stopTimer();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the information about the tasks.\n\t * @returns The tasks information.\n\t */\n\tpublic async tasksInfo(): Promise<IScheduledTaskInfo> {\n\t\tconst tasksInfo: IScheduledTaskInfo = {\n\t\t\ttasks: {}\n\t\t};\n\t\tfor (const taskId in this._tasks) {\n\t\t\ttasksInfo.tasks[taskId] = this._tasks[taskId].times;\n\t\t}\n\t\treturn tasksInfo;\n\t}\n\n\t/**\n\t * Calculate the next run time for a task based on its scheduled times.\n\t * @param time The times at which the task should be scheduled.\n\t * @returns The update time with the next run.\n\t * @internal\n\t */\n\tprivate calculateNextTriggerTime(time: IScheduledTaskTime): number {\n\t\tlet nextTriggerTime = time.nextTriggerTime;\n\n\t\tif (Is.empty(nextTriggerTime)) {\n\t\t\tnextTriggerTime = Date.now();\n\t\t}\n\n\t\tif (!Is.empty(time.intervalDays)) {\n\t\t\tnextTriggerTime += time.intervalDays * 24 * 60 * 60 * 1000;\n\t\t}\n\n\t\tif (!Is.empty(time.intervalHours)) {\n\t\t\tnextTriggerTime += time.intervalHours * 60 * 60 * 1000;\n\t\t}\n\n\t\tif (!Is.empty(time.intervalMinutes)) {\n\t\t\tnextTriggerTime += time.intervalMinutes * 60 * 1000;\n\t\t}\n\n\t\treturn nextTriggerTime;\n\t}\n\n\t/**\n\t * Start the timer for running scheduled tasks.\n\t * @internal\n\t */\n\tprivate async startTimer(): Promise<void> {\n\t\tif (Is.empty(this._timer)) {\n\t\t\t// Trigger immediately to catch up on any missed tasks\n\t\t\tawait this.triggerScheduledTasks();\n\t\t\t// Set the timer to run at the specified interval\n\t\t\tthis._timer = setInterval(async () => this.triggerScheduledTasks(), this._tickInterval);\n\t\t}\n\t}\n\n\t/**\n\t * Stop the timer for running scheduled tasks.\n\t * @internal\n\t */\n\tprivate stopTimer(): void {\n\t\tif (!Is.empty(this._timer)) {\n\t\t\tclearInterval(this._timer);\n\t\t\tthis._timer = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Trigger scheduled tasks based on their next run times.\n\t * @internal\n\t */\n\tprivate async triggerScheduledTasks(): Promise<void> {\n\t\tconst now = Date.now();\n\n\t\tfor (const taskId in this._tasks) {\n\t\t\tconst task = this._tasks[taskId];\n\n\t\t\tfor (const taskTime of task.times) {\n\t\t\t\tif (!Is.empty(taskTime.nextTriggerTime) && taskTime.nextTriggerTime <= now) {\n\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\tsource: TaskSchedulerService.CLASS_NAME,\n\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t\tmessage: \"taskTriggered\",\n\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\tid: taskId,\n\t\t\t\t\t\t\ttime: new Date(taskTime.nextTriggerTime).toISOString()\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait task.taskCallback();\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\t\t\tsource: TaskSchedulerService.CLASS_NAME,\n\t\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t\t\tmessage: \"taskFailed\",\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tid: taskId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\terror: BaseError.fromError(error)\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\n\t\t\t\t\t// If the intervals are empty, we do not recalculate a next run time\n\t\t\t\t\tif (\n\t\t\t\t\t\tIs.empty(taskTime.intervalDays) &&\n\t\t\t\t\t\tIs.empty(taskTime.intervalHours) &&\n\t\t\t\t\t\tIs.empty(taskTime.intervalMinutes)\n\t\t\t\t\t) {\n\t\t\t\t\t\ttaskTime.nextTriggerTime = undefined;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Recalculate the next run time based on the current time and the intervals\n\t\t\t\t\t\ttaskTime.nextTriggerTime = this.calculateNextTriggerTime(taskTime);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"taskSchedulerService.js","sourceRoot":"","sources":["../../src/taskSchedulerService.ts"],"names":[],"mappings":"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","sourcesContent":["// Copyright 2024 IOTA Stiftung.\n// SPDX-License-Identifier: Apache-2.0.\nimport type {\n\tIScheduledTaskInfo,\n\tIScheduledTaskTime,\n\tITaskSchedulerComponent\n} from \"@twin.org/background-task-models\";\nimport { BaseError, ComponentFactory, Is } from \"@twin.org/core\";\nimport {\n\tEntityStorageConnectorFactory,\n\ttype IEntityStorageConnector\n} from \"@twin.org/entity-storage-models\";\nimport type { ILoggingComponent } from \"@twin.org/logging-models\";\nimport { nameof } from \"@twin.org/nameof\";\nimport type { ScheduledTask } from \"./entities/scheduledTask.js\";\nimport type { ITaskSchedulerConstructorOptions } from \"./models/ITaskSchedulerConstructorOptions.js\";\n\n/**\n * Class for scheduling tasks.\n */\nexport class TaskSchedulerService implements ITaskSchedulerComponent {\n\t/**\n\t * Runtime name for the class.\n\t */\n\tpublic static readonly CLASS_NAME: string = nameof<TaskSchedulerService>();\n\n\t/**\n\t * The logger for the task service.\n\t * @internal\n\t */\n\tprivate readonly _logging?: ILoggingComponent;\n\n\t/**\n\t * The entity storage for the scheduled tasks.\n\t * @internal\n\t */\n\tprivate readonly _scheduledTaskEntityStorageConnector: IEntityStorageConnector<ScheduledTask>;\n\n\t/**\n\t * The interval in milliseconds at which the tasks are checked.\n\t * @internal\n\t */\n\tprivate readonly _tickIntervalMs: number;\n\n\t/**\n\t * The timeout in milliseconds after which an in-progress task is considered stalled.\n\t * @internal\n\t */\n\tprivate readonly _stalledTaskTimeoutMs: number;\n\n\t/**\n\t * The tasks that are scheduled.\n\t * @internal\n\t */\n\tprivate readonly _tasks: {\n\t\t[id: string]: {\n\t\t\ttimes: IScheduledTaskTime[];\n\t\t\ttaskCallback: () => Promise<void>;\n\t\t};\n\t};\n\n\t/**\n\t * The tasks currently running in this scheduler instance.\n\t * @internal\n\t */\n\tprivate _runningTasks: string[];\n\n\t/**\n\t * The timer for running scheduled tasks.\n\t * @internal\n\t */\n\tprivate _timer?: NodeJS.Timeout;\n\n\t/**\n\t * Create a new instance of TaskSchedulerComponent.\n\t * @param options The options for the scheduler.\n\t */\n\tconstructor(options?: ITaskSchedulerConstructorOptions) {\n\t\tthis._scheduledTaskEntityStorageConnector = EntityStorageConnectorFactory.get(\n\t\t\toptions?.scheduledTaskEntityStorageType ?? \"scheduled-task\"\n\t\t);\n\t\tthis._logging = ComponentFactory.getIfExists(options?.loggingComponentType ?? \"logging\");\n\t\tthis._tasks = {};\n\t\tthis._runningTasks = [];\n\t\tthis._tickIntervalMs = options?.config?.intervalMs ?? 60 * 1000; // 1 minute\n\t\tthis._stalledTaskTimeoutMs = options?.config?.stalledTaskTimeoutMs ?? 5 * 60 * 1000; // 5 minutes\n\t}\n\n\t/**\n\t * Returns the class name of the component.\n\t * @returns The class name of the component.\n\t */\n\tpublic className(): string {\n\t\treturn TaskSchedulerService.CLASS_NAME;\n\t}\n\n\t/**\n\t * The component needs to be stopped when the node is closed.\n\t * @param nodeLoggingComponentType The node logging component type.\n\t * @returns Nothing.\n\t */\n\tpublic async stop(nodeLoggingComponentType?: string): Promise<void> {\n\t\tthis.stopTimer();\n\n\t\t// If we had any running tasks, we reset their last run time to allow them to be\n\t\t// triggered by other components\n\t\tfor (const taskId of this._runningTasks) {\n\t\t\tawait this._scheduledTaskEntityStorageConnector.set({\n\t\t\t\tid: taskId,\n\t\t\t\tlastRunTime: undefined\n\t\t\t});\n\t\t}\n\t\tthis._runningTasks = [];\n\t}\n\n\t/**\n\t * Add a task to the scheduler.\n\t * @param taskId The id of the task to add.\n\t * @param times The times at which the task should be scheduled.\n\t * @param taskCallback The callback to execute when the task is scheduled.\n\t * @returns Nothing.\n\t */\n\tpublic async addTask(\n\t\ttaskId: string,\n\t\ttimes: IScheduledTaskTime[],\n\t\ttaskCallback: () => Promise<void>\n\t): Promise<void> {\n\t\tthis._tasks[taskId] = {\n\t\t\ttimes: times.map(time => ({\n\t\t\t\t...time,\n\t\t\t\tnextTriggerTime: Is.empty(time.nextTriggerTime)\n\t\t\t\t\t? this.calculateNextTriggerTime(time)\n\t\t\t\t\t: time.nextTriggerTime\n\t\t\t})),\n\t\t\ttaskCallback\n\t\t};\n\n\t\tawait this._logging?.log({\n\t\t\tlevel: \"info\",\n\t\t\tsource: TaskSchedulerService.CLASS_NAME,\n\t\t\tts: Date.now(),\n\t\t\tmessage: \"taskAdded\",\n\t\t\tdata: {\n\t\t\t\tid: taskId\n\t\t\t}\n\t\t});\n\n\t\tawait this.startTimer();\n\t}\n\n\t/**\n\t * Remove a task from the scheduler.\n\t * @param taskId The id of the task to remove.\n\t * @returns Nothing.\n\t */\n\tpublic async removeTask(taskId: string): Promise<void> {\n\t\tif (!Is.empty(this._tasks[taskId])) {\n\t\t\tawait this._logging?.log({\n\t\t\t\tlevel: \"info\",\n\t\t\t\tsource: TaskSchedulerService.CLASS_NAME,\n\t\t\t\tts: Date.now(),\n\t\t\t\tmessage: \"taskRemoved\",\n\t\t\t\tdata: {\n\t\t\t\t\tid: taskId\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tdelete this._tasks[taskId];\n\n\t\t\tif (Object.keys(this._tasks).length === 0) {\n\t\t\t\tthis.stopTimer();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Get the information about the tasks.\n\t * @returns The tasks information.\n\t */\n\tpublic async tasksInfo(): Promise<IScheduledTaskInfo> {\n\t\tconst tasksInfo: IScheduledTaskInfo = {\n\t\t\ttasks: {}\n\t\t};\n\t\tfor (const taskId in this._tasks) {\n\t\t\ttasksInfo.tasks[taskId] = this._tasks[taskId].times;\n\t\t}\n\t\treturn tasksInfo;\n\t}\n\n\t/**\n\t * Calculate the next run time for a task based on its scheduled times.\n\t * @param time The times at which the task should be scheduled.\n\t * @returns The update time with the next run.\n\t * @internal\n\t */\n\tprivate calculateNextTriggerTime(time: IScheduledTaskTime): number {\n\t\tlet nextTriggerTime = time.nextTriggerTime;\n\n\t\tif (Is.empty(nextTriggerTime)) {\n\t\t\tnextTriggerTime = Date.now();\n\t\t}\n\n\t\tif (!Is.empty(time.intervalDays)) {\n\t\t\tnextTriggerTime += time.intervalDays * 24 * 60 * 60 * 1000;\n\t\t}\n\n\t\tif (!Is.empty(time.intervalHours)) {\n\t\t\tnextTriggerTime += time.intervalHours * 60 * 60 * 1000;\n\t\t}\n\n\t\tif (!Is.empty(time.intervalMinutes)) {\n\t\t\tnextTriggerTime += time.intervalMinutes * 60 * 1000;\n\t\t}\n\n\t\treturn nextTriggerTime;\n\t}\n\n\t/**\n\t * Start the timer for running scheduled tasks.\n\t * @internal\n\t */\n\tprivate async startTimer(): Promise<void> {\n\t\tif (Is.empty(this._timer)) {\n\t\t\t// Trigger immediately to catch up on any missed tasks\n\t\t\tawait this.triggerScheduledTasks();\n\t\t\t// Set the timer to run at the specified interval\n\t\t\tthis._timer = setInterval(async () => this.triggerScheduledTasks(), this._tickIntervalMs);\n\t\t}\n\t}\n\n\t/**\n\t * Stop the timer for running scheduled tasks.\n\t * @internal\n\t */\n\tprivate stopTimer(): void {\n\t\tif (!Is.empty(this._timer)) {\n\t\t\tclearInterval(this._timer);\n\t\t\tthis._timer = undefined;\n\t\t}\n\t}\n\n\t/**\n\t * Trigger scheduled tasks based on their next run times.\n\t * @internal\n\t */\n\tprivate async triggerScheduledTasks(): Promise<void> {\n\t\tconst now = Date.now();\n\n\t\tfor (const taskId in this._tasks) {\n\t\t\tconst task = this._tasks[taskId];\n\n\t\t\tfor (const taskTime of task.times) {\n\t\t\t\tif (!Is.empty(taskTime.nextTriggerTime) && taskTime.nextTriggerTime <= now) {\n\t\t\t\t\tlet taskStarted = false;\n\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst scheduledTask = await this._scheduledTaskEntityStorageConnector.get(taskId);\n\t\t\t\t\t\tconst lastRunTime = scheduledTask?.lastRunTime;\n\t\t\t\t\t\tconst taskInProgress = !Is.empty(lastRunTime);\n\t\t\t\t\t\tconst taskStalled = taskInProgress && now - lastRunTime >= this._stalledTaskTimeoutMs;\n\n\t\t\t\t\t\tif (taskStalled) {\n\t\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\t\tlevel: \"warn\",\n\t\t\t\t\t\t\t\tsource: TaskSchedulerService.CLASS_NAME,\n\t\t\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t\t\t\tmessage: \"taskStalled\",\n\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\tid: taskId,\n\t\t\t\t\t\t\t\t\tlastRunTime,\n\t\t\t\t\t\t\t\t\tstalledForMs: now - (lastRunTime ?? now),\n\t\t\t\t\t\t\t\t\tstalledTaskTimeoutMs: this._stalledTaskTimeoutMs\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (!taskInProgress || taskStalled) {\n\t\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\t\tlevel: \"info\",\n\t\t\t\t\t\t\t\tsource: TaskSchedulerService.CLASS_NAME,\n\t\t\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t\t\t\tmessage: \"taskTriggered\",\n\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\tid: taskId,\n\t\t\t\t\t\t\t\t\ttime: new Date(taskTime.nextTriggerTime).toISOString()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Update the last run time of the task to prevent multiple triggers in case of long running tasks\n\t\t\t\t\t\t\tawait this._scheduledTaskEntityStorageConnector.set({\n\t\t\t\t\t\t\t\tid: taskId,\n\t\t\t\t\t\t\t\tlastRunTime: Date.now()\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\tif (!this._runningTasks.includes(taskId)) {\n\t\t\t\t\t\t\t\tthis._runningTasks.push(taskId);\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttaskStarted = true;\n\t\t\t\t\t\t\tawait task.taskCallback();\n\t\t\t\t\t\t}\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tawait this._logging?.log({\n\t\t\t\t\t\t\tlevel: \"error\",\n\t\t\t\t\t\t\tsource: TaskSchedulerService.CLASS_NAME,\n\t\t\t\t\t\t\tts: Date.now(),\n\t\t\t\t\t\t\tmessage: \"taskFailed\",\n\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\tid: taskId\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\terror: BaseError.fromError(error)\n\t\t\t\t\t\t});\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (taskStarted) {\n\t\t\t\t\t\t\t// Reset the last run time to allow future triggers, even if the task callback fails\n\t\t\t\t\t\t\tawait this._scheduledTaskEntityStorageConnector.set({\n\t\t\t\t\t\t\t\tid: taskId,\n\t\t\t\t\t\t\t\tlastRunTime: undefined\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\t// Remove the task from the running tasks list\n\t\t\t\t\t\t\tconst index = this._runningTasks.indexOf(taskId);\n\t\t\t\t\t\t\tif (index >= 0) {\n\t\t\t\t\t\t\t\tthis._runningTasks.splice(index, 1);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// If the intervals are empty, we do not recalculate a next run time\n\t\t\t\t\tif (\n\t\t\t\t\t\tIs.empty(taskTime.intervalDays) &&\n\t\t\t\t\t\tIs.empty(taskTime.intervalHours) &&\n\t\t\t\t\t\tIs.empty(taskTime.intervalMinutes)\n\t\t\t\t\t) {\n\t\t\t\t\t\ttaskTime.nextTriggerTime = undefined;\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Recalculate the next run time based on the current time and the intervals\n\t\t\t\t\t\ttaskTime.nextTriggerTime = this.calculateNextTriggerTime(taskTime);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Class defining a scheduled task.
3
+ */
4
+ export declare class ScheduledTask {
5
+ /**
6
+ * The id.
7
+ */
8
+ id: string;
9
+ /**
10
+ * The last run time of the task, if undefined waiting for next run.
11
+ */
12
+ lastRunTime?: number;
13
+ }
@@ -1,3 +1,5 @@
1
+ export * from "./entities/scheduledTask.js";
1
2
  export * from "./models/ITaskSchedulerConfig.js";
2
3
  export * from "./models/ITaskSchedulerConstructorOptions.js";
4
+ export * from "./schema.js";
3
5
  export * from "./taskSchedulerService.js";
@@ -6,5 +6,10 @@ export interface ITaskSchedulerConfig {
6
6
  * The interval between checks for running tasks, defaults to 1 minute since that is the resolution of the tasks.
7
7
  * @default 60000
8
8
  */
9
- overrideInterval?: number;
9
+ intervalMs?: number;
10
+ /**
11
+ * The time in milliseconds after which a task that is still marked as running is considered stalled and can be run again.
12
+ * @default 300000
13
+ */
14
+ stalledTaskTimeoutMs?: number;
10
15
  }
@@ -8,6 +8,11 @@ export interface ITaskSchedulerConstructorOptions {
8
8
  * @default logging
9
9
  */
10
10
  loggingComponentType?: string;
11
+ /**
12
+ * The scheduled task entity storage connector type.
13
+ * @default scheduled-task
14
+ */
15
+ scheduledTaskEntityStorageType?: string;
11
16
  /**
12
17
  * The configuration for the task scheduler.
13
18
  */
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Initialize the schema for the scheduled task service entity storage.
3
+ */
4
+ export declare function initSchema(): void;
package/docs/changelog.md CHANGED
@@ -1,25 +1,169 @@
1
1
  # Changelog
2
2
 
3
- ## [0.0.3-next.1](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.3-next.0...background-task-scheduler-v0.0.3-next.1) (2025-11-11)
3
+ ## [0.0.3-next.10](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.9...background-task-scheduler-v0.0.3-next.10) (2026-06-09)
4
+
5
+
6
+ ### Miscellaneous Chores
7
+
8
+ * **background-task-scheduler:** Synchronize repo versions
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * The following workspace dependencies were updated
14
+ * dependencies
15
+ * @twin.org/background-task-models bumped from 0.0.3-next.9 to 0.0.3-next.10
16
+
17
+ ## [0.0.3-next.9](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.8...background-task-scheduler-v0.0.3-next.9) (2026-06-08)
18
+
19
+
20
+ ### Features
21
+
22
+ * add context id features ([#29](https://github.com/iotaledger/twin-background-task/issues/29)) ([46ede49](https://github.com/iotaledger/twin-background-task/commit/46ede49a51a4955fe1530e645a66f0073db9a1fd))
23
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
24
+ * add validate-locales ([968cbf9](https://github.com/iotaledger/twin-background-task/commit/968cbf966fffb5060305e8b221fecc0b6c8105b9))
25
+ * background tasks immediately trigger ([a0a847b](https://github.com/iotaledger/twin-background-task/commit/a0a847ba9686adcd0460e810540959f87dcaeab1))
26
+ * eslint migration to flat config ([6c9136c](https://github.com/iotaledger/twin-background-task/commit/6c9136c37bccdbbd109892d1503660aab7080d49))
27
+ * multi-instance lock ([#39](https://github.com/iotaledger/twin-background-task/issues/39)) ([7dcd434](https://github.com/iotaledger/twin-background-task/commit/7dcd434da5e3d1645b6fcd19ed34be4e628e50de))
28
+ * remove unused parameters ([1028b3c](https://github.com/iotaledger/twin-background-task/commit/1028b3cc147c25da22a8ba8d7207acfb34f89cdb))
29
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
30
+ * rename task scheduler component to service ([f097a98](https://github.com/iotaledger/twin-background-task/commit/f097a988c9ee0795aa55d74deda616365ec4ffb1))
31
+ * typescript 6 update ([e3f2727](https://github.com/iotaledger/twin-background-task/commit/e3f272783e0de7cf4d31f3e84a8e6f5ff633961b))
32
+ * update dependencies ([0867e02](https://github.com/iotaledger/twin-background-task/commit/0867e02fc3c034f8e8cf5918ac6cc4e6b5ca0c93))
33
+ * update framework core ([a068098](https://github.com/iotaledger/twin-background-task/commit/a0680983d7923a1bfb980a67879019bb870ccc5d))
34
+ * update IComponent signatures ([e1a79bc](https://github.com/iotaledger/twin-background-task/commit/e1a79bc4dd813435c56e376f231a4b4ecd2276bf))
35
+
36
+
37
+ ### Bug Fixes
38
+
39
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
40
+ * restore task context in background task state-change callbacks ([#46](https://github.com/iotaledger/twin-background-task/issues/46)) ([d4f9f3b](https://github.com/iotaledger/twin-background-task/commit/d4f9f3bb57f8fb83c62024f9a385c81e2d511920))
41
+
42
+
43
+ ### Dependencies
44
+
45
+ * The following workspace dependencies were updated
46
+ * dependencies
47
+ * @twin.org/background-task-models bumped from 0.0.3-next.8 to 0.0.3-next.9
48
+
49
+ ## [0.0.3-next.8](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.7...background-task-scheduler-v0.0.3-next.8) (2026-06-08)
50
+
51
+
52
+ ### Bug Fixes
53
+
54
+ * restore task context in background task state-change callbacks ([#46](https://github.com/iotaledger/twin-background-task/issues/46)) ([d4f9f3b](https://github.com/iotaledger/twin-background-task/commit/d4f9f3bb57f8fb83c62024f9a385c81e2d511920))
55
+
56
+
57
+ ### Dependencies
58
+
59
+ * The following workspace dependencies were updated
60
+ * dependencies
61
+ * @twin.org/background-task-models bumped from 0.0.3-next.7 to 0.0.3-next.8
62
+
63
+ ## [0.0.3-next.7](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.6...background-task-scheduler-v0.0.3-next.7) (2026-05-20)
64
+
65
+
66
+ ### Features
67
+
68
+ * update dependencies ([0867e02](https://github.com/iotaledger/twin-background-task/commit/0867e02fc3c034f8e8cf5918ac6cc4e6b5ca0c93))
69
+
70
+
71
+ ### Dependencies
72
+
73
+ * The following workspace dependencies were updated
74
+ * dependencies
75
+ * @twin.org/background-task-models bumped from 0.0.3-next.6 to 0.0.3-next.7
76
+
77
+ ## [0.0.3-next.6](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.5...background-task-scheduler-v0.0.3-next.6) (2026-05-11)
78
+
79
+
80
+ ### Features
81
+
82
+ * typescript 6 update ([e3f2727](https://github.com/iotaledger/twin-background-task/commit/e3f272783e0de7cf4d31f3e84a8e6f5ff633961b))
83
+
84
+
85
+ ### Dependencies
86
+
87
+ * The following workspace dependencies were updated
88
+ * dependencies
89
+ * @twin.org/background-task-models bumped from 0.0.3-next.5 to 0.0.3-next.6
90
+
91
+ ## [0.0.3-next.5](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.4...background-task-scheduler-v0.0.3-next.5) (2026-04-10)
92
+
93
+
94
+ ### Miscellaneous Chores
95
+
96
+ * **background-task-scheduler:** Synchronize repo versions
97
+
98
+
99
+ ### Dependencies
100
+
101
+ * The following workspace dependencies were updated
102
+ * dependencies
103
+ * @twin.org/background-task-models bumped from 0.0.3-next.4 to 0.0.3-next.5
104
+
105
+ ## [0.0.3-next.4](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.3...background-task-scheduler-v0.0.3-next.4) (2026-02-23)
106
+
107
+
108
+ ### Features
109
+
110
+ * multi-instance lock ([#39](https://github.com/iotaledger/twin-background-task/issues/39)) ([7dcd434](https://github.com/iotaledger/twin-background-task/commit/7dcd434da5e3d1645b6fcd19ed34be4e628e50de))
111
+
112
+
113
+ ### Dependencies
114
+
115
+ * The following workspace dependencies were updated
116
+ * dependencies
117
+ * @twin.org/background-task-models bumped from 0.0.3-next.3 to 0.0.3-next.4
118
+
119
+ ## [0.0.3-next.3](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.2...background-task-scheduler-v0.0.3-next.3) (2026-01-07)
120
+
121
+
122
+ ### Miscellaneous Chores
123
+
124
+ * **background-task-scheduler:** Synchronize repo versions
125
+
126
+
127
+ ### Dependencies
128
+
129
+ * The following workspace dependencies were updated
130
+ * dependencies
131
+ * @twin.org/background-task-models bumped from 0.0.3-next.2 to 0.0.3-next.3
132
+
133
+ ## [0.0.3-next.2](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.1...background-task-scheduler-v0.0.3-next.2) (2025-11-28)
134
+
135
+
136
+ ### Miscellaneous Chores
137
+
138
+ * **background-task-scheduler:** Synchronize repo versions
139
+
140
+
141
+ ### Dependencies
142
+
143
+ * The following workspace dependencies were updated
144
+ * dependencies
145
+ * @twin.org/background-task-models bumped from 0.0.3-next.1 to 0.0.3-next.2
146
+
147
+ ## [0.0.3-next.1](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.0...background-task-scheduler-v0.0.3-next.1) (2025-11-11)
4
148
 
5
149
 
6
150
  ### Features
7
151
 
8
- * add context id features ([#29](https://github.com/twinfoundation/background-task/issues/29)) ([46ede49](https://github.com/twinfoundation/background-task/commit/46ede49a51a4955fe1530e645a66f0073db9a1fd))
9
- * add task scheduler ([754d973](https://github.com/twinfoundation/background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
10
- * add validate-locales ([968cbf9](https://github.com/twinfoundation/background-task/commit/968cbf966fffb5060305e8b221fecc0b6c8105b9))
11
- * background tasks immediately trigger ([a0a847b](https://github.com/twinfoundation/background-task/commit/a0a847ba9686adcd0460e810540959f87dcaeab1))
12
- * eslint migration to flat config ([6c9136c](https://github.com/twinfoundation/background-task/commit/6c9136c37bccdbbd109892d1503660aab7080d49))
13
- * remove unused parameters ([1028b3c](https://github.com/twinfoundation/background-task/commit/1028b3cc147c25da22a8ba8d7207acfb34f89cdb))
14
- * rename task scheduler component ([2f8aa59](https://github.com/twinfoundation/background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
15
- * rename task scheduler component to service ([f097a98](https://github.com/twinfoundation/background-task/commit/f097a988c9ee0795aa55d74deda616365ec4ffb1))
16
- * update framework core ([a068098](https://github.com/twinfoundation/background-task/commit/a0680983d7923a1bfb980a67879019bb870ccc5d))
17
- * update IComponent signatures ([e1a79bc](https://github.com/twinfoundation/background-task/commit/e1a79bc4dd813435c56e376f231a4b4ecd2276bf))
152
+ * add context id features ([#29](https://github.com/iotaledger/twin-background-task/issues/29)) ([46ede49](https://github.com/iotaledger/twin-background-task/commit/46ede49a51a4955fe1530e645a66f0073db9a1fd))
153
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
154
+ * add validate-locales ([968cbf9](https://github.com/iotaledger/twin-background-task/commit/968cbf966fffb5060305e8b221fecc0b6c8105b9))
155
+ * background tasks immediately trigger ([a0a847b](https://github.com/iotaledger/twin-background-task/commit/a0a847ba9686adcd0460e810540959f87dcaeab1))
156
+ * eslint migration to flat config ([6c9136c](https://github.com/iotaledger/twin-background-task/commit/6c9136c37bccdbbd109892d1503660aab7080d49))
157
+ * remove unused parameters ([1028b3c](https://github.com/iotaledger/twin-background-task/commit/1028b3cc147c25da22a8ba8d7207acfb34f89cdb))
158
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
159
+ * rename task scheduler component to service ([f097a98](https://github.com/iotaledger/twin-background-task/commit/f097a988c9ee0795aa55d74deda616365ec4ffb1))
160
+ * update framework core ([a068098](https://github.com/iotaledger/twin-background-task/commit/a0680983d7923a1bfb980a67879019bb870ccc5d))
161
+ * update IComponent signatures ([e1a79bc](https://github.com/iotaledger/twin-background-task/commit/e1a79bc4dd813435c56e376f231a4b4ecd2276bf))
18
162
 
19
163
 
20
164
  ### Bug Fixes
21
165
 
22
- * models import ([c830b0d](https://github.com/twinfoundation/background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
166
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
23
167
 
24
168
 
25
169
  ### Dependencies
@@ -28,12 +172,12 @@
28
172
  * dependencies
29
173
  * @twin.org/background-task-models bumped from 0.0.3-next.0 to 0.0.3-next.1
30
174
 
31
- ## [0.0.2-next.9](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.2-next.8...background-task-scheduler-v0.0.2-next.9) (2025-10-09)
175
+ ## [0.0.2-next.9](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.2-next.8...background-task-scheduler-v0.0.2-next.9) (2025-10-09)
32
176
 
33
177
 
34
178
  ### Features
35
179
 
36
- * add validate-locales ([968cbf9](https://github.com/twinfoundation/background-task/commit/968cbf966fffb5060305e8b221fecc0b6c8105b9))
180
+ * add validate-locales ([968cbf9](https://github.com/iotaledger/twin-background-task/commit/968cbf966fffb5060305e8b221fecc0b6c8105b9))
37
181
 
38
182
 
39
183
  ### Dependencies
@@ -42,12 +186,12 @@
42
186
  * dependencies
43
187
  * @twin.org/background-task-models bumped from 0.0.2-next.8 to 0.0.2-next.9
44
188
 
45
- ## [0.0.2-next.8](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.2-next.7...background-task-scheduler-v0.0.2-next.8) (2025-09-29)
189
+ ## [0.0.2-next.8](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.2-next.7...background-task-scheduler-v0.0.2-next.8) (2025-09-29)
46
190
 
47
191
 
48
192
  ### Features
49
193
 
50
- * update IComponent signatures ([e1a79bc](https://github.com/twinfoundation/background-task/commit/e1a79bc4dd813435c56e376f231a4b4ecd2276bf))
194
+ * update IComponent signatures ([e1a79bc](https://github.com/iotaledger/twin-background-task/commit/e1a79bc4dd813435c56e376f231a4b4ecd2276bf))
51
195
 
52
196
 
53
197
  ### Dependencies
@@ -56,12 +200,12 @@
56
200
  * dependencies
57
201
  * @twin.org/background-task-models bumped from 0.0.2-next.7 to 0.0.2-next.8
58
202
 
59
- ## [0.0.2-next.7](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.2-next.6...background-task-scheduler-v0.0.2-next.7) (2025-08-29)
203
+ ## [0.0.2-next.7](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.2-next.6...background-task-scheduler-v0.0.2-next.7) (2025-08-29)
60
204
 
61
205
 
62
206
  ### Features
63
207
 
64
- * eslint migration to flat config ([6c9136c](https://github.com/twinfoundation/background-task/commit/6c9136c37bccdbbd109892d1503660aab7080d49))
208
+ * eslint migration to flat config ([6c9136c](https://github.com/iotaledger/twin-background-task/commit/6c9136c37bccdbbd109892d1503660aab7080d49))
65
209
 
66
210
 
67
211
  ### Dependencies
@@ -70,12 +214,12 @@
70
214
  * dependencies
71
215
  * @twin.org/background-task-models bumped from 0.0.2-next.6 to 0.0.2-next.7
72
216
 
73
- ## [0.0.2-next.6](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.2-next.5...background-task-scheduler-v0.0.2-next.6) (2025-08-22)
217
+ ## [0.0.2-next.6](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.2-next.5...background-task-scheduler-v0.0.2-next.6) (2025-08-22)
74
218
 
75
219
 
76
220
  ### Features
77
221
 
78
- * remove unused parameters ([1028b3c](https://github.com/twinfoundation/background-task/commit/1028b3cc147c25da22a8ba8d7207acfb34f89cdb))
222
+ * remove unused parameters ([1028b3c](https://github.com/iotaledger/twin-background-task/commit/1028b3cc147c25da22a8ba8d7207acfb34f89cdb))
79
223
 
80
224
 
81
225
  ### Dependencies
@@ -84,12 +228,12 @@
84
228
  * dependencies
85
229
  * @twin.org/background-task-models bumped from 0.0.2-next.5 to 0.0.2-next.6
86
230
 
87
- ## [0.0.2-next.5](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.2-next.4...background-task-scheduler-v0.0.2-next.5) (2025-08-20)
231
+ ## [0.0.2-next.5](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.2-next.4...background-task-scheduler-v0.0.2-next.5) (2025-08-20)
88
232
 
89
233
 
90
234
  ### Features
91
235
 
92
- * update framework core ([a068098](https://github.com/twinfoundation/background-task/commit/a0680983d7923a1bfb980a67879019bb870ccc5d))
236
+ * update framework core ([a068098](https://github.com/iotaledger/twin-background-task/commit/a0680983d7923a1bfb980a67879019bb870ccc5d))
93
237
 
94
238
 
95
239
  ### Dependencies
@@ -98,12 +242,12 @@
98
242
  * dependencies
99
243
  * @twin.org/background-task-models bumped from 0.0.2-next.4 to 0.0.2-next.5
100
244
 
101
- ## [0.0.2-next.4](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.2-next.3...background-task-scheduler-v0.0.2-next.4) (2025-07-23)
245
+ ## [0.0.2-next.4](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.2-next.3...background-task-scheduler-v0.0.2-next.4) (2025-07-23)
102
246
 
103
247
 
104
248
  ### Features
105
249
 
106
- * background tasks immediately trigger ([a0a847b](https://github.com/twinfoundation/background-task/commit/a0a847ba9686adcd0460e810540959f87dcaeab1))
250
+ * background tasks immediately trigger ([a0a847b](https://github.com/iotaledger/twin-background-task/commit/a0a847ba9686adcd0460e810540959f87dcaeab1))
107
251
 
108
252
 
109
253
  ### Dependencies
@@ -112,12 +256,12 @@
112
256
  * dependencies
113
257
  * @twin.org/background-task-models bumped from 0.0.2-next.3 to 0.0.2-next.4
114
258
 
115
- ## [0.0.2-next.3](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.2-next.2...background-task-scheduler-v0.0.2-next.3) (2025-07-21)
259
+ ## [0.0.2-next.3](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.2-next.2...background-task-scheduler-v0.0.2-next.3) (2025-07-21)
116
260
 
117
261
 
118
262
  ### Features
119
263
 
120
- * rename task scheduler component to service ([f097a98](https://github.com/twinfoundation/background-task/commit/f097a988c9ee0795aa55d74deda616365ec4ffb1))
264
+ * rename task scheduler component to service ([f097a98](https://github.com/iotaledger/twin-background-task/commit/f097a988c9ee0795aa55d74deda616365ec4ffb1))
121
265
 
122
266
 
123
267
  ### Dependencies
@@ -126,18 +270,18 @@
126
270
  * dependencies
127
271
  * @twin.org/background-task-models bumped from 0.0.2-next.2 to 0.0.2-next.3
128
272
 
129
- ## [0.0.2-next.2](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.2-next.1...background-task-scheduler-v0.0.2-next.2) (2025-07-09)
273
+ ## [0.0.2-next.2](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.2-next.1...background-task-scheduler-v0.0.2-next.2) (2025-07-09)
130
274
 
131
275
 
132
276
  ### Features
133
277
 
134
- * add task scheduler ([754d973](https://github.com/twinfoundation/background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
135
- * rename task scheduler component ([2f8aa59](https://github.com/twinfoundation/background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
278
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
279
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
136
280
 
137
281
 
138
282
  ### Bug Fixes
139
283
 
140
- * models import ([c830b0d](https://github.com/twinfoundation/background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
284
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
141
285
 
142
286
 
143
287
  ### Dependencies
@@ -146,18 +290,18 @@
146
290
  * dependencies
147
291
  * @twin.org/background-task-models bumped from 0.0.2-next.1 to 0.0.2-next.2
148
292
 
149
- ## [0.0.2-next.1](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.2-next.0...background-task-scheduler-v0.0.2-next.1) (2025-07-09)
293
+ ## [0.0.2-next.1](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.2-next.0...background-task-scheduler-v0.0.2-next.1) (2025-07-09)
150
294
 
151
295
 
152
296
  ### Features
153
297
 
154
- * add task scheduler ([754d973](https://github.com/twinfoundation/background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
155
- * rename task scheduler component ([2f8aa59](https://github.com/twinfoundation/background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
298
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
299
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
156
300
 
157
301
 
158
302
  ### Bug Fixes
159
303
 
160
- * models import ([c830b0d](https://github.com/twinfoundation/background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
304
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
161
305
 
162
306
 
163
307
  ### Dependencies
@@ -171,7 +315,7 @@
171
315
 
172
316
  ### Features
173
317
 
174
- * release to production ([7ce9896](https://github.com/twinfoundation/background-task/commit/7ce989659e6819f05655c86b1bda2a265af5d281))
318
+ * release to production ([7ce9896](https://github.com/iotaledger/twin-background-task/commit/7ce989659e6819f05655c86b1bda2a265af5d281))
175
319
 
176
320
 
177
321
  ### Dependencies
@@ -180,12 +324,12 @@
180
324
  * dependencies
181
325
  * @twin.org/background-task-models bumped from ^0.0.0 to ^0.0.1
182
326
 
183
- ## [0.0.1-next.21](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.1-next.20...background-task-scheduler-v0.0.1-next.21) (2025-06-23)
327
+ ## [0.0.1-next.21](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.1-next.20...background-task-scheduler-v0.0.1-next.21) (2025-06-23)
184
328
 
185
329
 
186
330
  ### Features
187
331
 
188
- * rename task scheduler component ([2f8aa59](https://github.com/twinfoundation/background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
332
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
189
333
 
190
334
 
191
335
  ### Dependencies
@@ -194,17 +338,17 @@
194
338
  * dependencies
195
339
  * @twin.org/background-task-models bumped from 0.0.1-next.20 to 0.0.1-next.21
196
340
 
197
- ## [0.0.1-next.20](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.1-next.19...background-task-scheduler-v0.0.1-next.20) (2025-06-23)
341
+ ## [0.0.1-next.20](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.1-next.19...background-task-scheduler-v0.0.1-next.20) (2025-06-23)
198
342
 
199
343
 
200
344
  ### Features
201
345
 
202
- * add task scheduler ([754d973](https://github.com/twinfoundation/background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
346
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
203
347
 
204
348
 
205
349
  ### Bug Fixes
206
350
 
207
- * models import ([c830b0d](https://github.com/twinfoundation/background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
351
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
208
352
 
209
353
 
210
354
  ### Dependencies
@@ -213,12 +357,12 @@
213
357
  * dependencies
214
358
  * @twin.org/background-task-models bumped from 0.0.1-next.19 to 0.0.1-next.20
215
359
 
216
- ## [0.0.1-next.19](https://github.com/twinfoundation/background-task/compare/background-task-scheduler-v0.0.1-next.18...background-task-scheduler-v0.0.1-next.19) (2025-06-23)
360
+ ## [0.0.1-next.19](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.1-next.18...background-task-scheduler-v0.0.1-next.19) (2025-06-23)
217
361
 
218
362
 
219
363
  ### Features
220
364
 
221
- * add task scheduler ([754d973](https://github.com/twinfoundation/background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
365
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
222
366
 
223
367
 
224
368
  ### Dependencies
@@ -227,4 +371,4 @@
227
371
  * dependencies
228
372
  * @twin.org/background-task-models bumped from 0.0.1-next.18 to 0.0.1-next.19
229
373
 
230
- ## @twin.org/background-task-scheduler - Changelog
374
+ ## Changelog
package/docs/examples.md CHANGED
@@ -1 +1,95 @@
1
- # @twin.org/background-task-scheduler - Examples
1
+ # Background Task Scheduler Examples
2
+
3
+ Use these snippets to configure recurring schedules and monitor trigger state for background work.
4
+
5
+ ## TaskSchedulerService
6
+
7
+ ```typescript
8
+ import { TaskSchedulerService } from '@twin.org/background-task-scheduler';
9
+
10
+ const scheduler = new TaskSchedulerService({
11
+ config: {
12
+ intervalMs: 10000,
13
+ stalledTaskTimeoutMs: 120000
14
+ }
15
+ });
16
+
17
+ console.log(scheduler.className()); // TaskSchedulerService
18
+ ```
19
+
20
+ ```typescript
21
+ import { TaskSchedulerService } from '@twin.org/background-task-scheduler';
22
+
23
+ const scheduler = new TaskSchedulerService();
24
+ const taskId = 'report-refresh';
25
+
26
+ await scheduler.addTask(
27
+ taskId,
28
+ [
29
+ {
30
+ nextTriggerTime: Date.now() + 5000,
31
+ intervalMinutes: 10
32
+ },
33
+ {
34
+ nextTriggerTime: Date.now() + 30000,
35
+ intervalHours: 1
36
+ }
37
+ ],
38
+ async () => {
39
+ const runAt = new Date().toISOString();
40
+ console.log('report-refresh runAt', runAt); // report-refresh runAt 2026-03-09T10:45:05.000Z
41
+ }
42
+ );
43
+
44
+ const info = await scheduler.tasksInfo();
45
+ console.log(info.tasks[taskId].length); // 2
46
+ ```
47
+
48
+ ```typescript
49
+ import { TaskSchedulerService } from '@twin.org/background-task-scheduler';
50
+
51
+ const scheduler = new TaskSchedulerService();
52
+ const taskId = 'cache-prune';
53
+
54
+ await scheduler.addTask(
55
+ taskId,
56
+ [
57
+ {
58
+ nextTriggerTime: Date.now() + 1000,
59
+ intervalMinutes: 5
60
+ }
61
+ ],
62
+ async () => {
63
+ const runAt = new Date().toISOString();
64
+ console.log('cache-prune runAt', runAt); // cache-prune runAt 2026-03-09T10:45:01.000Z
65
+ }
66
+ );
67
+
68
+ await scheduler.removeTask(taskId);
69
+
70
+ const infoAfterRemoval = await scheduler.tasksInfo();
71
+ console.log(taskId in infoAfterRemoval.tasks); // false
72
+
73
+ await scheduler.stop();
74
+ ```
75
+
76
+ ## ScheduledTask
77
+
78
+ ```typescript
79
+ import { ScheduledTask } from '@twin.org/background-task-scheduler';
80
+
81
+ const scheduledTask = new ScheduledTask();
82
+ scheduledTask.id = 'nightly-index';
83
+ scheduledTask.lastRunTime = Date.now();
84
+
85
+ console.log(scheduledTask.id); // nightly-index
86
+ console.log(typeof scheduledTask.lastRunTime); // number
87
+ ```
88
+
89
+ ## initSchema
90
+
91
+ ```typescript
92
+ import { initSchema } from '@twin.org/background-task-scheduler';
93
+
94
+ initSchema();
95
+ ```
@@ -0,0 +1,29 @@
1
+ # Class: ScheduledTask
2
+
3
+ Class defining a scheduled task.
4
+
5
+ ## Constructors
6
+
7
+ ### Constructor
8
+
9
+ > **new ScheduledTask**(): `ScheduledTask`
10
+
11
+ #### Returns
12
+
13
+ `ScheduledTask`
14
+
15
+ ## Properties
16
+
17
+ ### id {#id}
18
+
19
+ > **id**: `string`
20
+
21
+ The id.
22
+
23
+ ***
24
+
25
+ ### lastRunTime? {#lastruntime}
26
+
27
+ > `optional` **lastRunTime?**: `number`
28
+
29
+ The last run time of the task, if undefined waiting for next run.
@@ -28,7 +28,7 @@ The options for the scheduler.
28
28
 
29
29
  ## Properties
30
30
 
31
- ### CLASS\_NAME
31
+ ### CLASS\_NAME {#class_name}
32
32
 
33
33
  > `readonly` `static` **CLASS\_NAME**: `string`
34
34
 
@@ -36,7 +36,7 @@ Runtime name for the class.
36
36
 
37
37
  ## Methods
38
38
 
39
- ### className()
39
+ ### className() {#classname}
40
40
 
41
41
  > **className**(): `string`
42
42
 
@@ -54,7 +54,7 @@ The class name of the component.
54
54
 
55
55
  ***
56
56
 
57
- ### stop()
57
+ ### stop() {#stop}
58
58
 
59
59
  > **stop**(`nodeLoggingComponentType?`): `Promise`\<`void`\>
60
60
 
@@ -80,7 +80,7 @@ Nothing.
80
80
 
81
81
  ***
82
82
 
83
- ### addTask()
83
+ ### addTask() {#addtask}
84
84
 
85
85
  > **addTask**(`taskId`, `times`, `taskCallback`): `Promise`\<`void`\>
86
86
 
@@ -118,7 +118,7 @@ Nothing.
118
118
 
119
119
  ***
120
120
 
121
- ### removeTask()
121
+ ### removeTask() {#removetask}
122
122
 
123
123
  > **removeTask**(`taskId`): `Promise`\<`void`\>
124
124
 
@@ -144,7 +144,7 @@ Nothing.
144
144
 
145
145
  ***
146
146
 
147
- ### tasksInfo()
147
+ ### tasksInfo() {#tasksinfo}
148
148
 
149
149
  > **tasksInfo**(): `Promise`\<`IScheduledTaskInfo`\>
150
150
 
@@ -0,0 +1,9 @@
1
+ # Function: initSchema()
2
+
3
+ > **initSchema**(): `void`
4
+
5
+ Initialize the schema for the scheduled task service entity storage.
6
+
7
+ ## Returns
8
+
9
+ `void`
@@ -2,9 +2,14 @@
2
2
 
3
3
  ## Classes
4
4
 
5
+ - [ScheduledTask](classes/ScheduledTask.md)
5
6
  - [TaskSchedulerService](classes/TaskSchedulerService.md)
6
7
 
7
8
  ## Interfaces
8
9
 
9
10
  - [ITaskSchedulerConfig](interfaces/ITaskSchedulerConfig.md)
10
11
  - [ITaskSchedulerConstructorOptions](interfaces/ITaskSchedulerConstructorOptions.md)
12
+
13
+ ## Functions
14
+
15
+ - [initSchema](functions/initSchema.md)
@@ -4,9 +4,9 @@ Interface for the task scheduler configuration.
4
4
 
5
5
  ## Properties
6
6
 
7
- ### overrideInterval?
7
+ ### intervalMs? {#intervalms}
8
8
 
9
- > `optional` **overrideInterval**: `number`
9
+ > `optional` **intervalMs?**: `number`
10
10
 
11
11
  The interval between checks for running tasks, defaults to 1 minute since that is the resolution of the tasks.
12
12
 
@@ -15,3 +15,17 @@ The interval between checks for running tasks, defaults to 1 minute since that i
15
15
  ```ts
16
16
  60000
17
17
  ```
18
+
19
+ ***
20
+
21
+ ### stalledTaskTimeoutMs? {#stalledtasktimeoutms}
22
+
23
+ > `optional` **stalledTaskTimeoutMs?**: `number`
24
+
25
+ The time in milliseconds after which a task that is still marked as running is considered stalled and can be run again.
26
+
27
+ #### Default
28
+
29
+ ```ts
30
+ 300000
31
+ ```
@@ -4,9 +4,9 @@ Options for the task scheduler constructor.
4
4
 
5
5
  ## Properties
6
6
 
7
- ### loggingComponentType?
7
+ ### loggingComponentType? {#loggingcomponenttype}
8
8
 
9
- > `optional` **loggingComponentType**: `string`
9
+ > `optional` **loggingComponentType?**: `string`
10
10
 
11
11
  The logging component type.
12
12
 
@@ -18,8 +18,22 @@ logging
18
18
 
19
19
  ***
20
20
 
21
- ### config?
21
+ ### scheduledTaskEntityStorageType? {#scheduledtaskentitystoragetype}
22
22
 
23
- > `optional` **config**: [`ITaskSchedulerConfig`](ITaskSchedulerConfig.md)
23
+ > `optional` **scheduledTaskEntityStorageType?**: `string`
24
+
25
+ The scheduled task entity storage connector type.
26
+
27
+ #### Default
28
+
29
+ ```ts
30
+ scheduled-task
31
+ ```
32
+
33
+ ***
34
+
35
+ ### config? {#config}
36
+
37
+ > `optional` **config?**: [`ITaskSchedulerConfig`](ITaskSchedulerConfig.md)
24
38
 
25
39
  The configuration for the task scheduler.
package/locales/en.json CHANGED
@@ -10,5 +10,10 @@
10
10
  "taskRemoved": "Task with id \"{id}\" removed",
11
11
  "taskTriggered": "Task with id \"{id}\" triggered at time \"{time}\""
12
12
  }
13
+ },
14
+ "warn": {
15
+ "taskSchedulerService": {
16
+ "taskStalled": "Task with id \"{id}\" is stalled, last run at \"{lastRunTime}\" and exceeded timeout \"{stalledTaskTimeoutMs}\" ms"
17
+ }
13
18
  }
14
19
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@twin.org/background-task-scheduler",
3
- "version": "0.0.3-next.1",
4
- "description": "Background task scheduler",
3
+ "version": "0.0.3-next.10",
4
+ "description": "Schedules background tasks for one-off or recurring execution windows",
5
5
  "repository": {
6
6
  "type": "git",
7
- "url": "git+https://github.com/twinfoundation/background-task.git",
7
+ "url": "git+https://github.com/iotaledger/twin-background-task.git",
8
8
  "directory": "packages/background-task-scheduler"
9
9
  },
10
10
  "author": "martyn.janes@iota.org",
@@ -14,8 +14,9 @@
14
14
  "node": ">=20.0.0"
15
15
  },
16
16
  "dependencies": {
17
- "@twin.org/background-task-models": "0.0.3-next.1",
17
+ "@twin.org/background-task-models": "0.0.3-next.10",
18
18
  "@twin.org/core": "next",
19
+ "@twin.org/entity-storage-models": "next",
19
20
  "@twin.org/logging-models": "next",
20
21
  "@twin.org/nameof": "next"
21
22
  },
@@ -48,7 +49,7 @@
48
49
  "async"
49
50
  ],
50
51
  "bugs": {
51
- "url": "git+https://github.com/twinfoundation/background-task/issues"
52
+ "url": "git+https://github.com/iotaledger/twin-background-task/issues"
52
53
  },
53
54
  "homepage": "https://twindev.org"
54
55
  }