2017-08-11 2 views
1

Lors de l'utilisation de async/await, je suis concerné par l'élimination du client alors qu'il est en train de traiter un message. Considérez ce qui suit:Mise au rebut appropriée du client Azure Service Bus lorsqu'un message est en cours de traitement

  1. Initialiser un client de file d'attente queueClient et stocker une référence dans le cadre global de la classe

  2. client file d'attente gère un message et en appelle code d'application pour le manipuler, ce qui pourrait finir par faire une base de données asynchrone ou appeler une API distante. Considérons que l'application est un service Windows avec une méthode CloseAsync qui est signalée lorsque le service doit être arrêté. Dans cette méthode, j'appelle queueClient.CloseAsync()

  3. Le travail effectué à l'étape 2 se termine et passe à message.Complete(). À ce stade, je suppose que la file d'attente a été fermée et que le message serait traité comme un échec.

Quelle est la meilleure pratique pour veiller à ce que le client de la file d'attente ne gère pas les messages plus et attend de fermer jusqu'à ce que tous les messages en cours de traitement sont terminées?

Répondre

1

Vous pouvez annuler le travail de l'étape 2 en utilisant un CancellationToken et/ou attendre le code de traitement de message asynchrone à l'étape 4 avant d'attendre l'appel de queueClient.CloseAsync(). Je suppose que vous êtes familier avec Tasks and Cancellation.

tâche de traitement des messages Attendent

  1. Initialiser un client de file d'attente queueClient et stocker une référence dans le cadre global de la classe

  2. client file d'attente gère un message et appelle un code d'application pour le gérer, ce qui pourrait finir par faire un travail de base de données asynchrone ou appeler une API distante, par exemple public Task HandleMessageAsync() {..}. Stocker une référence à cette tâche dans la portée globale de la classe. Par exemple private Task messageHandleTask;

  3. Considérons l'application est un service Windows avec une méthode CloseAsync qui est signalée lorsque le service doit être arrêté. Dans cette méthode j'appelle d'abord await messageHandleTask puis await queueClient.CloseAsync()

  4. Nous vivons tous longtemps et heureusement.

Dans ce scénario, le service ne sera pas complètement arrêté jusqu'à ce que la gestion des messages soit terminée.

Annuler tâche de traitement des messages

  1. Initialiser un client de file d'attente queueClient et stocker une référence dans le cadre global de la classe

  2. client file d'attente gère un message et demande un code d'application pour le gérer, en passant par un CancellationToken, qui pourrait finir par faire un travail de base de données asynchrone ou appeler une API distante, par exemple public Task HandleMessageAsync(CancellationToken token) {..}. Stocker une référence à cette tâche dans la portée globale de la classe. Considérons que l'application est un service Windows avec une méthode CloseAsync qui est signalée lorsque le service doit être arrêté. Dans cette méthode j'appelle d'abord cancellationTokenSource.Cancel(), puis await messageHandleTask et enfin await queueClient.CloseAsync()

  3. Nous vivons tous longtemps et heureusement.

Dans ce scénario, dans le code de gestion des messages, juste avant l'appel à message.Complete(). vous vérifier pour toute annulation: token.ThrowIfCancellationRequested. Dans ce cas, lorsque le service est fermé, le message n'atteint jamais l'état terminé et sera traité plus tard. (Soyez conscient, je ne connais pas le code impliqué donc ce scénario pourrait être complexe si le travail est déjà en partie fait avant que l'annulation se produise) Assurez-vous de gérer OperationCanceledException.

Dans un scénario où plusieurs messages sont traités en même temps, vous pouvez utiliser await Task.WhenAll(..)

+1

Par ailleurs, si cette suites de réponse que vous, envoyez-moi un muffin, ils semblent délicieux ;-) –

+0

Merci pour la réponse détaillée. Pour être clair, je préfèrerais ne pas introduire la complexité de l'annulation des changements partiels sur lesquels l'application travaillait lors de la gestion d'un message, je préfère le laisser finir avant de permettre la fermeture du service, donc le premier exemple être le plus simple et ce que je fais actuellement est la bonne façon? J'avais supposé, puisque l'attente laisserait l'exécution du programme continuer alors qu'il attendait sur la base de données, qu'il permettrait à la méthode 'queueClient.CloseAsync' d'être appelée avant que la base de données renvoyé le contrôle à l'application. –

+1

Le premier exemple correspond le mieux à votre scénario, en effet. Si vous attendez la méthode qui communique d'abord avec de base de données, puis attendez l'appel à 'queueClient.CloseAsync()' alors vous pouvez être assuré que la première tâche est terminée avant l'appel pour fermer le client. –