RetryPolicy thread safety
See original GitHub issueIs it safe to use RetryPolicy from multiple threads?
I can see it doesn’t set it’s own members but it does add members to (array)lists of predicates. This is potentially not thread-safe and can break when using the same RetryPolicy
object from multiple threads.
Is there a standard to do this? I can copy the object for now when I modify it on specific threads, but perhaps making it thread safe is possible on your end.
Issue Analytics
- State:
- Created 7 years ago
- Reactions:1
- Comments:49 (17 by maintainers)
Top Results From Across the Web
RetryPolicy thread safety · Issue #47 · failsafe-lib ... - GitHub
Hey, I've just noticed that RetryPolicy is not thread safe as of 2.4.0. One example: delay field is not volatile, nor final, there...
Read more >Frequently Asked Questions - Failsafe
Failsafe requires the use of separate threads for a few different situations: ... When a RetryPolicy is exceeded, the last execution result or...
Read more >RetryPolicy(T) Class (Microsoft.WindowsAzure.Common ...
An instance of a callback delegate that will be invoked whenever a retry condition is encountered.(Inherited from RetryPolicy.) Thread Safety.
Read more >How to make manual retry thread safe - java - Stack Overflow
I am trying to do a manual retry. But I feel the code is not thread safe. Can anyone please ...
Read more >2 Things I learnt By Reading Failsafe Source code
Users want to reuse RetryPolicy object but because it is not immutable they fear thread safety concerns. Library author clarified that ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I’m sorry I didn’t notice that I was tagged back in October.
Initializing both condition lists with
CopyOnWriteArrayList
would avoid the CME betweenRetryPolicy#retryWhen
andRetryPolicy#canRetryFor
and similar situations, but there are other safety problems with sharing instances between threads: The double fields are vulnerable to out-of-thin-air values and the visibility of other fields is not guaranteed. Making all fieldsvolatile
(except the condition lists, which should befinal
) would provide visibility guarantees, but even then the non-atomicity of methods likewithBackoff
that modify several fields would still leaveRetryPolicy
fundamentally thread-unsafe.You could slap the
@ThreadUnsafe
annotation on the class, but documenting safe uses of a thread-unsafe class is tricky. The only safe way to share is to copy before sharing to a different thread:No one should have to perform this kind of delicate reasoning when using a class, so I think documented thread-unsafety is not a good answer.
The options, then, are either to make the class thread-safe mutable or to make it immutable, as @akincel noted. Unless someone can give compelling use cases for mutability in response to @jhalterman’s request, immutability is clearly preferable. The bar is high: To anyone thinking of presenting such a use case, I would ask whether they wouldn’t be able to make do with a
MutableRetryPolicyHolder
class with a mutable reference to an (immutable)RetryPolicy
.I don’t think the cost of creating a new
RetryPolicy
instance for each “mutable” method call is particularly high in practice. It’s hard to imagine uses that involve creating instances in a tight inner loop, because theRetryPolicy
is designed to be applied to repeatable tasks that typically take some time.Bottom line:
@Immutable
is the way to go.Very late correction (2020-July-9)
I got this one (the line marked [1]) wrong initially: There is a happens-before edge between actions taking place before submission of a task (which is what
supplyAsync
does) and the execution of that task. It’s still the case that you can’t use copy at [2].The fact that I got this wrong just goes to show how tricky the reasoning around thread-unsafe objects can be.
@reutsharabani From your scenario, it sounds like you need different
RetryPolicy
instances for each service no matter what since their retry patterns will vary. These can certainly be copied from a common base policy viacopy()
, but it’s not clear that thread-safety will solve anything in the scenario you described.Thread-safety would only be an issue if you were configuring a single
RetryPolicy
from multiple threads concurrently, or configuring aRetryPolicy
while using it via aFailsafe
call. Is there a scenario where you need to do something like this?@sunng87
RetryPolicy
is certainly reusable and shareable. Failsafe will never modify aRetryPolicy
, only read them. That said, sinceRetryPolicy
is currently not thread-safe, unexpected behavior could result if reading/writing to it concurrently.