Question

J'ai créé un service WCF et utilise la liaison netMsmqBinding.

Il s'agit d'un service simple qui transmet un Dto à ma méthode de service et n'attend pas de réponse. Le message est placé dans un MSMQ et, une fois ramassé, inséré dans une base de données.

Quelle est la meilleure méthode pour vous assurer qu'aucune donnée n'est perdue.

J'ai essayé les 2 méthodes suivantes:

  1. Lance une exception

    Ceci place le message dans une file d'attente de lettres mortes pour une lecture manuelle. Je peux le traiter lorsque mon poste de travail commence

  2. définissez receiveRetryCount = " 3 " sur la reliure

    Après 3 tentatives - ce qui se produit instantanément, cela semble laisser le message en file d'attente, mais il est imputable à mon service. Le redémarrage de mon service répète ce processus.

Idéalement, j'aimerais faire ce qui suit:

Essayez de traiter le message

  • Si cela échoue, attendez 5 minutes pour ce message et réessayez.
  • Si ce processus échoue 3 fois, déplacez le message dans une file d'attente de lettres mortes.
  • Le redémarrage du service repoussera tous les messages de la file d'attente de lettres mortes dans la file d'attente pour pouvoir être traités.

Puis-je y parvenir? Si c'est le cas, comment? Pouvez-vous m'indiquer de bons articles sur la meilleure façon d'utiliser la WCF et le MSMQ pour mes sceneria donnés.

Toute aide serait très appréciée. Merci!

Quelques informations supplémentaires

J'utilise MSMQ 3.0 sous Windows XP et Windows Server 2003. Malheureusement, je ne peux pas utiliser la prise en charge intégrée des messages toxiques ciblée sur MSMQ 4.0 et Vista / 2008.

Était-ce utile?

La solution

Il existe un exemple dans le SDK qui pourrait être utile dans votre cas. Fondamentalement, il associe à votre service une implémentation IErrorHandler qui interceptera l’erreur lorsque la WCF déclare que le message est "poison". (c’est-à-dire lorsque tous les essais configurés ont été épuisés). L’exemple c’est déplacer le message dans une autre file d’attente, puis redémarrer le ServiceHost associé au message (car il aura fait défaut lorsque le message de poison a été trouvé).

Ce n’est pas un très joli échantillon, mais cela peut être utile. Il existe cependant quelques limitations:

1- Si plusieurs services d'extrémité sont associés à votre service (c.-à-d. exposés au travers de plusieurs files d'attente), il est impossible de savoir dans quelle file d'attente le message poison est arrivé. Si vous ne disposez que d'une seule file d'attente, cela ne posera pas de problème . Je n'ai pas vu de solution officielle pour cela, mais j'ai expérimenté une alternative possible que j'ai documentée ici: http://winterdom.com/weblog/2008/05/27/NetMSMQAndPoisonMessages.aspx

2- Une fois que le message problématique est déplacé vers une autre file d'attente, il vous incombe de le remettre dans la file d'attente de traitement une fois le délai d'attente écoulé (ou d'attacher un nouveau service à cette file d'attente pour le gérer.) ).

Pour être honnête, dans les deux cas, vous consultez un "manuel". travailler ici que WCF ne couvre tout simplement pas.

J'ai récemment travaillé sur un projet différent pour lequel je dois contrôler explicitement le nombre de tentatives, et ma solution actuelle consistait à créer un ensemble de files d'attente avant nouvelle tentative et à déplacer manuellement les messages entre les nouvelles files d'attente et le traitement principal. file d'attente basée sur un ensemble de minuteries et certaines méthodes heuristiques, en utilisant simplement le truc System.Messaging brut pour gérer les files d'attente MSMQ. Cela semble fonctionner assez bien, bien qu'il y ait quelques pièges si vous allez de cette façon.

Autres conseils

Je pense qu'avec MSMQ (disponible uniquement sur Vista), vous pourrez peut-être faire comme ceci:

