userver: userver/engine/wait_all_checked.hpp Source File
Loading...
Searching...
No Matches
wait_all_checked.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/engine/wait_all_checked.hpp
4/// @brief Provides engine::WaitAllChecked
5
6#include <chrono>
7#include <vector>
8
9#include <userver/engine/awaitable.hpp>
10#include <userver/engine/deadline.hpp>
11#include <userver/engine/future_status.hpp>
12#include <userver/utils/meta.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace engine {
17
18/// @ingroup userver_concurrency
19///
20/// @brief Waits for the successful completion of all of the specified tasks
21/// or for the cancellation of the caller.
22///
23/// Effectively performs `for (auto& task : tasks) task.Wait();` with a twist:
24/// if any task completes with an exception, it gets rethrown ASAP.
25///
26/// Invalid tasks are skipped.
27///
28/// Tasks are not invalidated by `WaitAllChecked`; the result can be retrieved
29/// after the call.
30///
31/// @param tasks either a single container, or a pack of future-like elements.
32/// @throws WaitInterruptedException when `current_task::ShouldCancel()` (for
33/// WaitAllChecked versions without a deadline)
34/// @throws std::exception one of specified tasks exception, if any, in no
35/// particular order.
36///
37/// @note Has overall computational complexity of O(N),
38/// where N is the number of tasks.
39/// @note Keeping the tasks valid may have a small extra memory impact. Make
40/// sure to drop the tasks after reading the results.
41/// @note Prefer engine::GetAll for tasks without a result, unless you
42/// specifically need to keep the tasks alive for some reason.
43template <typename... Tasks>
44void WaitAllChecked(Tasks&... tasks);
45
46/// @ingroup userver_concurrency
47///
48/// @overload void WaitAllChecked(Tasks&... tasks)
49template <typename... Tasks, typename Rep, typename Period>
50[[nodiscard]] FutureStatus WaitAllCheckedFor(const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks);
51
52/// @ingroup userver_concurrency
53///
54/// @overload void WaitAllChecked(Tasks&... tasks)
55template <typename... Tasks, typename Clock, typename Duration>
56[[nodiscard]] FutureStatus WaitAllCheckedUntil(const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks);
57
58/// @ingroup userver_concurrency
59///
60/// @overload void WaitAllChecked(Tasks&... tasks)
61template <typename... Tasks>
62[[nodiscard]] FutureStatus WaitAllCheckedUntil(Deadline deadline, Tasks&... tasks);
63
64namespace impl {
65
66FutureStatus DoWaitAllChecked(std::vector<AwaitableToken>&& targets, Deadline deadline);
67
68template <typename Container>
69FutureStatus WaitAllCheckedFromContainer(Deadline deadline, Container& tasks) {
70 std::vector<AwaitableToken> targets;
71 targets.reserve(std::size(tasks));
72
73 for (auto& task : tasks) {
74 static_assert(engine::Awaitable<decltype(task)>, "Tasks must be awaitable");
75 targets.push_back(task.GetAwaitableToken());
76 }
77
78 return impl::DoWaitAllChecked(std::move(targets), deadline);
79}
80
81template <typename... Tasks>
82FutureStatus WaitAllCheckedFromTasks(Deadline deadline, Tasks&... tasks) {
83 static_assert((true && ... && engine::Awaitable<Tasks>), "Tasks must be awaitable");
84 return impl::DoWaitAllChecked({tasks.GetAwaitableToken()...}, deadline);
85}
86
87inline FutureStatus WaitAllCheckedFromTasks(Deadline /*deadline*/) { return FutureStatus::kReady; }
88
89void HandleWaitAllStatus(FutureStatus status);
90
91} // namespace impl
92
93template <typename... Tasks>
94void WaitAllChecked(Tasks&... tasks) {
95 impl::HandleWaitAllStatus(engine::WaitAllCheckedUntil(Deadline{}, tasks...));
96}
97
98template <typename... Tasks, typename Rep, typename Period>
99[[nodiscard]] FutureStatus WaitAllCheckedFor(const std::chrono::duration<Rep, Period>& duration, Tasks&... tasks) {
100 return WaitAllCheckedUntil(Deadline::FromDuration(duration), tasks...);
101}
102
103template <typename... Tasks, typename Clock, typename Duration>
104[[nodiscard]] FutureStatus WaitAllCheckedUntil(const std::chrono::time_point<Clock, Duration>& until, Tasks&... tasks) {
105 return WaitAllCheckedUntil(Deadline::FromTimePoint(until), tasks...);
106}
107
108template <typename... Tasks>
109[[nodiscard]] FutureStatus WaitAllCheckedUntil(Deadline deadline, Tasks&... tasks) {
110 if constexpr (meta::impl::IsSingleRange<Tasks...>) {
111 return impl::WaitAllCheckedFromContainer(deadline, tasks...);
112 } else {
113 return impl::WaitAllCheckedFromTasks(deadline, tasks...);
114 }
115}
116
117} // namespace engine
118
119USERVER_NAMESPACE_END