المهل الزمنية والإلغاء والمعترضات
طبّقوا مهلات باستخدام المهل الزمنية، وانشروا 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
مرّر دائمًا رمز إلغاء الخادم عبر كل سلسلة استدعاءات غير متزامنة. إذا تجاهلته، فستستمر الاستدعاءات الملغاة في استهلاك الموارد دون حاجة.
// 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: المفهوم
المعترضات هي النظير في gRPC للبرمجيات الوسيطة في ASP.NET Core؛ إذ تُنفَّذ قبل استدعاءات 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على الخادم ومرّره إلى جميع الاستدعاءات غير المتزامنة - تعالج المعترضات الاهتمامات المشتركة، مثل التسجيل والمصادقة وتعيين الأخطاء، دون إثقال كود الخدمة
- معترضات الخادم: تجاوز طرق معالج Unary/Stream واستدعِ
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 يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- أساسيات gRPC وProtobuf
- استدعاءات RPC الأحادية والبث من الخادم
- البث من العميل والبث ثنائي الاتجاه
- المهل الزمنية والإلغاء والمعترضات