3

我正在构建一个 T4 模板,它将帮助人们以一致且简单的方式构建 Azure 队列。我想让这个自我记录,并且有点一致。

  1. 首先我在文件顶部创建了队列名称,队列名称必须是小写的,所以我添加了 ToLower()

  2. 公共构造函数使用内置的 StorageClient API 来访问连接字符串。我已经看到了许多不同的方法,并且希望得到适用于几乎所有情况的东西。(想法?分享)

  3. 我不喜欢检查队列是否已创建的不需要的 HTTP 请求,所以我创建了一个static bool. 我没有实现 Lock(monitorObject) 因为我认为不需要。

  4. 我不是使用字符串并用逗号解析它(像大多数 MSDN 文档一样),而是在将对象传递到队列时对其进行序列化。

  5. 为了进一步优化,我使用JSON 序列化程序扩展方法来充分利用 8k 限制。不确定编码是否有助于优化这一点

  6. 添加了重试逻辑以处理队列中发生的某些情况(请参阅 html 链接)

  7. 问: “DataContext”这个类的名称合适吗?

  8. 问:以我所做的方式命名队列操作名称是一种不好的做法吗?

你认为我应该做哪些额外的改变?

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

问:“DataContext”这个类的名称合适吗?

在 .NET 中,我们有很多 DataContext 类,因此从某种意义上说,您希望名称能够恰当地传达类的功能,我认为XyzQueueDataContext可以正确传达类的功能——尽管您无法从中查询。

如果您想与公认的模式语言保持一致,企业应用程序架构模式调用任何封装对网关外部系统的访问的类,而更具体地说,您可能希望在企业集成模式的语言中使用术语通道-这就是我要做的。

问:以我所做的方式命名队列操作名称是一种不好的做法吗?

好吧,它肯定将队列名称与类紧密耦合。这意味着,如果您以后决定要将它们解耦,则不能。

作为一般性评论,我认为这门课可能会受益于尝试做的更少。使用队列与管理队列不同,因此我建议不要将所有队列管理代码都放在那里,而是建议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 回答