Branch data Line data Source code
1 : : /*
2 : : * Copyright 2025 Jinwoo Sung
3 : : *
4 : : * Licensed under the Apache License, Version 2.0 (the "License");
5 : : * you may not use this file except in compliance with the License.
6 : : * You may obtain a copy of the License at
7 : : *
8 : : * http://www.apache.org/licenses/LICENSE-2.0
9 : : *
10 : : * Unless required by applicable law or agreed to in writing, software
11 : : * distributed under the License is distributed on an "AS IS" BASIS,
12 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : : * See the License for the specific language governing permissions and
14 : : * limitations under the License.
15 : : */
16 : :
17 : : #pragma once
18 : :
19 : : #include <algorithm>
20 : : #include <chrono>
21 : : #include <cstdint>
22 : : #include <optional>
23 : :
24 : : #include "wirestead/diagnostics/error_types.hpp"
25 : : #include "wirestead/transport/base/reconnect_policy.hpp"
26 : :
27 : : namespace wirestead {
28 : : namespace transport {
29 : : namespace detail {
30 : :
31 : : // Keep the existing cap used by reconnect logic to avoid runtime behavior changes.
32 : : constexpr auto MAX_RECONNECT_DELAY = std::chrono::milliseconds(30000);
33 : :
34 : : /**
35 : : * @brief Represents the decision on whether to retry a connection attempt.
36 : : */
37 : : struct ReconnectLogicDecision {
38 : : bool should_retry{false};
39 : : std::optional<std::chrono::milliseconds> delay{std::nullopt};
40 : : };
41 : :
42 : 104 : inline std::chrono::milliseconds clamp_reconnect_delay(std::chrono::milliseconds delay) {
43 [ + + ]: 104 : if (delay < std::chrono::milliseconds(0)) {
44 : 1 : return std::chrono::milliseconds(0);
45 : : }
46 : 103 : return std::min(delay, MAX_RECONNECT_DELAY);
47 : : }
48 : :
49 : : /**
50 : : * @brief Determines whether a reconnection attempt should be made and the base delay to use.
51 : : *
52 : : * This is a generic implementation that works with any configuration type that has
53 : : * max_retries and retry_interval_ms fields.
54 : : */
55 : : template <typename ConfigType>
56 : 118 : inline ReconnectLogicDecision decide_reconnect_common(const ConfigType& cfg, const diagnostics::ErrorInfo& error_info,
57 : : uint32_t attempt_count,
58 : : const std::optional<ReconnectPolicy>& policy) {
59 [ + + ]: 118 : if (!error_info.retryable) {
60 : 1 : return {false, std::nullopt};
61 : : }
62 : :
63 [ + + ]: 117 : if (cfg.max_retries == 0) {
64 : 8 : return {false, std::nullopt};
65 : : }
66 : :
67 [ + + + + ]: 109 : if (cfg.max_retries > 0 && attempt_count >= static_cast<uint32_t>(cfg.max_retries)) {
68 : 2 : return {false, std::nullopt};
69 : : }
70 : :
71 [ + + ]: 107 : if (policy) {
72 : 31 : auto policy_decision = (*policy)(error_info, attempt_count);
73 [ + + ]: 31 : if (!policy_decision.retry) {
74 : 3 : return {false, std::nullopt};
75 : : }
76 : 28 : return {true, clamp_reconnect_delay(policy_decision.delay)};
77 : : }
78 : :
79 : 76 : return {true, clamp_reconnect_delay(std::chrono::milliseconds(cfg.retry_interval_ms))};
80 : : }
81 : :
82 : : } // namespace detail
83 : : } // namespace transport
84 : : } // namespace wirestead
|