Skip to content

Instantly share code, notes, and snippets.

@neuecc
Created August 3, 2022 08:42
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save neuecc/895b1ae705479214ff74cae89e48c38e to your computer and use it in GitHub Desktop.
Save neuecc/895b1ae705479214ff74cae89e48c38e to your computer and use it in GitHub Desktop.
class Client : IDisposable
{
readonly TimeSpan timeout;
readonly ObjectPool<CancellationTokenSource> timeoutTokenSourcePool;
readonly CancellationTokenSource clientLifetimeTokenSource;
public TimeSpan Timeout { get; }
public Client(TimeSpan timeout)
{
this.Timeout = timeout;
this.timeoutTokenSourcePool = ObjectPool.Create<CancellationTokenSource>();
this.clientLifetimeTokenSource = new CancellationTokenSource();
}
public async Task SendAsync(CancellationToken cancellationToken = default)
{
var timeoutTokenSource = timeoutTokenSourcePool.Get();
CancellationTokenRegistration externalCancellation = default;
if (cancellationToken.CanBeCanceled)
{
// call Timeout's cancel from argument CancellationToken
externalCancellation = cancellationToken.UnsafeRegister(static state =>
{
((CancellationTokenSource)state!).Cancel();
}, timeoutTokenSource);
}
// same as Client's lifetime
var clientLifetimeCancellation = clientLifetimeTokenSource.Token.UnsafeRegister(static state =>
{
((CancellationTokenSource)state!).Cancel();
}, timeoutTokenSource);
timeoutTokenSource.CancelAfter(Timeout);
try
{
await SendCoreAsync(timeoutTokenSource.Token);
}
finally
{
// Unregisters
externalCancellation.Dispose();
clientLifetimeCancellation.Dispose();
if (timeoutTokenSource.TryReset())
{
timeoutTokenSourcePool.Return(timeoutTokenSource);
}
}
}
async Task SendCoreAsync(CancellationToken cancellationToken)
{
// snip...
}
public void Dispose()
{
clientLifetimeTokenSource.Cancel();
clientLifetimeTokenSource.Dispose();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment