gRPC Services

15 questions found

How do you handle authentication for gRPC calls, and how does it differ from typical REST API authentication patterns?

Advanced
gRPC supports the same underlying mechanisms as REST (JWT bearer tokens, mutual TLS/client certificates) but transmits credentials via gRPC metadata (analogous to HTTP headers) rather than traditional HTTP headers directly in application code -- ASP.NET Core's standard authentication/authorization middleware ([Authorize] attributes, JWT bearer validation) works identically for gRPC services since they run on the same underlying ASP.NET Core pipeline, while gRPC clients attach credentials via CallCredentials or metadata added to each call.
// Server: same [Authorize] attribute works identically for gRPC services
[Authorize]
public class SecureService : Secure.SecureBase {
    public override Task<Response> GetData(Request request, ServerCallContext context) { ... }
}

// Client: attaching a bearer token via call credentials
var credentials = CallCredentials.FromInterceptor((context, metadata) => {
    metadata.Add("Authorization", $"Bearer {token}");
    return Task.CompletedTask;
});
Real-world example A service mesh secures internal gRPC service-to-service communication using mutual TLS (mTLS) for transport-level authentication, while a client-facing gRPC gateway uses JWT bearer tokens validated through the same ASP.NET Core JWT middleware used by its REST endpoints.

Common follow-ups: How does mutual TLS (mTLS) work for gRPC service-to-service authentication?;Can the same [Authorize] policy be shared identically between REST and gRPC endpoints?

Authentication & Authorization (Identity JWT OAuth);Microservices & Distributed Architecture Patterns

How would you version a gRPC service's contract while maintaining backward compatibility with existing clients?

Intermediate
Protobuf inherently supports additive, backward-compatible evolution: adding new fields (with new numbers) to existing messages doesn't break old clients (which simply ignore unknown fields) or old servers (which see new fields as absent/default on requests from newer clients) -- for genuinely breaking changes (removing or fundamentally changing a field's meaning), the convention is defining an entirely new service or method (like GetOrderV2) or a new package/namespace, similar in spirit to REST's URL-based versioning but expressed through the protobuf package/service naming instead.
// Adding a field is safe -- old clients simply don't send/see it
message OrderRequest {
  int32 order_id = 1;
  string include_details = 2;  // NEW field, old clients omit it, defaults apply
}

// Breaking change: new service version entirely
service OrderServiceV2 {
  rpc GetOrder (GetOrderRequestV2) returns (OrderResponseV2);
}
Real-world example An internal platform evolves its OrderService contract by only ever adding new optional fields for two years, avoiding the need for a breaking V2 service entirely, since protobuf's additive-evolution model accommodated every required change without compatibility issues.

Common follow-ups: How does protobuf handle a field present in a newer message but absent in the client's older generated code?;When is a new service version truly unavoidable versus additive evolution being sufficient?

API Versioning;Microservices & Distributed Architecture Patterns

How do you configure deadlines and cancellation for gRPC calls, and how does this differ from typical HTTP request timeouts?

Advanced
gRPC clients specify a deadline (an absolute point in time by which the call must complete) rather than a simple duration-based timeout, and this deadline is automatically propagated through the entire call chain if a server-side method itself makes further downstream gRPC calls -- meaning if service A calls service B which calls service C, all with a shared deadline, C automatically knows how much time budget remains from the original caller's perspective, letting the whole call chain fail fast consistently rather than each hop having its own independent, potentially conflicting timeout.
var deadline = DateTime.UtcNow.AddSeconds(5);
var response = await client.GetOrderAsync(request, deadline: deadline);

// If GetOrder's server implementation calls ANOTHER gRPC service,
// the remaining deadline automatically propagates to that downstream call too,
// so the whole chain respects the original 5-second budget
Real-world example A deeply nested microservices call chain (gateway -> order service -> inventory service -> pricing service) automatically respects a single 5-second deadline set by the original client, with each hop able to check remaining time and fail fast rather than each service independently timing out at different, uncoordinated points.

Common follow-ups: How does deadline propagation work automatically across multiple hops?;What happens to in-flight work on the server when a deadline is exceeded mid-call?

Microservices & Distributed Architecture Patterns;Diagnostics & Performance

What is the purpose of the ServerCallContext parameter present in every gRPC server method, and what information does it expose?

Beginner
ServerCallContext gives access to call-level metadata and control within a gRPC method implementation: the incoming request metadata (headers), the CancellationToken tied to the call's deadline/cancellation, the peer's identity information, and the ability to write outgoing response headers/trailers -- serving a similar role to HttpContext in a typical ASP.NET Core controller action, but specific to the gRPC call lifecycle.
public override async Task<OrderResponse> GetOrder(GetOrderRequest request, ServerCallContext context) {
    var userId = context.GetHttpContext().User.FindFirst("sub")?.Value;
    context.CancellationToken.ThrowIfCancellationRequested();
    var order = await _repository.GetAsync(request.OrderId, context.CancellationToken);
    return MapToResponse(order);
}
Real-world example A gRPC service method passes context.CancellationToken through to every downstream async database call, ensuring that if the client cancels or the deadline expires, the entire chain of work is cooperatively cancelled rather than continuing pointlessly after the client has given up.

Common follow-ups: How do you access the underlying HttpContext from within a gRPC service method?;How does ServerCallContext's CancellationToken relate to the call's deadline?

gRPC Services;Concurrency (asyncio/threading/multiprocessing)

How does client-side load balancing work for gRPC when calling a service with multiple backend instances, without a dedicated load balancer?

Intermediate
Client-side load balancing configures the gRPC client's channel with a resolver (discovering available backend addresses, often via DNS or a service discovery system) and a load-balancing policy (like round_robin), letting the client itself distribute calls across multiple known backend instances directly over independent connections -- avoiding a single load balancer as a potential bottleneck or extra network hop, common in Kubernetes environments using headless services for direct pod-to-pod gRPC communication.
var channel = GrpcChannel.ForAddress("dns:///order-service.default.svc.cluster.local:5000", new GrpcChannelOptions {
    ServiceConfig = new ServiceConfig { LoadBalancingConfigs = { new RoundRobinConfig() } },
    Credentials = ChannelCredentials.Insecure
});
// Client resolves multiple pod IPs via DNS and round-robins calls across them directly
Real-world example A Kubernetes-deployed gRPC client uses a headless service (providing direct pod IP resolution via DNS) combined with client-side round-robin load balancing, distributing calls evenly across all order-service pod replicas without routing through an additional load-balancer hop.

Common follow-ups: What's the difference between client-side and proxy-based (sidecar) load balancing for gRPC?;How does DNS-based service resolution handle pods being added or removed dynamically?

Microservices & Distributed Architecture Patterns;gRPC Services

Showing 11–15 of 15