task-manager
What is a task-manager?
This library helps solve the common development problem of managing complex, resource-intensive asynchronous tasks (workflows).
Imagine you have a request for a Service
that needs to execute a sequential workflow consisting of several lengthy asynchronous steps in order to return the final result.
If this task takes a significant amount of time, the user may want to cancel it manually or by timeout. If this task has multiple lengthy asynchronous steps and a cancel request can be made at any point in this complex flow, you would want to cancel it as soon as possible and skip all subsequent steps. Each step's cancellation may require its own logic to clean up and free consumed resources.
If resources for doing smth 1
or doing smth 2
are limited - you may want to add some internal Queue to collect incoming requests and perform the execution of these workflow steps one by one.
In task-manager this possibility implemented as an addon and can be optionally added if needed. The basic behavior of task-manager includes only canceling logic.
The main idea of task-manager
:
-
You create your own TaskManager where define
ExecutionFlow
.ExecutionFlow
made ofStep
s - for eachStep
you defineRunLogic
- async function that performs logic you want to do, likedoing smth 1
, andCancelLogic
- async function that performs all cleaning up you want to do if canceling happened during this step. -
On incoming request, you create
TaskPassport
that contains the type of task and payload of your request. -
Save
taskId
of the task you are performing to be able to cancel it if needed.
const STEP_2_RESULT = 'step_2_result';
const SOME_RUNTIME_VALUE = 'some_runtime_value';
const step1 = new Step(
'step_1_name',
async (task: MyTask) => {
// do something 1
task.addRuntimeInfo('someRuntimeValue', SOME_RUNTIME_VALUE);
// return nothing
},
async () => {
// clean up if canceled during step 1
},
);
const step2 = new Step(
'step_2_name',
async () => {
// do something 2
return STEP_2_RESULT;
},
async () => {
// clean up if canceled during step 2
},
);
class MyTaskManager extends AbstractTaskManager {
executeTestFlow = super.createFlow<MyTaskPassport, MyTaskRuntimeInfo, MyTaskResultData>([
step1,
step2,
]);
}
const manager = new MyTaskManager();
// for each incoming request
const taskPassport = new MyTaskPassport(/* payload */);
const result = await manager.executeTestFlow(taskPassport);
// if cancel request ->
manager.cancel(taskPassport.taskId);
// cancel by timeout
setTimeout(() => {
manager.cancel(taskPassport.taskId);
}, 1000);