Line data Source code
1 : #include "NetworkRetryPolicy.h"
2 : #include <algorithm>
3 : #include <cmath>
4 :
5 0 : NetworkRetryPolicy::NetworkRetryPolicy()
6 0 : : maxNumRetries(0)
7 0 : , defaultDelayMs(1000)
8 0 : , maxDelayMs(60000)
9 0 : , strategy(Exponential)
10 0 : , shouldRetryOnTimeout(true)
11 0 : , shouldRetryOnDnsFailure(true)
12 0 : , shouldRetryOnConnectionRefused(true)
13 0 : , shouldRetryOnServerError(true)
14 : {
15 0 : }
16 :
17 43 : NetworkRetryPolicy::NetworkRetryPolicy(int maxRetries, int baseDelay, BackoffStrategy strategy, int maxDelay)
18 43 : : maxNumRetries(maxRetries)
19 43 : , defaultDelayMs(baseDelay)
20 43 : , maxDelayMs(maxDelay)
21 43 : , strategy(strategy)
22 43 : , shouldRetryOnTimeout(true)
23 43 : , shouldRetryOnDnsFailure(true)
24 43 : , shouldRetryOnConnectionRefused(true)
25 43 : , shouldRetryOnServerError(true)
26 : {
27 43 : }
28 :
29 4 : NetworkRetryPolicy NetworkRetryPolicy::forFeedUpdate()
30 : {
31 : // Medium importance: 3 retries with exponential backoff: 2s, 4s, 8s
32 4 : return NetworkRetryPolicy(3, 2000, Exponential, 30000);
33 : }
34 :
35 1 : NetworkRetryPolicy NetworkRetryPolicy::forFavicon()
36 : {
37 : // Non-critical: 2 retries with linear backoff: 1s, 2s
38 1 : return NetworkRetryPolicy(2, 1000, Linear, 5000);
39 : }
40 :
41 1 : NetworkRetryPolicy NetworkRetryPolicy::forCritical()
42 : {
43 : // Give it our best shot: 5 retries with fibonacci backoff: 1s, 2s, 3s, 5s, 8s
44 1 : return NetworkRetryPolicy(5, 1000, Fibonacci, 60000);
45 : }
46 :
47 25 : NetworkRetryPolicy NetworkRetryPolicy::noRetry()
48 : {
49 25 : return NetworkRetryPolicy(0, 0, Fixed, 0);
50 : }
51 :
52 30 : bool NetworkRetryPolicy::isRetryable(QNetworkReply::NetworkError error) const
53 : {
54 30 : switch (error) {
55 : // Network errors
56 1 : case QNetworkReply::ConnectionRefusedError:
57 1 : return shouldRetryOnConnectionRefused;
58 :
59 2 : case QNetworkReply::RemoteHostClosedError:
60 : case QNetworkReply::HostNotFoundError:
61 2 : return shouldRetryOnDnsFailure;
62 :
63 14 : case QNetworkReply::TimeoutError:
64 : case QNetworkReply::OperationCanceledError:
65 14 : return shouldRetryOnTimeout;
66 :
67 3 : case QNetworkReply::TemporaryNetworkFailureError:
68 : case QNetworkReply::NetworkSessionFailedError:
69 : case QNetworkReply::BackgroundRequestNotAllowedError:
70 3 : return true;
71 :
72 : // Don't retry at all for SSL errors
73 2 : case QNetworkReply::SslHandshakeFailedError:
74 : case QNetworkReply::UnknownServerError:
75 2 : return false;
76 :
77 : // Protocol errors are also not retryable (is that a word?)
78 2 : case QNetworkReply::ProtocolUnknownError:
79 : case QNetworkReply::ProtocolInvalidOperationError:
80 : case QNetworkReply::ProtocolFailure:
81 2 : return false;
82 :
83 : // HTTP-specific errors
84 2 : case QNetworkReply::InternalServerError:
85 : case QNetworkReply::ServiceUnavailableError:
86 2 : return shouldRetryOnServerError;
87 :
88 : // Oddball errors that we should try again ASAP
89 0 : case QNetworkReply::UnknownNetworkError:
90 : case QNetworkReply::UnknownProxyError:
91 : case QNetworkReply::UnknownContentError:
92 0 : return true;
93 :
94 : // No point in retrying these
95 4 : case QNetworkReply::ContentAccessDenied:
96 : case QNetworkReply::ContentNotFoundError:
97 : case QNetworkReply::AuthenticationRequiredError:
98 : case QNetworkReply::ContentOperationNotPermittedError:
99 4 : return false;
100 :
101 0 : case QNetworkReply::NoError:
102 0 : return false;
103 :
104 0 : default:
105 : // Retry by default
106 0 : return true;
107 : }
108 : }
109 :
110 33 : int NetworkRetryPolicy::calculateDelay(int attemptNumber) const
111 : {
112 33 : if (attemptNumber >= maxNumRetries) {
113 0 : return 0;
114 : }
115 :
116 : int delay;
117 :
118 33 : switch (strategy) {
119 4 : case Linear:
120 4 : delay = defaultDelayMs * (attemptNumber + 1);
121 4 : break;
122 :
123 7 : case Exponential:
124 7 : delay = static_cast<int>(defaultDelayMs * std::pow(2, attemptNumber));
125 7 : break;
126 :
127 6 : case Fibonacci: {
128 : // Math alert! Find the next Fibonacci number for this attempt.
129 6 : int fib1 = 1, fib2 = 1;
130 16 : for (int i = 0; i < attemptNumber; ++i) {
131 10 : int temp = fib1 + fib2;
132 10 : fib1 = fib2;
133 10 : fib2 = temp;
134 : }
135 6 : delay = defaultDelayMs * fib2;
136 6 : break;
137 : }
138 :
139 16 : case Fixed:
140 : default:
141 16 : delay = defaultDelayMs;
142 16 : break;
143 : }
144 :
145 : // Max delay.
146 33 : return std::min(delay, maxDelayMs);
147 : }
|