0Pricing
C# Academy · Урок

Крайние сроки, отмена и перехватчики

Применяйте тайм-ауты с помощью крайних сроков, передавайте 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 — локальная установка не требуется.

Все уроки этого курса

  1. Основы gRPC и Protobuf
  2. Унарные вызовы и потоковая передача от сервера
  3. Потоковая передача от клиента и двунаправленная передача
  4. Крайние сроки, отмена и перехватчики
← Назад к C# Academy