Services gRPC fiables avec échéances et annulation
Remarque
Ceci n’est pas la dernière version de cet article. Pour la version actuelle, consultez la version .NET 9 de cet article.
Avertissement
Cette version d’ASP.NET Core n’est plus prise en charge. Pour plus d’informations, consultez la Stratégie de prise en charge de .NET et .NET Core. Pour la version actuelle, consultez la version .NET 8 de cet article.
Important
Ces informations portent sur la préversion du produit, qui est susceptible d’être en grande partie modifié avant sa commercialisation. Microsoft n’offre aucune garantie, expresse ou implicite, concernant les informations fournies ici.
Pour la version actuelle, consultez la version .NET 9 de cet article.
Les délais et l’annulation sont des fonctionnalités utilisées par les clients gRPC pour abandonner les appels en cours. Cet article explique pourquoi les délais et l’annulation sont importants et comment les utiliser dans les applications gRPC .NET.
Échéances
Une échéance permet à un client gRPC de spécifier la durée d’attente d’un appel. Lorsqu’une échéance est dépassée, l’appel est annulé. La définition d’une échéance est importante, car elle fournit une limite supérieure à la durée d’exécution d’un appel. Il empêche les services au comportement problématique de s’exécuter indéfiniment et d’épuiser les ressources du serveur. Les délais sont un outil utile pour créer des applications fiables et doivent être configurés.
Configuration de l’échéance :
- Une échéance est configurée à l’aide de
CallOptions.Deadline
au moment où un appel est effectué. - Il n’existe aucune valeur d’échéance par défaut. Les appels gRPC ne sont pas limités dans le temps, sauf si une échéance est spécifiée.
- Une échéance est l’heure UTC du dépassement de l’échéance. Par exemple,
DateTime.UtcNow.AddSeconds(5)
est une échéance de 5 secondes à partir de maintenant. - Si une heure passée ou actuelle est utilisée, l’appel dépasse immédiatement l’échéance.
- L’échéance est envoyée avec l’appel gRPC au service et est suivie indépendamment par le client et le service. Il est possible qu’un appel gRPC se termine sur une machine, mais qu’au moment où la réponse est retournée au client, l’échéance a été dépassée.
Si une échéance est dépassée, le client et le service ont un comportement différent :
- Le client abandonne immédiatement la requête HTTP sous-jacente et génère une erreur
DeadlineExceeded
. L’application cliente peut choisir d’intercepter l’erreur et d’afficher un message d’expiration de délai à l’utilisateur. - Sur le serveur, la requête HTTP en cours d’exécution est abandonnée et ServerCallContext.CancellationToken est levé. Bien que la requête HTTP soit abandonnée, l’appel gRPC continue de s’exécuter sur le serveur jusqu’à la fin de la méthode. Il est important que le jeton d’annulation soit passé à des méthodes asynchrones afin qu’elles soient annulées avec l’appel. Par exemple, en passant un jeton d’annulation aux requêtes de base de données asynchrones et aux requêtes HTTP. Le passage d’un jeton d’annulation permet à l’appel annulé de se terminer rapidement sur le serveur et de libérer les ressources pour d’autres appels.
Configurez CallOptions.Deadline
pour définir une échéance pour un appel 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.");
}
Utilisation de ServerCallContext.CancellationToken
dans un service 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 };
}
Échéances et nouvelles tentatives
Lorsqu’un appel gRPC est configuré avec la gestion des erreurs de nouvelle tentative et une échéance, l’échéance suit le temps de toutes les nouvelles tentatives pour un appel gRPC. Si l’échéance est dépassée, un appel gRPC abandonne immédiatement la requête HTTP sous-jacente, ignore les nouvelles tentatives restantes et génère une erreur DeadlineExceeded
.
Propagation des échéances
Lorsqu’un appel gRPC est effectué à partir d’un service gRPC en cours d’exécution, l’échéance doit être propagée. Par exemple :
- L’application cliente appelle
FrontendService.GetUser
avec une échéance. FrontendService
appelleUserService.GetUser
. L’échéance spécifiée par le client doit être spécifiée avec le nouvel appel gRPC.UserService.GetUser
reçoit l’échéance. Il expire correctement si l’échéance de l’application cliente est dépassée.
Le contexte d’appel indique l’échéance avec 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;
}
La propagation manuelle des échéances peut être fastidieuse. L’échéance doit être passée à chaque appel, et il est facile de la manquer accidentellement. Une solution automatique est disponible avec la fabrique de clients gRPC. Spécification de EnableCallContextPropagation
:
- Propage automatiquement le jeton d’échéance et d’annulation aux appels enfants.
- Ne propage pas l’échéance si l’appel enfant spécifie une échéance plus courte. Par exemple, une échéance propagée de 10 secondes n’est pas utilisée si un appel enfant spécifie une nouvelle échéance de 5 secondes avec
CallOptions.Deadline
. Lorsque plusieurs échéances sont disponibles, la plus courte est utilisée. - C’est un excellent moyen de s’assurer que les scénarios gRPC complexes et imbriqués propagent toujours l’échéance et l’annulation.
services
.AddGrpcClient<User.UserServiceClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.EnableCallContextPropagation();
Pour plus d’informations, consultez Intégration de la fabrique de clients gRPC dans .NET.
Annulation
L’annulation permet à un client gRPC d’annuler les appels de longue durée qui ne sont plus nécessaires. Par exemple, un appel gRPC qui diffuse des mises à jour en temps réel est démarré lorsque l’utilisateur visite une page d’un site web. Le flux doit être annulé lorsque l’utilisateur quitte la page.
Un appel gRPC peut être annulé dans le client en passant un jeton d’annulation avec CallOptions.CancelToken ou en appelant Dispose
sur l’appel.
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();
}
Les services gRPC qui peuvent être annulés doivent :
- Passer
ServerCallContext.CancellationToken
aux méthodes asynchrones. L’annulation des méthodes asynchrones permet à l’appel sur le serveur de se terminer rapidement. - Propager le jeton d’annulation aux appels enfants. La propagation du jeton d’annulation garantit que les appels enfants sont annulés avec leur parent. La fabrique de clients gRPC et
EnableCallContextPropagation()
propagent automatiquement le jeton d’annulation.