Crate async_tasks_recorder
source ·Expand description
§Introduction
A struct for recording execution status of async tasks with lock-free and async methods.
Can host Futures and query whether they are not found, successful, failed, or running.
- Depend on
tokiowith featurert, so cannot use other async runtimes. - Depend on scc for lock-free and async
HashSet.
Use this crate if:
- Easy to generate an unique
task_id(not necessarilyString) for a future (task). - Tasks might fail, and then you want to run it again, while you don’t want it to success more then once.
- Want to record and query all succeeded tasks and failed tasks.
- Want to handling every task in the same state (e.g.
success).
A recorder can only use one task_id type. The type of task_id should be:
Eq + Hash + Clone + Send + Sync + 'static- Cheap to clone (sometimes can use
Arc).
And remember, you can add anything in the Future to achieve the functionality you want.
For example:
- Handle your
ResultinFuture, and then return empty resultResult<(),()>. - Send a message to a one shot channel at the end of the
Futureto notify upper level that “This task is done”. Don’t forget to consider usingtokio::spawnwhen the channel may not complete sending immediately. - Set other callback functions.
It is recommended to directly look at the source code (about 100 line) if there is any confusion.
NOTE: This crate use three HashSet to make it easy to handle all tasks in the same state.
But scc::HashSet have less contention in single access when it grows larger.
Therefore, if you don’t need handling every tasks in the same state,
then just use scc::HashMap (task_id -> task_status) to build a simpler implementation,
which might have less contention and clone, but more expansive to iterator.
§Usage
Launch a task with a unique task_id and a Future by launch.
Query the state of the task with its task_id
by query_task_state or query_task_state_quick.
§Theory & Design
§Abstract Model
Here is the three-level structure for thinking about tasks’ status:
- Level 0:
real_none,real_failed,real_working,real_success: Exact status of the tasks in the CPU (seen by God). - Level 1:
failed_tasks,working_tasks,success_tasks: Containers to storetask_ids (atask_idcan be stored in 0 to 2 containers simultaneously). - Level 2:
Not Found,Failed,Working,Success: States of the task that could be obtained byquery_task_state.
§State Transition Diagram
Not Found---->WorkingWorking<--->FailedWorking---->Success
If you equivalent Not Found to Failed, then:
Failed <---> Working ----> Success
§Nature
§About Task
- A task is launched by passing a
Future<Output=Result<R, E>>with uniquetask_id. - A task is
real_successwhen returnOk(R), andreal_failedwhen returnErr(E). - Different future with the same
task_idis considered the same task. - The same task can only
real_successonce, e.g. a purchase process would never succeed more then once by launching with unique process id astask_id.
§About Task State
- If a task’s state is
Success, it must bereal_success, i.e. $\text{Success}(id) \rightarrow \text{real_success}(id)$. - If a task’s state is
Failed, it may be in any status, but mostlyreal_failed. - If a task’s state is
Working, it may be in any status, but mostlyreal_working. - If a task’s state is
Not Found, it may be in any status, but mostlyreal_none.
§About Task State Transition
- Any task’s state can be queried at any time.
- The initial state of the task is
Not Found, and won’t change immediately afterlaunch. - Always, when a task whose state is
FailedorNotFoundis launched, it will beWorkingat some future moment. - Always, when a task is
Working, it would eventually beFailorSuccess, i.e. $\Box (\text{Working}(id) \rightarrow \lozenge(\text{Fail}(id) \vee \text{Success}(id)))$. - Always, when a task is
Success, it would beSuccessforever, i.e. $\Box (\text{Success}(id) \rightarrow \Box \text{Success}(id))$.
§Other
Relationship between states and containers at query_task_state.
Further propositions and proofs at AsyncTasksRecoder.
Use query_task_state_quick for less contention.
Structs§
- Arc was used internally, so after
clone, the sameTaskManagerwas used, which means you can shareAsyncTasksRecoderby clone. - Thread-safe.