`io.runTask()` allows you to run a [Task](https://trigger.dev/docs/documentation/concepts/tasks) from inside a Job run. A Task is a resumable unit of a Run that can be retried, resumed and is logged. [Integrations](https://trigger.dev/docs/integrations) use Tasks internally to perform their actions.
(
cacheKey: string | any[],
callback: (task: ServerTask, io: IO) => Promise<T>,
options?: RunTaskOptions & { parseOutput?: (output: unknown) => T },
onError?: RunTaskErrorCallback
)
| 1095 | * @returns A Promise that resolves with the returned value of the callback. |
| 1096 | */ |
| 1097 | async runTask<T extends Json<T> | void>( |
| 1098 | cacheKey: string | any[], |
| 1099 | callback: (task: ServerTask, io: IO) => Promise<T>, |
| 1100 | options?: RunTaskOptions & { parseOutput?: (output: unknown) => T }, |
| 1101 | onError?: RunTaskErrorCallback |
| 1102 | ): Promise<T> { |
| 1103 | const parentId = this._taskStorage.getStore()?.taskId; |
| 1104 | |
| 1105 | if (parentId) { |
| 1106 | this._logger.debug("Using parent task", { |
| 1107 | parentId, |
| 1108 | cacheKey, |
| 1109 | options, |
| 1110 | }); |
| 1111 | } |
| 1112 | |
| 1113 | //don't auto-yield if it's a no-op and a subtask (e.g. a log inside a task) |
| 1114 | const isSubtaskNoop = options?.noop === true && parentId !== undefined; |
| 1115 | if (!isSubtaskNoop) { |
| 1116 | this.#detectAutoYield("start_task", 500); |
| 1117 | } |
| 1118 | |
| 1119 | const idempotencyKey = await generateIdempotencyKey( |
| 1120 | [this._id, parentId ?? "", cacheKey].flat() |
| 1121 | ); |
| 1122 | |
| 1123 | if (this._visitedCacheKeys.has(idempotencyKey)) { |
| 1124 | if (typeof cacheKey === "string") { |
| 1125 | throw new Error( |
| 1126 | `Task with cacheKey "${cacheKey}" has already been executed in this run. Each task must have a unique cacheKey.` |
| 1127 | ); |
| 1128 | } else { |
| 1129 | throw new Error( |
| 1130 | `Task with cacheKey "${cacheKey.join( |
| 1131 | "-" |
| 1132 | )}" has already been executed in this run. Each task must have a unique cacheKey.` |
| 1133 | ); |
| 1134 | } |
| 1135 | } |
| 1136 | |
| 1137 | this._visitedCacheKeys.add(idempotencyKey); |
| 1138 | |
| 1139 | const cachedTask = this._cachedTasks.get(idempotencyKey); |
| 1140 | |
| 1141 | if (cachedTask && cachedTask.status === "COMPLETED") { |
| 1142 | this._logger.debug("Using completed cached task", { |
| 1143 | idempotencyKey, |
| 1144 | }); |
| 1145 | |
| 1146 | this._stats.cachedTaskHits++; |
| 1147 | |
| 1148 | return options?.parseOutput |
| 1149 | ? options.parseOutput(cachedTask.output) |
| 1150 | : (cachedTask.output as T); |
| 1151 | } |
| 1152 | |
| 1153 | if (options?.noop && this._noopTasksBloomFilter) { |
| 1154 | if (this._noopTasksBloomFilter.test(idempotencyKey)) { |
no test coverage detected