Skip to content

Commit

Permalink
caching the CancellationToken will prevent race condition (#2125)
Browse files Browse the repository at this point in the history
To be a good citizen, it is important that the caller of this method can (and should) call Dispose() on the returned token source. The problem though, is that each time cts.Token was called before, it would try to create a new CancellationToken which means that it could throw an ObjectDisposed exception leading to noisy logs.
  • Loading branch information
jstnlef authored May 19, 2024
1 parent 3c04ac2 commit e8ba0f6
Showing 1 changed file with 16 additions and 33 deletions.
49 changes: 16 additions & 33 deletions src/Proto.Actor/Timers/Scheduler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace Proto.Timers;
/// </summary>
/// <remarks>
/// The user is responsible for cancelling sends. They will not be automatically
/// cancelled when this object is distroyed and will be left around in the background.
/// cancelled when this object is destroyed and will be left around in the background.
/// </remarks>
[PublicAPI]
public class Scheduler
Expand All @@ -37,13 +37,14 @@ public Scheduler(ISenderContext context)
public CancellationTokenSource SendOnce(TimeSpan delay, PID target, object message)
{
var cts = new CancellationTokenSource();
var token = cts.Token;

_ = SafeTask.Run(async () =>
{
await Task.Delay(delay, cts.Token).ConfigureAwait(false);
await Task.Delay(delay, token).ConfigureAwait(false);

_context.Send(target, message);
}, cts.Token
}, token
);

return cts;
Expand All @@ -70,28 +71,19 @@ public CancellationTokenSource SendRepeatedly(TimeSpan interval, PID target, obj
public CancellationTokenSource SendRepeatedly(TimeSpan delay, TimeSpan interval, PID target, object message)
{
var cts = new CancellationTokenSource();
var token = cts.Token;

_ = SafeTask.Run(async () =>
{
await Task.Delay(delay, cts.Token).ConfigureAwait(false);
await Task.Delay(delay, token).ConfigureAwait(false);

async Task Trigger()
while (!cts.IsCancellationRequested)
{
while (true)
{
if (cts.IsCancellationRequested)
{
return;
}
_context.Send(target, message);

_context.Send(target, message);

await Task.Delay(interval, cts.Token).ConfigureAwait(false);
}
await Task.Delay(interval, token).ConfigureAwait(false);
}

await Trigger().ConfigureAwait(false);
}, cts.Token
}, token
);

return cts;
Expand All @@ -109,28 +101,19 @@ async Task Trigger()
public CancellationTokenSource RequestRepeatedly(TimeSpan delay, TimeSpan interval, PID target, object message)
{
var cts = new CancellationTokenSource();
var token = cts.Token;

_ = SafeTask.Run(async () =>
{
await Task.Delay(delay, cts.Token).ConfigureAwait(false);
await Task.Delay(delay, token).ConfigureAwait(false);

async Task Trigger()
while (!cts.IsCancellationRequested)
{
while (true)
{
if (cts.IsCancellationRequested)
{
return;
}
_context.Request(target, message);

_context.Request(target, message);

await Task.Delay(interval, cts.Token).ConfigureAwait(false);
}
await Task.Delay(interval, token).ConfigureAwait(false);
}

await Trigger().ConfigureAwait(false);
}, cts.Token
}, token
);

return cts;
Expand Down

0 comments on commit e8ba0f6

Please sign in to comment.