private async Task ExecuteOp(IOperation op, CancellationToken token = default(CancellationToken), TimeSpan?timeout = null) { // wire up op's completed function var tcs = new TaskCompletionSource <IMemoryOwner <byte> >(); op.Completed = state => { if (state.Status == ResponseStatus.Success) { tcs.SetResult(state.ExtractData()); } else { tcs.SetException(KeyValueException.Create(state.Status, errorMap: state.ErrorMap)); } return(tcs.Task); }; CancellationTokenSource cts = null; try { if (token == CancellationToken.None) { cts = CancellationTokenSource.CreateLinkedTokenSource(token); cts.CancelAfter(timeout.HasValue && timeout != TimeSpan.Zero ? timeout.Value : DefaultTimeout); token = cts.Token; } using (token.Register(() => { if (tcs.Task.Status != TaskStatus.RanToCompletion) { tcs.SetCanceled(); } }, useSynchronizationContext: false)) { await _bucket.Send(op, tcs).ConfigureAwait(false); var bytes = await tcs.Task.ConfigureAwait(false); await op.ReadAsync(bytes).ConfigureAwait(false); } } catch (OperationCanceledException e) { if (!e.CancellationToken.IsCancellationRequested) { //oddly IsCancellationRequested is false when timed out throw new TimeoutException(); } } finally { //clean up the token if we used a default token cts?.Dispose(); } }
private async Task ExecuteOp(IOperation op, CancellationToken token = default(CancellationToken), TimeSpan?timeout = null) { // wire up op's completed function var tcs = new TaskCompletionSource <byte[]>(); op.Completed = state => { if (state.Status == ResponseStatus.Success) { tcs.SetResult(state.Data.ToArray()); } else { tcs.SetException(new Exception(state.Status.ToString())); } return(tcs.Task); }; CancellationTokenSource cts = null; if (token == CancellationToken.None) { cts = CancellationTokenSource.CreateLinkedTokenSource(token); cts.CancelAfter(timeout.HasValue && timeout != TimeSpan.Zero ? timeout.Value : DefaultTimeout); token = cts.Token; } using (token.Register(() => { if (tcs.Task.Status != TaskStatus.RanToCompletion) { tcs.SetCanceled(); } }, useSynchronizationContext: false)) { await _bucket.Send(op, tcs).ConfigureAwait(false); var bytes = await tcs.Task.ConfigureAwait(false); await op.ReadAsync(bytes).ConfigureAwait(false); //clean up the token if we used a default token cts?.Dispose(); } }