Project: userver (App Definition and Development / Streaming & Messaging)
File: task_processors_guide.md

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 @ref scripts/docs/en/userver/component_system.md "component system". Example: @snippet components/commoncomponentlist_test.cpp Sample components manager config component config 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: @snippet components/componentsampletest.cpp Sample user component source @warning If a blocking system call (for example, one that reads a file in a synchronous way) runs on `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 @ref scripts/docs/en/userver/intro.md "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 start the component system, call constructors of the components; for initialization of the caches (if not specified otherwise); for accepting incoming requests and processing them; do all the other CPU bound things; @note congestion_control::Component at the moment monitors only the task processor that starts the component system. Handlers that run on other tasks processors are not

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. @note Functions from the userver framework that are not in the `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: ```cpp // lib_sample synchronously reads some of /etc/* files. auto result = engine::AsyncNoSpan(fstaskprocessor_, { return libsample::quickcheckconfigpreset(preset_name); }).Get(); ``` Or: ```cpp auto result = engine::Async(fstaskprocessor_, "torrent/validate", { auto files = libtorrent::discover_files(path); // searches FS return libtorrent::validate_hashes(files); // reads files and computes hashes }).Get(); ``` 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. @warning Test and load-test your service, the feature may do things worse. Some background tasks can slow down handles even if those tasks don't execute a blocking wait: Multiple background tasks can start running at the same time Worse if those background tasks are CPU-heavy and don't call engine::Yield It can also be a problem if parallel tasks are launched in caches. Then one cache is able to fill the entire task processor with tasks 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: Allocate the minimum possible number of threads for background task processors, less than CPU cores. Experiment with the `os-scheduling` static option to give lower priority for background tasks. Make sure that tasks execute faster than they arrive. @htmlonly <div class="bottom-nav"> @endhtmlonly @ref scripts/docs/en/userver/logging.md | @ref scripts/docs/en/userver/periodics.md @htmlonly </div> @endhtmlonly