Перейти к содержимому

Context, Metadata & Deadlines

Это содержимое пока не доступно на вашем языке.

RpcContext is the metadata envelope that travels with every call. It stores headers, deadlines, cancellation tokens, trace identifiers, and arbitrary key/value pairs so that both caller and responder can collaborate without sprinkling optional parameters everywhere.

Headers

Typed access to key/value pairs that end up as HTTP/2 metadata headers.

Deadlines

Absolute or relative timeouts propagated across services.

Cancellation

Cooperative cancellation via RpcCancellationToken.

Traceability

Trace IDs, correlation IDs, and domain metadata for observability.

final ctx = RpcContextBuilder()
.withGeneratedTraceId()
.withHeader('x-user-id', user.id)
.withTimeout(const Duration(seconds: 3))
.build();

Every call automatically receives the context in handler signatures:

Future<User> getUser(GetUserRequest request, {RpcContext? context}) async {
final traceId = context?.traceId;
final locale = context?.getHeader('x-locale') ?? 'en';
if (context?.isCancelled ?? false) {
throw RpcCancelledException('Client aborted the request');
}
return userRepository.fetch(request.id, locale: locale, traceId: traceId);
}

Because RpcContext is immutable you can create derived copies whenever you need to add or override metadata.

final retryCtx = context
?.withAdditionalHeaders({'x-retry-count': '2'})
.withTimeout(const Duration(seconds: 1));
  • RpcContext.withTimeout or .withDeadline attach temporal limits. They are honoured on both sides: callers stop waiting and responders can short-circuit expensive work.
  • RpcCancellationToken provides cooperative cancellation. The caller creates a token, passes it into the context, and keeps a handle to token.cancel().
  • RpcDeadlineExceededException and RpcCancelledException make it explicit why a call was terminated early.
final token = RpcCancellationToken();
final ctx = RpcContextBuilder()
.withCancellation(token)
.withTimeout(const Duration(seconds: 2))
.build();
final future = calculator.callSomething(request, context: ctx);
// Cancel from the UI after 500ms
Future.delayed(const Duration(milliseconds: 500), () => token.cancel('User left page'));

When a workflow spans multiple domains you rarely want to re-create metadata from scratch. RpcContext.createChain generates a sequence of derived contexts with fresh request IDs while preserving headers and trace IDs:

final base = RpcContext.forBusinessOperation(
operationType: 'PlaceOrder',
userId: user.id,
sessionId: session.id,
);
final chain = RpcContext.createChain(
base,
steps: ['Inventory', 'Payment', 'Notifications'],
stepTimeout: const Duration(seconds: 5),
);
await inventoryCaller.reserve(itemId, context: chain['Inventory']);
await paymentCaller.charge(paymentId, context: chain['Payment']);
  • RpcContext.sanitize removes sensitive headers such as authorization and cookies before you log or persist the context.
  • RpcContextUtils.merge combines two contexts, letting the right-hand side take precedence for overlapping headers or deadlines.
  • Extensions like RpcContext.createChildWith make it trivial to fork contexts with a few overrides, ideal for fan-out operations.

RpcContext.extractDomainMetadata summarises business identifiers (user IDs, tenant IDs, operation names, trace IDs). You can feed it to structured logging or metrics without manually parsing headers each time.

By embracing RpcContext you create a consistent experience across transports and services: every RPC carries enough information to authenticate, trace, and control its execution without ad-hoc plumbing.