ASP.NET Core: Dịch vụ gRPC đáng tin cậy có thời hạn và hủy bỏ


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Trong bài viết này

  1. Thời hạn (Deadline)
  2. Hủy bỏ (Cancellation
  3. Tài nguyên bổ sung

Thời hạn và hủy bỏ là các tính năng được máy khách gRPC sử dụng để hủy bỏ các lời gọi đang diễn ra. Bài viết này thảo luận tại sao thời hạn và việc hủy bỏ lại quan trọng cũng như cách sử dụng chúng trong ứng dụng .NET gRPC.

Thời hạn (Deadline)

Thời hạn cho phép máy khách gRPC chỉ định thời gian chờ lời gọi hoàn tất. Khi quá thời hạn, lời gọi sẽ bị hủy. Đặt thời hạn rất quan trọng vì nó cung cấp giới hạn trên về thời lượng lời gọi có thể kéo dài. Nó ngăn các dịch vụ hoạt động sai chạy mãi và làm cạn kiệt tài nguyên máy chủ. Thời hạn là một công cụ hữu ích để xây dựng các ứng dụng đáng tin cậy và cần được định cấu hình.

Cấu hình thời hạn:

  • Thời hạn được định cấu hình bằng cách sử dụng CallOptions.Deadline khi thực hiện lời gọi.
  • Không có giá trị thời hạn mặc định. Lệnh gọi gRPC không bị giới hạn thời gian trừ khi có thời hạn cụ thể.
  • Thời hạn là thời gian UTC khi vượt quá thời hạn. Ví dụ: DateTime.UtcNow.AddSeconds(5) có thời hạn là 5 giây kể từ bây giờ.
  • Nếu thời gian trong quá khứ hoặc hiện tại được sử dụng thì lời gọi sẽ ngay lập tức vượt quá thời hạn.
  • Thời hạn được gửi cùng với lệnh gọi gRPC tới dịch vụ và được cả máy khách và dịch vụ theo dõi độc lập. Có thể lệnh gọi gRPC hoàn thành trên một máy, nhưng đến thời điểm phản hồi trả về máy khách thì đã quá thời hạn.

Nếu vượt quá thời hạn, máy khách và dịch vụ sẽ có hành vi khác nhau:

  • Máy khách ngay lập tức hủy bỏ yêu cầu HTTP cơ bản và đưa ra lỗi DeadlineExceeded. Ứng dụng khách có thể chọn bắt lỗi và hiển thị thông báo hết thời gian chờ cho người dùng.
  • Trên máy chủ, yêu cầu HTTP đang thực thi bị hủy bỏ và ServerCallContext.CancellationToken được nâng lên. Mặc dù yêu cầu HTTP bị hủy nhưng lệnh gọi gRPC vẫn tiếp tục chạy trên máy chủ cho đến khi phương thức hoàn tất. Điều quan trọng là mã thông báo hủy được chuyển đến các phương thức không đồng bộ để chúng bị hủy cùng với lời gọi. Ví dụ: truyền mã thông báo hủy tới các truy vấn cơ sở dữ liệu không đồng bộ và yêu cầu HTTP. Việc truyền mã thông báo hủy cho phép lời gọi bị hủy hoàn tất nhanh chóng trên máy chủ và giải phóng tài nguyên cho các lời gọi khác.

Định cấu hình CallOptions.Deadline để đặt thời hạn cho lời gọi gRPC:

var client = new Greet.GreeterClient(channel);

try
{
    var response = await client.SayHelloAsync(
        new HelloRequest { Name = "World" },
        deadline: DateTime.UtcNow.AddSeconds(5));
    
    // Greeting: Hello World
    Console.WriteLine("Greeting: " + response.Message);
}
catch (RpcException ex) when (ex.StatusCode == StatusCode.DeadlineExceeded)
{
    Console.WriteLine("Greeting timeout.");
}

Sử dụng ServerCallContext.CancellationTokentrong dịch vụ gRPC:

public override async Task<HelloReply> SayHello(HelloRequest request,
    ServerCallContext context)
{
    var user = await _databaseContext.GetUserAsync(request.Name,
        context.CancellationToken);

    return new HelloReply { Message = "Hello " + user.DisplayName };
}

Thời hạn và thử lại

Khi cuộc gọi gRPC được định cấu hình với việc xử lý lỗi thử lại và thời hạn, thời hạn sẽ theo dõi thời gian trong tất cả các lần thử lại cho cuộc gọi gRPC. Nếu vượt quá thời hạn, lệnh gọi gRPC sẽ ngay lập tức hủy bỏ yêu cầu HTTP cơ bản, bỏ qua mọi lần thử lại còn lại và đưa ra lỗi DeadlineExceeded.

Truyền bá thời hạn

Khi lệnh gọi gRPC được thực hiện từ dịch vụ gRPC đang thực thi, thời hạn sẽ được thông báo. Ví dụ:

  1. Ứng dụng khách gọi FrontendService.GetUser có thời hạn.
  2. FrontendService gọi UserService.GetUser. Thời hạn do máy khách chỉ định phải được chỉ định bằng lệnh gọi gRPC mới.
  3. UserService.GetUser nhận được thời hạn. Nó hết thời gian chính xác nếu vượt quá thời hạn của ứng dụng khách.

Ngữ cảnh lời gọi cung cấp thời hạn với ServerCallContext.Deadline:

public override async Task<UserResponse> GetUser(UserRequest request,
    ServerCallContext context)
{
    var client = new User.UserServiceClient(_channel);
    var response = await client.GetUserAsync(
        new UserRequest { Id = request.Id },
        deadline: context.Deadline);

    return response;
}

Thời hạn phổ biến thủ công có thể rất cồng kềnh. Thời hạn cần được thông qua cho mỗi lời gọi và rất dễ vô tình bỏ lỡ. Một giải pháp tự động có sẵn tại factory máy khách gRPC. Chỉ định EnableCallContextPropagation:

  • Tự động truyền bá thời hạn và mã thông báo hủy cho các lời gọi con.
  • Không truyền bá thời hạn nếu lời gọi con chỉ định thời hạn nhỏ hơn. Ví dụ: thời hạn phổ biến là 10 giây không được sử dụng nếu lời gọi con chỉ định thời hạn mới là 5 giây bằng cách sử dụng CallOptions.Deadline. Khi có nhiều thời hạn thì thời hạn nhỏ nhất sẽ được sử dụng.
  • Đây là một cách tuyệt vời để đảm bảo rằng các kịch bản gRPC lồng nhau, phức tạp luôn truyền đạt thời hạn và việc hủy bỏ.
services
    .AddGrpcClient<User.UserServiceClient>(o =>
    {
        o.Address = new Uri("https://localhost:5001");
    })
    .EnableCallContextPropagation();

Để biết thêm thông tin, hãy xem tích hợp factory máy khách gRPC trong .NET.

Hủy bỏ (Cancellation)

Việc hủy cho phép máy khách gRPC hủy các lời gọi dài không còn cần thiết nữa. Ví dụ: lệnh gọi gRPC truyền phát các bản cập nhật theo thời gian thực được bắt đầu khi người dùng truy cập một trang trên trang web. Luồng sẽ bị hủy khi người dùng điều hướng khỏi trang.

Lời gọi gRPC có thể bị hủy trong ứng dụng khách bằng cách truyền mã thông báo hủy bằng CallOptions.CancellationToken hoặc gọi Disposetrong trên lời gọi.

private AsyncServerStreamingCall<HelloReply> _call;

public void StartStream()
{
    _call = client.SayHellos(new HelloRequest { Name = "World" });

    // Read response in background task.
    _ = Task.Run(async () =>
    {
        await foreach (var response in _call.ResponseStream.ReadAllAsync())
        {
            Console.WriteLine("Greeting: " + response.Message);
        }
    });
}

public void StopStream()
{
    _call.Dispose();
}

Các dịch vụ gRPC có thể bị hủy nên:

  • Truyền ServerCallContext.CancellationToken sang các phương thức không đồng bộ. Việc hủy các phương thức không đồng bộ cho phép lời gọi trên máy chủ hoàn thành nhanh chóng.
  • Truyền mã thông báo hủy cho các lời gọi con. Việc truyền mã thông báo hủy đảm bảo rằng các lời gọi con bị hủy với cha của chúng. Factory máy khách gRPC và EnableCallContextPropagation() tự động truyền mã thông báo hủy.

Tài nguyên bổ sung

Nguồn: learn.microsoft.com
» Tiếp: Xử lý lỗi tạm thời bằng cách thử lại gRPC
« Trước: Tích hợp factory máy khách gRPC trong .NET
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!