Почему CancellationToken хранится в исключении, отличном от токена, предоставленного CancellationTokenSource?
Это деталь реализации. Я не смотрел на источник, но я подозреваю , что CancellationToken
, предоставленный ExecuteScalarAsync
, объединяется с некоторым внутренним CancellationToken
, что означает "мы потеряли соединение" или что-то вроде того. Эти связанные CancellationToken
s не эквивалентны их источнику CancellationToken
s.
Это проблема использования с CancellationToken
s в целом. Со связанными токенами не всегда возможно определить , какой токен отмены вызвал отмену. По этой причине я рекомендую проверить вашу собственную копию токена отмены через catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
:
static async Task Main(string[] args)
{
var timeout = TimeSpan.FromSeconds(1);
var cts = new CancellationTokenSource(timeout);
try
{
await IndirectDelay(10, cts.Token);
await Task.Delay(timeout + TimeSpan.FromSeconds(1));
await IndirectDelay(10, cts.Token);
}
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
{
Console.WriteLine(ex.CancellationToken == cts.Token); // false
Console.WriteLine("Our token is canceled.");
}
catch (OperationCanceledException)
{
Console.WriteLine("Canceled for some other reason.");
}
catch (Exception)
{
Console.WriteLine("General error.");
}
}
private static async Task IndirectDelay(int timeout, CancellationToken token)
{
using (var internalCts = new CancellationTokenSource())
using (var cts = CancellationTokenSource.CreateLinkedTokenSource(token, internalCts.Token))
await Task.Delay(timeout, cts.Token);
}
Существует вероятность состояния гонки, когда ваш код думает , что отмена происходит из-за тайм-аута, но на самом деле это из-за разрыва соединения (или какой-либо внутренней логики), но в большинстве случаях это не имеет значения.