clockwork
clockwork copied to clipboard
Add a new interface method: AfterTime
Without this iterface, there is an unresolvable race condition with After
vs. Advance
. In one go routine, you might:
deadline := /* some deadline in the future */;
wait := deadline.Sub(fc.Now());
select {
case <-fc.After(wait):
}
And in another, you might:
fc.Advance(3)
The problem is that two go-routines might interleave arbitrarily. The solution is to compute the deadline and to call After
atomically, but you can't do that without sleeping on a lock. I believe BlockUntil
was partially invented to handle this problem, so that you could call Advance
only after you know that the other go-routine was selecting on the After
. But it can be quite challenging to figure out which parameter to pass to BlockUntil
, especially if your code is happy to let old After
calls just dangle until they expire (which otherwise isn't a problem).
The solution is just to add a new interface method, which is to write to a channel after a given time has been surpassed. This feature was basically available internally, but this PR makes it available publicly.
Fyi, #13 seems to fix the problem as well, as it's rewriting the After
method to use timers. (At least it fixes the snippet from above)
What's the status of this PR? Is there a reason it's been sitting for so long?
I'm not sure I like the idea of adding a non-standard method either. Although I'm not sure I understand the problem completely, sounds like #44 could be a fix for the above. Can you please try and let me know? Thanks!
Closing with no activity (recent changes may have provided a fix for the root cause).