Comments 13
Рекомендации
Не совсем соглашусь в плане данных рекомендаций. В приведённом вами фрагменте кода происходит утечка регистраций. Вызов tokenRegistration.Dispose()
осуществляется только в случае исключения. Если же исключения нет, .Dispose()
никем не вызывается.
С тем же успехом можно для каждой итерации создавать свой CancellationTokenSource и забывать делать ему Dispose, когда токен становится не нужен.
То есть код достаточно переписать таким образом, чтобы tokenRegistration.Dispose()
вызывался после вызова DbDataReader.Dispose()
. Ну да, придётся сделать враппер.
И ещё: проверять cancellationToken.CanBeCanceled
нет необходимости, т.к.:
https://github.com/microsoft/referencesource/blob/master/mscorlib/system/threading/CancellationToken.cs#L332
То есть сразу писать:
var tokenRegistration = cancellationToken.Register(new Action(this.CancelIgnoreFailure));
Если говорит о нашей регистрации, то Dispose вызывался при остановке сервиса. Но из-за особенностей «примера», о которых мы не знали, происходила утечка регистраций.
using (var source = new CancellationTokenSource(TimeSpan.FromSeconds(15))
using (var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(source.Token, cancellationToken))
Что думаете насчет такого подхода?
То есть клиент оказался абсолютно синхронным (вот это открытие).
Неуправляемый Oracle Client — полностью синхронный внутри.
Управляемый тоже. На форуме Oracle менеджеры по общественному питанию кормят аудиторию завтраками уже который квартал.
Но я считаю, что это ошибка Microsoft. Когда они добавляли асинхронные методы в базовые классы ADO.NET, у них было три варианта
- сделать абстрактные методы и сломать все драйвера (Microsoft так не делает никогда)
- сделать методы, которые делают throw new NotImplementedException();
- сделать методы, которые вызывают синхронные методы и возвращают Task.FromResult()
Что они сделали, вы можете догадаться (и проверить себя). Я бы выбрал вариант 2, потому что с ним не было бы возможности узнать, что драйвер твоей СУБД оказался синхронным, уже отлаживая баги в проде.
Да. Помимо приколов, что в асинхронных методах возвращается Task.FromResult()
я ещё сталкивался с обратной ситуацией, когда асинхронный код является основным, а в синхронных методах встречается вызов асинхронного кода с .GetResult()
. А ещё веселее, когда подобные преобразования случаются несколько раз при вызове одной функции.
С одной стороны, это хорошо с точки зрения обратной совместимости. Но с другой, теряется смысл в CancellationToken.
То есть в CancellationTokenSource будут храниться все объекты, которые зарегистрировали свой собственный метод отмены/завершения, до окончания работы с этим CancellationTokenSource
Вот это поворот :)
очень интересно, как вы собираете метрики служб?
CancellationTokenSource и «утечки памяти»