Крайние сроки, отмена и перехватчики
Применяйте тайм-ауты с помощью крайних сроков, передавайте CancellationToken и добавляйте сквозную функциональность через перехватчики gRPC.
«Крайние сроки, отмена и перехватчики» — бесплатный урок C# Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.
Надёжность в gRPC: крайние сроки и отмена
Рабочие службы gRPC должны учитывать два критически важных аспекта надёжности: крайние сроки (как долго клиент будет ждать) и отмену (прекращение работы раньше времени). Вместе они предотвращают исчерпание ресурсов и каскадные сбои.
Установка крайнего срока для вызова
Крайний срок — это абсолютный момент времени, к которому вызов должен завершиться. Установите его с помощью CallOptions. Если срок превышен, сервер получает отмену, а клиент — StatusCode.DeadlineExceeded.
var deadline = DateTime.UtcNow.AddSeconds(5);
var reply = await client.GetOrderAsync(
new GetOrderRequest { Id = 42 },
deadline: deadline);
// Or via CallOptions:
var options = new CallOptions(deadline: deadline);
var reply2 = await client.GetOrderAsync(
new GetOrderRequest { Id = 42 }, options);Обработка DeadlineExceeded на клиенте
Перехватите RpcException и проверьте код состояния, чтобы отличить истечение крайнего срока от других ошибок.
try
{
var reply = await client.GetOrderAsync(
new GetOrderRequest { Id = 42 },
deadline: DateTime.UtcNow.AddSeconds(3));
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.DeadlineExceeded)
{
Console.WriteLine("Call timed out");
}
catch (RpcException ex)
{
Console.WriteLine($"gRPC error: {ex.Status.Detail}");
}Соблюдение крайних сроков на сервере
Серверу следует проверять context.CancellationToken во время длительной работы. Когда крайний срок истекает, этот токен отменяется автоматически.
public override async Task<ReportResponse> GenerateReport(
ReportRequest request,
ServerCallContext context)
{
var ct = context.CancellationToken;
// Pass ct to every async call — work stops when deadline hits
var data = await _db.FetchLargeDatasetAsync(request.Filters, ct);
var report = await _reportEngine.BuildAsync(data, ct);
ct.ThrowIfCancellationRequested(); // explicit check before CPU work
return MapToResponse(report);
}Распространение CancellationToken
Всегда передавайте токен отмены сервера через всю цепочку async-вызовов. Если проигнорировать его, отменённые вызовы продолжат без необходимости расходовать ресурсы.
// GOOD: token flows through the call chain
await _db.Products.AsNoTracking()
.Where(p => p.IsActive)
.ToListAsync(context.CancellationToken); // cancels if client disconnects
// BAD: ignores cancellation
await _db.Products.ToListAsync(); // keeps running after deadlineПерехватчики gRPC: понятие
Перехватчики — это эквивалент промежуточного ПО ASP.NET Core в gRPC: они выполняются до и после RPC-вызовов и могут проверять или изменять запросы, ответы и исключения. Они идеально подходят для ведения журналов, аутентификации и логики повторных попыток.
Создание перехватчика на стороне сервера
Унаследуйтесь от Interceptor и переопределите нужный тип метода. Вызовите continuation, чтобы продолжить выполнение и передать управление фактическому обработчику.
using Grpc.Core.Interceptors;
public class LoggingInterceptor : Interceptor
{
private readonly ILogger<LoggingInterceptor> _logger;
public LoggingInterceptor(ILogger<LoggingInterceptor> l) => _logger = l;
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
_logger.LogInformation("gRPC call: {Method}", context.Method);
var sw = System.Diagnostics.Stopwatch.StartNew();
var response = await continuation(request, context);
_logger.LogInformation("Completed in {Ms}ms", sw.ElapsedMilliseconds);
return response;
}
}Регистрация перехватчиков сервера
Зарегистрируйте перехватчики глобально (для всех служб) или для отдельной службы в Program.cs. Контейнер DI разрешает зависимости конструктора.
// Globally for all gRPC services:
builder.Services.AddGrpc(opt =>
opt.Interceptors.Add<LoggingInterceptor>());
// Or per service:
builder.Services.AddGrpc();
builder.Services.AddSingleton<LoggingInterceptor>();
app.MapGrpcService<OrderService>()
.AddInterceptor<LoggingInterceptor>();Перехватчики на стороне клиента
Перехватчики клиента оборачивают исходящие вызовы — они полезны для добавления заголовков аутентификации, логики повторных попыток или идентификаторов корреляции без изменения каждого места вызова.
public class AuthInterceptor : Interceptor
{
private readonly ITokenProvider _tokens;
public AuthInterceptor(ITokenProvider t) => _tokens = t;
public override AsyncUnaryCall<TResponse> AsyncUnaryCall<TRequest, TResponse>(
TRequest request,
ClientInterceptorContext<TRequest, TResponse> context,
AsyncUnaryCallContinuation<TRequest, TResponse> continuation)
{
var headers = context.Options.Headers ?? new Metadata();
headers.Add("authorization", $"Bearer {_tokens.GetToken()}");
var newContext = new ClientInterceptorContext<TRequest, TResponse>(
context.Method, context.Host,
context.Options.WithHeaders(headers));
return continuation(request, newContext);
}
}
// Attach to channel:
var invoker = channel.Intercept(new AuthInterceptor(tokenProvider));
var client = new OrderService.OrderServiceClient(invoker);Перехватчик исключений
Перехватчик исключений на стороне сервера преобразует необработанные исключения в RpcExceptions, предотвращая утечку внутренних сведений клиентам.
public class ExceptionInterceptor : Interceptor
{
public override async Task<TResponse> UnaryServerHandler<TRequest, TResponse>(
TRequest request,
ServerCallContext context,
UnaryServerMethod<TRequest, TResponse> continuation)
{
try
{
return await continuation(request, context);
}
catch (NotFoundException ex)
{
throw new RpcException(new Status(StatusCode.NotFound, ex.Message));
}
catch (Exception ex)
{
throw new RpcException(new Status(StatusCode.Internal, "Internal error"));
}
}
}Быстрая проверка
Что происходит, когда вызов gRPC превышает свой крайний срок?
Итоги: крайние сроки, отмена и перехватчики
Основные выводы:
- Всегда устанавливайте крайние сроки для вызовов клиента, чтобы предотвратить неограниченное ожидание
- Проверяйте
context.CancellationTokenна сервере и передавайте его во все async-вызовы - Перехватчики обрабатывают сквозные задачи (ведение журналов, аутентификацию и сопоставление ошибок), не загромождая код службы
- Перехватчики сервера: переопределяйте методы обработчиков унарных вызовов и потоков и вызывайте
continuation - Перехватчики клиента: подключайте их к цепочке вызовов канала
Часто задаваемые вопросы
Урок «Крайние сроки, отмена и перехватчики» бесплатный?
Да — полный текст урока «Крайние сроки, отмена и перехватчики» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.
Чему я научусь в уроке «Крайние сроки, отмена и перехватчики»?
Применяйте тайм-ауты с помощью крайних сроков, передавайте CancellationToken и добавляйте сквозную функциональность через перехватчики gRPC. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать C# Academy?
Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.
Сколько времени занимает урок «Крайние сроки, отмена и перехватчики»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке C# Academy?
Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Основы gRPC и Protobuf
- Унарные вызовы и потоковая передача от сервера
- Потоковая передача от клиента и двунаправленная передача
- Крайние сроки, отмена и перехватчики