0Pricing
C# Academy · บทเรียน

เส้นตาย การยกเลิก และตัวดักจับ

ใช้ timeout ด้วยเส้นตาย ส่งต่อ CancellationToken และเพิ่มข้อกังวลที่ใช้ร่วมกันผ่านตัวดักจับของ gRPC

เส้นตาย การยกเลิก และตัวดักจับ เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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 ทั้งหมด
  • ตัวดักจับจัดการข้อกังวลที่ใช้ร่วมกันหลายส่วน (การบันทึกเหตุการณ์ การยืนยันตัวตน และการแปลงข้อผิดพลาด) โดยไม่ทำให้โค้ดบริการรก
  • ตัวดักจับฝั่งเซิร์ฟเวอร์: เขียนทับเมธอดตัวจัดการแบบ Unary/Stream และเรียก continuation
  • ตัวดักจับฝั่งไคลเอ็นต์: แนบเข้ากับลำดับตัวเรียกของแชนเนล

คำถามที่พบบ่อย

บทเรียน “เส้นตาย การยกเลิก และตัวดักจับ” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “เส้นตาย การยกเลิก และตัวดักจับ” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “เส้นตาย การยกเลิก และตัวดักจับ”

ใช้ timeout ด้วยเส้นตาย ส่งต่อ CancellationToken และเพิ่มข้อกังวลที่ใช้ร่วมกันผ่านตัวดักจับของ gRPC คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “เส้นตาย การยกเลิก และตัวดักจับ” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม

ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. พื้นฐาน gRPC และ Protobuf
  2. RPC แบบเอกภาพและการสตรีมจากเซิร์ฟเวอร์
  3. การสตรีมจากไคลเอ็นต์และแบบสองทิศทาง
  4. เส้นตาย การยกเลิก และตัวดักจับ
← กลับไปที่ C# Academy