3

そのため、私はMSMQの設定を任されており、メールサーバーがダウンした場合(これは頻繁に発生するようです)、メッセージはキューに入れられ、戻ってきたときに配信されます。そうは言っても、過去24時間で学んだことを除いて、これについてはあまり知らないと言わざるを得ませんが、正しいアプローチを取るには十分知っていると思いますが、混乱があるため、コミュニティの誰かに聞いてみたかったのです。私の同僚の間で、私たちのWCFアプリケーションにいくつかの既存のセットアップを与えました。

現在、エンドポイントのプロトコルとしてmsmqを使用するサービスがいくつかあります。エンドポイントは次のようになります

<endpoint address="net.msmq://localhost/private/Publisher"
behaviorConfiguration="BatchBehaviour" 
binding="netMsmqBinding"
bindingConfiguration="MSMQNoSecurity"
contract="HumanArc.Compass.Shared.Publisher.Interfaces.Service.IPublisherSubscriber"
name="PublishSubscriber"/>

もちろん、これによりクライアントはサービスコールを発信できます。何らかの理由でサービスが起動していなかった場合は、サービスが復旧したときにコールが処理されるようになります。次のようなサービス方法があれば、うまくいかないと思います。

try
{
    smtp.Send(mail);
    return true;
}
catch (System.Net.Mail.SmtpFailedRecipientException ex)
{
     throw new Exception("User Credentials for sending the Email are Invalid",ex);
}
catch (System.Net.Mail.SmtpException smtpEx)
{
   throw new Exception(string.Format("Application encountered a problem send a mail message to {0} ", smtpHostName),smtpEx);
}

WCFは再試行してメッセージを再度送信することはありませんが、この仮定については正しいですか?

上記のsmtp.send()の呼び出しの代わりに、次のようなものが必要だと思います。(http://www.bowu.org/it/microsoft/net/email-asp-net-mvc-msmq-2.htmlから)

  string queuePath = @".\private$\WebsiteEmails";
  MessageQueue msgQ;
  //if this queue doesn't exist we will create it
  if(!MessageQueue.Exists(queuePath))
       MessageQueue.Create(queuePath);
  msgQ = new MessageQueue(queuePath);
  msgQ.Formatter = new BinaryMessageFormatter();
  msgQ.Send(msg);

次に、サービスの起動のどこかで(まだどこにあるかわかりません)、SmtpClientオブジェクトで実際にsend()を呼び出すイベントハンドラーを設定します。このようなもの

 msgQ.ReceiveCompleted += new ReceiveCompletedEventHandler(msgQ_ReceiveCompleted)

まとめると、私の最初の質問はどちらが良いかということです。プロトコルとしてnet:msmqを使用するサービスを作成しますか、それとも単にメールメソッドを変更してメッセージをキューに入れ、そのハンドラーを設定しますか?次の質問、SmtpClient.Send()を呼び出すメソッドを変更することについての私の仮定が正しい場合、プログラムのどこにReceiveCompletedを接続する必要がありますか?Out WCFサービスはWindowsサービスでホストされます。つまり、実際にはServiceBase.Run(servicesToRun)が呼び出されます。そこに配線できる場所はありますか?私のWCFの経験は、IISでホストされるサービスがはるかに単純であるため、100%確信が持てません。

ありがとう-これは長い質問だと思いますが、私はそれを調査しようとしていて、たくさんの情報があり、ある方法と別の方法で物事を行うことの利点の明確な説明を見つけることができないようです。

4

1 に答える 1

6

msmq を使用してダウンストリームの依存関係 (この場合は smtp サーバー) の可用性に対処するアプローチは有効です。ただし、msmq について最初に理解しておくべきことがいくつかあります。

msmq でキューを作成すると、既定では非トランザクションになります。このモードでは、キューは必要な種類の保証された配信セマンティックを提供しません。そのため、キューをトランザクションとして作成します。

次に、処理するメッセージを受信したときに、サービス操作がトランザクションに参加することを WCF に伝えることができます。これを行うには、サービス操作の実装で動作を定義します。

[OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
public void SendEmail(Something mail)
{
    ....
    smtp.Send(mail);
}

TransactionScopeRequiredサービス操作が、送信者から受信者にメッセージを送信するために使用される同じトランザクションに参加する必要があることを WCF に通知します。TransactionAutoComplete操作が正常に完了したら、サービス メソッドがトランザクションをコミットする必要があることを示します。したがって、上記のクエリへの回答として、サービス操作で障害発生すると、トランザクションがロールバックされます。

この時点で何が起こるかは、サービス バインディングの構成によって異なります。

<netMsmqBinding>
  <binding name="netMsmqBinding_IMyServiceInterface" 
           exactlyOnce="true" 
           maxRetryCycles="3" 
           retryCycleDelay="00:01:00" 
           receiveErrorHandling="Move"> <-- this defines behavior after failure
    ...
  </binding>
</netMsmqBinding> 

なんらかの理由でトランザクションがコミットされていない場合 (たとえば、未処理の例外が発生した場合)、WCF はメッセージをキューにロールバックし、1 分間に 1 回、最大 3 回 (および で定義) 処理を再試行しmaxRetryCyclesますretryCycleDelay

この時間が経過してもメッセージの処理が失敗する場合、receiveErrorHandling属性は WCF に次に何をすべきかを伝えます (上記のバインディングは、メッセージがシステム ポイズン メッセージ キューに移動されることを指定します)。

注:exactlyOnceトランザクションが必要であること、各メッセージが送信された順序で 1 回だけ配信されることを WCF に伝えます。

したがって、元のアプローチは実際には正しく、必要な動作を実装するにはサービスを正しく構成する必要があります。

于 2012-11-29T21:02:20.083 に答える