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

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,183 @@
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.11](https://github.com/iotaledger/twin-background-task/compare/background-task-scheduler-v0.0.3-next.10...background-task-scheduler-v0.0.3-next.11) (2026-06-10)
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.10 to 0.0.3-next.11
16
+
17
+ ## [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)
18
+
19
+
20
+ ### Miscellaneous Chores
21
+
22
+ * **background-task-scheduler:** Synchronize repo versions
23
+
24
+
25
+ ### Dependencies
26
+
27
+ * The following workspace dependencies were updated
28
+ * dependencies
29
+ * @twin.org/background-task-models bumped from 0.0.3-next.9 to 0.0.3-next.10
30
+
31
+ ## [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)
32
+
33
+
34
+ ### Features
35
+
36
+ * add context id features ([#29](https://github.com/iotaledger/twin-background-task/issues/29)) ([46ede49](https://github.com/iotaledger/twin-background-task/commit/46ede49a51a4955fe1530e645a66f0073db9a1fd))
37
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
38
+ * add validate-locales ([968cbf9](https://github.com/iotaledger/twin-background-task/commit/968cbf966fffb5060305e8b221fecc0b6c8105b9))
39
+ * background tasks immediately trigger ([a0a847b](https://github.com/iotaledger/twin-background-task/commit/a0a847ba9686adcd0460e810540959f87dcaeab1))
40
+ * eslint migration to flat config ([6c9136c](https://github.com/iotaledger/twin-background-task/commit/6c9136c37bccdbbd109892d1503660aab7080d49))
41
+ * multi-instance lock ([#39](https://github.com/iotaledger/twin-background-task/issues/39)) ([7dcd434](https://github.com/iotaledger/twin-background-task/commit/7dcd434da5e3d1645b6fcd19ed34be4e628e50de))
42
+ * remove unused parameters ([1028b3c](https://github.com/iotaledger/twin-background-task/commit/1028b3cc147c25da22a8ba8d7207acfb34f89cdb))
43
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
44
+ * rename task scheduler component to service ([f097a98](https://github.com/iotaledger/twin-background-task/commit/f097a988c9ee0795aa55d74deda616365ec4ffb1))
45
+ * typescript 6 update ([e3f2727](https://github.com/iotaledger/twin-background-task/commit/e3f272783e0de7cf4d31f3e84a8e6f5ff633961b))
46
+ * update dependencies ([0867e02](https://github.com/iotaledger/twin-background-task/commit/0867e02fc3c034f8e8cf5918ac6cc4e6b5ca0c93))
47
+ * update framework core ([a068098](https://github.com/iotaledger/twin-background-task/commit/a0680983d7923a1bfb980a67879019bb870ccc5d))
48
+ * update IComponent signatures ([e1a79bc](https://github.com/iotaledger/twin-background-task/commit/e1a79bc4dd813435c56e376f231a4b4ecd2276bf))
49
+
50
+
51
+ ### Bug Fixes
52
+
53
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
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.8 to 0.0.3-next.9
62
+
63
+ ## [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)
64
+
65
+
66
+ ### Bug Fixes
67
+
68
+ * 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))
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.7 to 0.0.3-next.8
76
+
77
+ ## [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)
78
+
79
+
80
+ ### Features
81
+
82
+ * update dependencies ([0867e02](https://github.com/iotaledger/twin-background-task/commit/0867e02fc3c034f8e8cf5918ac6cc4e6b5ca0c93))
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.6 to 0.0.3-next.7
90
+
91
+ ## [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)
92
+
93
+
94
+ ### Features
95
+
96
+ * typescript 6 update ([e3f2727](https://github.com/iotaledger/twin-background-task/commit/e3f272783e0de7cf4d31f3e84a8e6f5ff633961b))
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.5 to 0.0.3-next.6
104
+
105
+ ## [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)
106
+
107
+
108
+ ### Miscellaneous Chores
109
+
110
+ * **background-task-scheduler:** Synchronize repo versions
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.4 to 0.0.3-next.5
118
+
119
+ ## [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)
120
+
121
+
122
+ ### Features
123
+
124
+ * multi-instance lock ([#39](https://github.com/iotaledger/twin-background-task/issues/39)) ([7dcd434](https://github.com/iotaledger/twin-background-task/commit/7dcd434da5e3d1645b6fcd19ed34be4e628e50de))
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.3 to 0.0.3-next.4
132
+
133
+ ## [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)
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.2 to 0.0.3-next.3
146
+
147
+ ## [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)
148
+
149
+
150
+ ### Miscellaneous Chores
151
+
152
+ * **background-task-scheduler:** Synchronize repo versions
153
+
154
+
155
+ ### Dependencies
156
+
157
+ * The following workspace dependencies were updated
158
+ * dependencies
159
+ * @twin.org/background-task-models bumped from 0.0.3-next.1 to 0.0.3-next.2
160
+
161
+ ## [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
162
 
5
163
 
6
164
  ### Features
7
165
 
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))
166
+ * add context id features ([#29](https://github.com/iotaledger/twin-background-task/issues/29)) ([46ede49](https://github.com/iotaledger/twin-background-task/commit/46ede49a51a4955fe1530e645a66f0073db9a1fd))
167
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
168
+ * add validate-locales ([968cbf9](https://github.com/iotaledger/twin-background-task/commit/968cbf966fffb5060305e8b221fecc0b6c8105b9))
169
+ * background tasks immediately trigger ([a0a847b](https://github.com/iotaledger/twin-background-task/commit/a0a847ba9686adcd0460e810540959f87dcaeab1))
170
+ * eslint migration to flat config ([6c9136c](https://github.com/iotaledger/twin-background-task/commit/6c9136c37bccdbbd109892d1503660aab7080d49))
171
+ * remove unused parameters ([1028b3c](https://github.com/iotaledger/twin-background-task/commit/1028b3cc147c25da22a8ba8d7207acfb34f89cdb))
172
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
173
+ * rename task scheduler component to service ([f097a98](https://github.com/iotaledger/twin-background-task/commit/f097a988c9ee0795aa55d74deda616365ec4ffb1))
174
+ * update framework core ([a068098](https://github.com/iotaledger/twin-background-task/commit/a0680983d7923a1bfb980a67879019bb870ccc5d))
175
+ * update IComponent signatures ([e1a79bc](https://github.com/iotaledger/twin-background-task/commit/e1a79bc4dd813435c56e376f231a4b4ecd2276bf))
18
176
 
19
177
 
20
178
  ### Bug Fixes
21
179
 
22
- * models import ([c830b0d](https://github.com/twinfoundation/background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
180
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
23
181
 
24
182
 
25
183
  ### Dependencies
@@ -28,12 +186,12 @@
28
186
  * dependencies
29
187
  * @twin.org/background-task-models bumped from 0.0.3-next.0 to 0.0.3-next.1
30
188
 
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)
189
+ ## [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
190
 
33
191
 
34
192
  ### Features
35
193
 
36
- * add validate-locales ([968cbf9](https://github.com/twinfoundation/background-task/commit/968cbf966fffb5060305e8b221fecc0b6c8105b9))
194
+ * add validate-locales ([968cbf9](https://github.com/iotaledger/twin-background-task/commit/968cbf966fffb5060305e8b221fecc0b6c8105b9))
37
195
 
38
196
 
39
197
  ### Dependencies
@@ -42,12 +200,12 @@
42
200
  * dependencies
43
201
  * @twin.org/background-task-models bumped from 0.0.2-next.8 to 0.0.2-next.9
44
202
 
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)
203
+ ## [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
204
 
47
205
 
48
206
  ### Features
49
207
 
50
- * update IComponent signatures ([e1a79bc](https://github.com/twinfoundation/background-task/commit/e1a79bc4dd813435c56e376f231a4b4ecd2276bf))
208
+ * update IComponent signatures ([e1a79bc](https://github.com/iotaledger/twin-background-task/commit/e1a79bc4dd813435c56e376f231a4b4ecd2276bf))
51
209
 
52
210
 
53
211
  ### Dependencies
@@ -56,12 +214,12 @@
56
214
  * dependencies
57
215
  * @twin.org/background-task-models bumped from 0.0.2-next.7 to 0.0.2-next.8
58
216
 
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)
217
+ ## [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
218
 
61
219
 
62
220
  ### Features
63
221
 
64
- * eslint migration to flat config ([6c9136c](https://github.com/twinfoundation/background-task/commit/6c9136c37bccdbbd109892d1503660aab7080d49))
222
+ * eslint migration to flat config ([6c9136c](https://github.com/iotaledger/twin-background-task/commit/6c9136c37bccdbbd109892d1503660aab7080d49))
65
223
 
66
224
 
67
225
  ### Dependencies
@@ -70,12 +228,12 @@
70
228
  * dependencies
71
229
  * @twin.org/background-task-models bumped from 0.0.2-next.6 to 0.0.2-next.7
72
230
 
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)
231
+ ## [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
232
 
75
233
 
76
234
  ### Features
77
235
 
78
- * remove unused parameters ([1028b3c](https://github.com/twinfoundation/background-task/commit/1028b3cc147c25da22a8ba8d7207acfb34f89cdb))
236
+ * remove unused parameters ([1028b3c](https://github.com/iotaledger/twin-background-task/commit/1028b3cc147c25da22a8ba8d7207acfb34f89cdb))
79
237
 
80
238
 
81
239
  ### Dependencies
@@ -84,12 +242,12 @@
84
242
  * dependencies
85
243
  * @twin.org/background-task-models bumped from 0.0.2-next.5 to 0.0.2-next.6
86
244
 
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)
245
+ ## [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
246
 
89
247
 
90
248
  ### Features
91
249
 
92
- * update framework core ([a068098](https://github.com/twinfoundation/background-task/commit/a0680983d7923a1bfb980a67879019bb870ccc5d))
250
+ * update framework core ([a068098](https://github.com/iotaledger/twin-background-task/commit/a0680983d7923a1bfb980a67879019bb870ccc5d))
93
251
 
94
252
 
95
253
  ### Dependencies
@@ -98,12 +256,12 @@
98
256
  * dependencies
99
257
  * @twin.org/background-task-models bumped from 0.0.2-next.4 to 0.0.2-next.5
100
258
 
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)
259
+ ## [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
260
 
103
261
 
104
262
  ### Features
105
263
 
106
- * background tasks immediately trigger ([a0a847b](https://github.com/twinfoundation/background-task/commit/a0a847ba9686adcd0460e810540959f87dcaeab1))
264
+ * background tasks immediately trigger ([a0a847b](https://github.com/iotaledger/twin-background-task/commit/a0a847ba9686adcd0460e810540959f87dcaeab1))
107
265
 
108
266
 
109
267
  ### Dependencies
@@ -112,12 +270,12 @@
112
270
  * dependencies
113
271
  * @twin.org/background-task-models bumped from 0.0.2-next.3 to 0.0.2-next.4
114
272
 
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)
273
+ ## [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
274
 
117
275
 
118
276
  ### Features
119
277
 
120
- * rename task scheduler component to service ([f097a98](https://github.com/twinfoundation/background-task/commit/f097a988c9ee0795aa55d74deda616365ec4ffb1))
278
+ * rename task scheduler component to service ([f097a98](https://github.com/iotaledger/twin-background-task/commit/f097a988c9ee0795aa55d74deda616365ec4ffb1))
121
279
 
122
280
 
123
281
  ### Dependencies
@@ -126,18 +284,18 @@
126
284
  * dependencies
127
285
  * @twin.org/background-task-models bumped from 0.0.2-next.2 to 0.0.2-next.3
128
286
 
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)
287
+ ## [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
288
 
131
289
 
132
290
  ### Features
133
291
 
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))
292
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
293
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
136
294
 
137
295
 
138
296
  ### Bug Fixes
139
297
 
140
- * models import ([c830b0d](https://github.com/twinfoundation/background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
298
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
141
299
 
142
300
 
143
301
  ### Dependencies
@@ -146,18 +304,18 @@
146
304
  * dependencies
147
305
  * @twin.org/background-task-models bumped from 0.0.2-next.1 to 0.0.2-next.2
148
306
 
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)
307
+ ## [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
308
 
151
309
 
152
310
  ### Features
153
311
 
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))
312
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
313
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
156
314
 
157
315
 
158
316
  ### Bug Fixes
159
317
 
160
- * models import ([c830b0d](https://github.com/twinfoundation/background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
318
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
161
319
 
162
320
 
163
321
  ### Dependencies
@@ -171,7 +329,7 @@
171
329
 
172
330
  ### Features
173
331
 
174
- * release to production ([7ce9896](https://github.com/twinfoundation/background-task/commit/7ce989659e6819f05655c86b1bda2a265af5d281))
332
+ * release to production ([7ce9896](https://github.com/iotaledger/twin-background-task/commit/7ce989659e6819f05655c86b1bda2a265af5d281))
175
333
 
176
334
 
177
335
  ### Dependencies
@@ -180,12 +338,12 @@
180
338
  * dependencies
181
339
  * @twin.org/background-task-models bumped from ^0.0.0 to ^0.0.1
182
340
 
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)
341
+ ## [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
342
 
185
343
 
186
344
  ### Features
187
345
 
188
- * rename task scheduler component ([2f8aa59](https://github.com/twinfoundation/background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
346
+ * rename task scheduler component ([2f8aa59](https://github.com/iotaledger/twin-background-task/commit/2f8aa59c069055ff020a3c0c149601f20c656022))
189
347
 
190
348
 
191
349
  ### Dependencies
@@ -194,17 +352,17 @@
194
352
  * dependencies
195
353
  * @twin.org/background-task-models bumped from 0.0.1-next.20 to 0.0.1-next.21
196
354
 
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)
355
+ ## [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
356
 
199
357
 
200
358
  ### Features
201
359
 
202
- * add task scheduler ([754d973](https://github.com/twinfoundation/background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
360
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
203
361
 
204
362
 
205
363
  ### Bug Fixes
206
364
 
207
- * models import ([c830b0d](https://github.com/twinfoundation/background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
365
+ * models import ([c830b0d](https://github.com/iotaledger/twin-background-task/commit/c830b0da4deb06f8aeca6fec8988be4da877e73b))
208
366
 
209
367
 
210
368
  ### Dependencies
@@ -213,12 +371,12 @@
213
371
  * dependencies
214
372
  * @twin.org/background-task-models bumped from 0.0.1-next.19 to 0.0.1-next.20
215
373
 
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)
374
+ ## [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
375
 
218
376
 
219
377
  ### Features
220
378
 
221
- * add task scheduler ([754d973](https://github.com/twinfoundation/background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
379
+ * add task scheduler ([754d973](https://github.com/iotaledger/twin-background-task/commit/754d973e7c8483e5e54e887c157661867d5a0375))
222
380
 
223
381
 
224
382
  ### Dependencies
@@ -227,4 +385,4 @@
227
385
  * dependencies
228
386
  * @twin.org/background-task-models bumped from 0.0.1-next.18 to 0.0.1-next.19
229
387
 
230
- ## @twin.org/background-task-scheduler - Changelog
388
+ ## 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.11",
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.11",
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
  }