3

一貫性のあるシンプルな方法でAzureキューを構築するのに役立つT4テンプレートを作成しています。これを自己文書化して、ある程度一貫性のあるものにしたいと思います。

  1. 最初にファイルの先頭にキュー名を作成しました。キュー名は小文字にする必要があるため、ToLower()を追加しました。

  2. パブリックコンストラクターは、組み込みのStorageClientAPIを使用して接続文字列にアクセスします。私はこれに対する多くの異なるアプローチを見てきましたが、ほとんどすべての状況で機能するものを手に入れたいと思っています。(アイデア?共有します)

  3. キューが作成されているかどうかを確認するための不要なHTTPリクエストが嫌いなので、作成しましたstatic bool。Lock(monitorObject)は必要ないと思うので、実装しませんでした。

  4. 文字列を使用してコンマで解析する代わりに(ほとんどのMSDNドキュメントのように)、オブジェクトをキューに渡すときにオブジェクトをシリアル化します。

  5. さらに最適化するために、JSONシリアライザー拡張メソッドを使用して8kの制限を最大限に活用しています。エンコーディングがこれを最適化するのに役立つかどうかわからない

  6. キューで発生する特定のシナリオを処理するための再試行ロジックが追加されました(htmlリンクを参照)

  7. Q:「DataContext」はこのクラスの適切な名前ですか?

  8. Q:私が行った方法でキューアクション名に名前を付けるのは悪い習慣ですか?

私が行うべき追加の変更は何だと思いますか?

public class AgentQueueDataContext
{
    // Queue names must always be in lowercase
    // Is named like a const, but isn't one because .ToLower won't compile...
    static string AGENT_QUEUE_ACTION_NAME = "AgentQueueActions".ToLower();

  static bool QueuesWereCreated { get; set; }

    DataModel.SecretDataSource secDataSource = null;

    CloudStorageAccount cloudStorageAccount = null;
    CloudQueueClient cloudQueueClient = null;
    CloudQueue queueAgentQueueActions = null;

    static AgentQueueDataContext()
    {
        QueuesWereCreated = false;
    }

    public AgentQueueDataContext() : this(false)
    {
    }
    public AgentQueueDataContext(bool CreateQueues)
    {
        // This pattern of setting up queues is from:
        // ttp://convective.wordpress.com/2009/11/15/queues-azure-storage-client-v1-0/
        //
        this.cloudStorageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
        this.cloudQueueClient = cloudStorageAccount.CreateCloudQueueClient();
        this.secDataSource = new DataModel.SecretDataSource();

        queueAgentQueueActions = cloudQueueClient.GetQueueReference(AGENT_QUEUE_ACTION_NAME);

        if (QueuesWereCreated == false || CreateQueues)
        {
            queueAgentQueueActions.CreateIfNotExist();
            QueuesWereCreated = true;
        }
    }

  // This is the method that will be spawned using ThreadStart
   public void CheckQueue()
    {
        while (true)
        {
            try
            {
                CloudQueueMessage msg = queueAgentQueueActions.GetMessage();

                bool DoRetryDelayLogic = false;

                if (msg != null)
                {
                    // Deserialize using JSON (allows more data to be stored)
                    AgentQueueEntry actionableMessage = msg.AsString.FromJSONString<AgentQueueEntry>();

                    switch (actionableMessage.ActionType)
                    {
                        case AgentQueueActionEnum.EnrollNew:
                            {
                                // Add to 
                                break;
                            }
                        case AgentQueueActionEnum.LinkToSite:
                            {
                                // Link within Agent itself

                                // Link within Site

                                break;
                            }
                        case AgentQueueActionEnum.DisableKey:
                            {
                                // Disable key in site

                                // Disable key in AgentTable (update modification time)

                                break;
                            }
                        default:
                            {
                                break;
                            }
                    }

                    //
                    // Only delete the message if the requested agent has been missing for 
                    // at least 10 minutes
                    //
                    if (DoRetryDelayLogic)
                    {
                        if (msg.InsertionTime != null)
                            if (msg.InsertionTime < DateTime.UtcNow + new TimeSpan(0, 10, 10))
                                continue;

                        // ToDo: Log error: AgentID xxx has not been found in table for xxx minutes.   
                        //                  It is likely the result of a the registratoin host crashing.
                        //                  Data is still consistent.  Deleting queued message.
                    }


                    //
                    // If execution made it to this point, then we are either fully processed, or 
                    // there is sufficent reason to discard the message.
                    //
                    try
                    {
                        queueAgentQueueActions.DeleteMessage(msg);
                    }
                    catch (StorageClientException ex)
                    {
                        // As of July 2010, this is the best way to detect this class of exception
                        // Description: ttp://blog.smarx.com/posts/deleting-windows-azure-queue-messages-handling-exceptions
                        if (ex.ExtendedErrorInformation.ErrorCode == "MessageNotFound")
                        {
                            // pop receipt must be invalid
                            // ignore or log (so we can tune the visibility timeout)
                        }
                        else
                        {
                            // not the error we were expecting
                            throw;
                        }
                    }
                }
                else
                {
                   // allow control to fall to the bottom, where the sleep timer is...
                }
            }
            catch (Exception e)
            {
                // Justification: Thread must not fail.
                //Todo: Log this exception

                // allow control to fall to the bottom, where the sleep timer is...
                // Rationale: not doing so may cause queue thrashing on a specific corrupt entry
            }

            // todo: Thread.Sleep() is bad
            //       Replace with something better...
            Thread.Sleep(9000);
        }
4

1 に答える 1

2

Q:「DataContext」はこのクラスの適切な名前ですか?

XyzQueueDataContext.NETには多くのDataContextクラスがあるので、名前でクラスの機能を適切に伝達するという意味で、クラスからのクエリはできませんが、クラスの機能を適切に伝達すると思います。

受け入れられているパターン言語との整合性を維持したい場合、Patterns of Enterprise Application Architectureは、ゲートウェイの外部システムへのアクセスをカプセル化するクラスを呼び出しますが、より具体的には、EnterpriseIntegrationPatternsの言語でチャネルという用語を使用することをお勧めます-それが私がすることです。

Q:私が行った方法でキューアクション名に名前を付けるのは悪い習慣ですか?

まあ、それは確かにキュー名をクラスに緊密に結合します。これは、後でそれらを切り離したいと決めた場合、それができないことを意味します。

一般的なコメントとして、私はこのクラスがより少ないことを試みることから利益を得るかもしれないと思います。キューを使用することは、キューを管理することと同じではないため、キュー管理コードをすべてそこに置く代わりに、 CloudQueueをインスタンスに挿入することをお勧めします。AzureChannelコンストラクターを実装する方法は次のとおりです。

private readonly CloudQueue queue;

public AzureChannel(CloudQueue queue)
{
    if (queue == null)
    {
        throw new ArgumentNullException("queue");
    }

    this.queue = queue;
}

これは単一責任の原則によりよく適合し、独自の(再利用可能な)クラスでキュー管理を実装できるようになりました。

于 2011-01-23T08:36:58.423 に答える