对于T4模板,这是Azure Queue构造的一个好/可取的模式吗?

时间:2011-01-23 01:50:56

标签: c# azure azure-storage t4 azure-storage-queues

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

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

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

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

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

  5. 为了进一步优化,我使用JSON serializer extension method来充分利用8k限制。不确定编码是否有助于优化此

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

  7. 问:“DataContext”是否适用于此类名称?

  8. 问:以我的方式命名队列操作名称是不是很糟糕?

  9. 您认为我应该做出哪些其他更改?

    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);
            }
    

1 个答案:

答案 0 :(得分:2)

  

问:“DataContext”是否适合此类?

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

如果您希望与已接受的模式语言更加一致,Patterns of Enterprise Application Architecture会调用任何封装对网关的外部系统访问权限的类,而更多具体而言,您可能希望使用Enterprise Integration Patterns语言中的频道一词 - 这就是我要做的。

  

问:以我的方式命名队列操作名称是不是很糟糕吗?

嗯,肯定将队列名称与班级紧密联系。这意味着,如果您以后决定要将它们分离,则不能。

作为一般性评论,我认为这个课程可能会因为努力做得更少而受益。使用队列与管理队列不同,因此我不建议将所有队列管理代码放在那里,而是建议将CloudQueue注入到实例中。以下是我实现AzureChannel构造函数的方法:

private readonly CloudQueue queue;

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

    this.queue = queue;
}

这更适合Single Responsibility Principle,您现在可以在自己的(可重用的)类中实现队列管理。