<bindings>
    <netMsmqBinding>
        <binding name="PosionMessageHandling"
             receiveRetryCount="3"
             retryCycleDelay="00:05:00"
             maxRetryCycles="3"
             receiveErrorHandling="Move" />
    </netMsmqBinding>
</bindings>

WCF réessayera immédiatement les temps ReceiveRetryCount après l'échec du premier appel. Après l'échec du lot, le message est déplacé à la file d'attente de nouvelles tentatives. Après un délai d'une minute RetryCycleDelay, le message a été déplacé de la file d'attente des nouvelles tentatives vers la file d'attente du noeud final et le lot a été soumis à une nouvelle tentative. Ce sera répété MaxRetryCycle time. Si tout cela échoue, le message est traité conformément à receiveErrorHandling qui peut être déplacé. (pour empoisonner la file d'attente), rejeter, supprimer ou faute

En passant, un bon texte sur la WCF et MSMQ est le chapitre 9 du livre Progammig WCF de Juval Lowy

Si vous utilisez SQL-Server, vous devez utiliser une transaction distribuée, MSMQ et SQL-Server la prenant en charge. Ce qui se passe, c’est que vous enveloppez votre base de données en écriture dans un bloc TransactionScope et n’appelez scope.Complete () que s’il y parvient. Si cela échoue, lorsque votre méthode WCF renverra le message, il sera replacé dans la file d'attente pour être à nouveau testé. Voici une version réduite du code que j'utilise:

    [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=true)]
    public void InsertRecord(RecordType record)
    {
        try
        {
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
            {
                SqlConnection InsertConnection = new SqlConnection(ConnectionString);
                InsertConnection.Open();

                // Insert statements go here

                InsertConnection.Close();

                // Vote to commit the transaction if there were no failures
                scope.Complete();
            }
        }
        catch (Exception ex)
        {
            logger.WarnException(string.Format("Distributed transaction failure for {0}", 
                Transaction.Current.TransactionInformation.DistributedIdentifier.ToString()),
                ex);
        }
     }

Je teste cela en mettant en file d'attente un nombre important mais connu d'enregistrements, laisse WCF démarrer beaucoup de threads pour en gérer plusieurs simultanément (atteint 16 threads - 16 messages de la file d'attente à la fois), puis tue le processus dans le dossier. milieu des opérations. Lorsque le programme est redémarré, les messages sont lus dans la file d'attente et traités à nouveau comme si rien ne s'était passé. À la fin du test, la base de données est cohérente et ne contient aucun enregistrement manquant.

Le gestionnaire de transactions distribuées a une présence ambiante et, lorsque vous créez une nouvelle instance de TransactionScope, il recherche automatiquement la transaction en cours dans l'étendue de l'appel de méthode - ce qui aurait déjà dû être créé par WCF lors de l'affichage du message. de la file d'attente et a appelé votre méthode.

Malheureusement, je suis bloqué sous Windows XP et Windows Server 2003, ce n'est donc pas une option pour moi. - (Je clarifierai cela dans ma question car j'ai trouvé cette solution après avoir posté et réalisé que je ne pouvais pas l'utiliser)

J'ai découvert qu'une solution consistait à configurer un gestionnaire personnalisé qui déplacerait mon message dans une autre file d'attente ou une autre file d'attente et redémarrerait mon service. Cela m'a semblé fou. Imaginez que mon serveur SQL était arrêté à quelle fréquence le service serait redémarré.

C’est pourquoi ce que j’ai fait est de laisser la ligne en défaut et de laisser des messages dans la file d’attente. J'enregistre également un message fatal à mon service de journalisation système indiquant que cela s'est produit. Une fois le problème résolu, je redémarre le service et tous les messages sont à nouveau traités.

J'ai réalisé que le re-traitement de ce message ou de tout autre échouera, alors pourquoi faut-il déplacer ce message et les autres vers une autre file d'attente? Je peux aussi bien arrêter mon service et le redémarrer lorsque tout fonctionne comme prévu.

aogan, vous aviez la solution idéale pour MSMQ 4.0, mais malheureusement pas pour moi

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top