engine::TaskProcessor or task processor is a thread pool on which the tasks (engine::Task, engine::TaskWithresult) are executed.
Task processors are configured via the static config file and are created at the start of the component system. Example:
Any amount of task processors could be created with any names.
utils::Async and engine::AsyncNoSpan start a new task on a provided as a first argument task processor. If the task processor is not provided utils::Async and engine::AsyncNoSpan use the task processor that runs the current task (engine::current_task::GetTaskProcessor()).
A task processor could be obtained from components::ComponentContext in the constructor of the component. References to task processors outlive the component system tear-down, they are safe to use from within any components:
main-task-processor
, then the thread and the processor core are idle until the system call ends. As a result, the throughput of the service temporarily decreases. To prevent this from happening, use userver provided primitives or if the primitive is missing, run the blocking system call on a separate task processor.Task processors intentionally hide their internals and member functions, so there's no way to call any of the task processor members directly.
In static configuration we use different names for task processors. The name does not affect the task processor behavior, only gives a hint on its usage for the developer.
This is usually the default task processor for CPU bound tasks. It is used to
Task processor for blocking calls. For example, for functions from blocking
namespaces, low-level blocking system calls or third-party library code that does blocking calls.
blocking
namespaces or do not have blocking
in their name are non-blocking! For example, there's no need to run engine::io::Socket::ReadAll() in fs-task-processor
, use the main-task-processor
instead.A common usage pattern for this task processor looks like:
Or:
Used for running task that do not permit concurrent execution (for example V8 or other interpreters). components::SingleThreadedTaskProcessors usually starts those task processors.
This task processor is used for diagnostic and administration handlers and tasks. Separate task processor helps to control service under heavy load or get info from a server with deadlocked threads in the main-task-processor
, e.g. server::handlers::InspectRequests handler.
Some background tasks can slow down handles even if those tasks don't execute a blocking wait:
As a workaround for the issue the heavy background tasks could be moved to a separate bg-task-processor
task processor.
There are multiple ways to prevent background tasks from consuming 100% of CPU cores:
os-scheduling
static option to give lower priority for background tasks.Make sure that tasks execute faster than they arrive.