@@ -34,6 +34,14 @@ defmodule Tesla.Middleware.Retry do
34
34
{:ok, _} -> false
35
35
{:error, _} -> true
36
36
end
37
+ # or
38
+ plug Tesla.Middleware.Retry, should_retry: fn
39
+ {:ok, %{status: status}}, _env, _context when status in [400, 500] -> true
40
+ {:ok, _reason}, _env, _context -> false
41
+ {:error, _reason}, %Tesla.Env{method: :post}, _context -> false
42
+ {:error, _reason}, %Tesla.Env{method: :put}, %{retries: 2} -> false
43
+ {:error, _reason}, _env, _context -> true
44
+ end
37
45
end
38
46
```
39
47
@@ -42,7 +50,9 @@ defmodule Tesla.Middleware.Retry do
42
50
- `:delay` - The base delay in milliseconds (positive integer, defaults to 50)
43
51
- `:max_retries` - maximum number of retries (non-negative integer, defaults to 5)
44
52
- `:max_delay` - maximum delay in milliseconds (positive integer, defaults to 5000)
45
- - `:should_retry` - function to determine if request should be retried
53
+ - `:should_retry` - function with an arity of 1 or 3 used to determine if the request should
54
+ be retried the first argument is the result, the second is the env and the third is
55
+ the context: options + `:retries` (defaults to a match on `{:error, _reason}`)
46
56
- `:jitter_factor` - additive noise proportionality constant
47
57
(float between 0 and 1, defaults to 0.2)
48
58
"""
@@ -65,7 +75,7 @@ defmodule Tesla.Middleware.Retry do
65
75
delay: integer_opt! ( opts , :delay , 1 ) ,
66
76
max_retries: integer_opt! ( opts , :max_retries , 0 ) ,
67
77
max_delay: integer_opt! ( opts , :max_delay , 1 ) ,
68
- should_retry: Keyword . get ( opts , :should_retry , & match? ( { :error , _ } , & 1 ) ) ,
78
+ should_retry: should_retry_opt! ( opts ) ,
69
79
jitter_factor: float_opt! ( opts , :jitter_factor , 0 , 1 )
70
80
}
71
81
@@ -84,15 +94,26 @@ defmodule Tesla.Middleware.Retry do
84
94
defp retry ( env , next , context ) do
85
95
res = Tesla . run ( env , next )
86
96
87
- if context . should_retry . ( res ) do
88
- backoff ( context . max_delay , context . delay , context . retries , context . jitter_factor )
89
- context = update_in ( context , [ :retries ] , & ( & 1 + 1 ) )
90
- retry ( env , next , context )
91
- else
92
- res
97
+ { :arity , should_retry_arity } = :erlang . fun_info ( context . should_retry , :arity )
98
+
99
+ cond do
100
+ should_retry_arity == 1 and context . should_retry . ( res ) ->
101
+ do_retry ( env , next , context )
102
+
103
+ should_retry_arity == 3 and context . should_retry . ( res , env , context ) ->
104
+ do_retry ( env , next , context )
105
+
106
+ true ->
107
+ res
93
108
end
94
109
end
95
110
111
+ defp do_retry ( env , next , context ) do
112
+ backoff ( context . max_delay , context . delay , context . retries , context . jitter_factor )
113
+ context = update_in ( context , [ :retries ] , & ( & 1 + 1 ) )
114
+ retry ( env , next , context )
115
+ end
116
+
96
117
# Exponential backoff with jitter
97
118
defp backoff ( cap , base , attempt , jitter_factor ) do
98
119
factor = Bitwise . bsl ( 1 , attempt )
@@ -124,6 +145,19 @@ defmodule Tesla.Middleware.Retry do
124
145
end
125
146
end
126
147
148
+ defp should_retry_opt! ( opts ) do
149
+ case Keyword . get ( opts , :should_retry , & match? ( { :error , _ } , & 1 ) ) do
150
+ should_retry_fun when is_function ( should_retry_fun , 1 ) ->
151
+ should_retry_fun
152
+
153
+ should_retry_fun when is_function ( should_retry_fun , 3 ) ->
154
+ should_retry_fun
155
+
156
+ value ->
157
+ invalid_should_retry_fun ( value )
158
+ end
159
+ end
160
+
127
161
defp invalid_integer ( key , value , min ) do
128
162
raise ( ArgumentError , "expected :#{ key } to be an integer >= #{ min } , got #{ inspect ( value ) } " )
129
163
end
@@ -134,4 +168,11 @@ defmodule Tesla.Middleware.Retry do
134
168
"expected :#{ key } to be a float >= #{ min } and <= #{ max } , got #{ inspect ( value ) } "
135
169
)
136
170
end
171
+
172
+ defp invalid_should_retry_fun ( value ) do
173
+ raise (
174
+ ArgumentError ,
175
+ "expected :should_retry to be a function with arity of 1 or 3, got #{ inspect ( value ) } "
176
+ )
177
+ end
137
178
end
0 commit comments