这是一个好/ preferable模式的Azure队列施工T4模板? [英] Is this a good/preferable pattern to Azure Queue construction for a T4 template?

查看:286
本文介绍了这是一个好/ preferable模式的Azure队列施工T4模板?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我建立一个T4模板,这将帮助人们建立Azure的队列一致和简单的方式。我想使这个自我记录,和有些是一致的。


  1. 首先,我在文件上做出的队列名称,队列名称必须为小写,所以我说ToLower将()


  2. 公共构造函数使用内置StorageClient的API来访问连接字符串。我见过很多不同的方法来此,并希望得到的东西,在几乎所有情况下工作。 (想法?做股)


  3. 我不喜欢不需要的HTTP请求,以检查是否已创建的队列,所以我做了一个静态布尔。我并没有实现一个锁(monitorObject),因为我不认为一个人是需要的。


  4. 而不是使用一个字符串,并用逗号解析它(像大多数MSDN文档)路过时到队列中,我序列化对象。


  5. 有关进一步的优化,我使用的是<一个href=\"http://stackoverflow.com/questions/4771582/optimized-json-serialiser-deserialiser-as-an-extension-method\">JSON串行扩展方法,以获得最大的8K限制。不知道编码将有助于优化这个更多的


  6. 添加重试逻辑来处理与队列出现某些情景(见HTML链接)


  7. 问:是DataContext的适合此类名


  8. 问:它是一个贫穷的做法,我做的方式来命名队列动作名称


你觉得其他更改我应该?

 公共类AgentQueueDataContext
{
    //队列名称必须始终使用小写
    //是这样命名一个常量,而不是一个,因为.ToLower不会编译...
    静态字符串AGENT_QUEUE_ACTION_NAME =AgentQueueActions.ToLower();  静态布尔QueuesWereCreated {搞定;组; }    DataModel.SecretDataSource secDataSource = NULL;    CloudStorageAccount cloudStorageAccount = NULL;
    CloudQueueClient cloudQueueClient = NULL;
    CloudQueue queueAgentQueueActions = NULL;    静态AgentQueueDataContext()
    {
        QueuesWereCreated = FALSE;
    }    公共AgentQueueDataContext():这个(假)
    {
    }
    公共AgentQueueDataContext(布尔CreateQueues)
    {
        //设置队列的这种模式是:
        // TTP://convective.word$p$pss.com/2009/11/15/queues-azure-storage-client-v1-0/
        //
        this.cloudStorageAccount = CloudStorageAccount.FromConfigurationSetting(DataConnectionString);
        this.cloudQueueClient = cloudStorageAccount.CreateCloudQueueClient();
        this.secD​​ataSource =新DataModel.SecretDataSource();        queueAgentQueueActions = cloudQueueClient.GetQueueReference(AGENT_QUEUE_ACTION_NAME);        如果(QueuesWereCreated == ||假CreateQueues)
        {
            queueAgentQueueActions.CreateIfNotExist();
            QueuesWereCreated = TRUE;
        }
    }  //这是将使用的ThreadStart催生方法
   公共无效CheckQueue()
    {
        而(真)
        {
            尝试
            {
                CloudQueueMessage味精= queueAgentQueueActions.GetMessage();                布尔DoRetryDelayLogic = FALSE;                如果(MSG!= NULL)
                {
                    //反序列化使用JSON(允许存储更多的数据)
                    AgentQueueEntry actionableMessage = msg.AsString.FromJSONString&LT; AgentQueueEntry&GT;();                    开关(actionableMessage.ActionType)
                    {
                        案例AgentQueueActionEnum.EnrollNew:
                            {
                                // 添加
                                打破;
                            }
                        案例AgentQueueActionEnum.LinkToSite:
                            {
                                //内代理本身链接                                //内的站点链接                                打破;
                            }
                        案例AgentQueueActionEnum.DisableKey:
                            {
                                在现场//禁用键                                //在AgentTable禁用键(更新修改时间)                                打破;
                            }
                        默认:
                            {
                                打破;
                            }
                    }                    //
                    //只删除消息,如果请求代理已经失踪
                    //至少10分钟
                    //
                    如果(DoRetryDelayLogic)
                    {
                        如果(msg.InsertionTime!= NULL)
                            如果(msg.InsertionTime&LT; D​​ateTime.UtcNow +新的时间跨度(0,10,10))
                                继续;                        // TODO:登录错误:AGENTID XXX没有在表中找到了XXX分钟。
                        //这是可能涉及的registratoin主机崩溃的结果。
                        //数据仍然是一致的。删除排队的消息。
                    }
                    //
                    //如果执行读完了这一点,那么我们要么完全处理,或
                    //有sufficent理由丢弃该消息。
                    //
                    尝试
                    {
                        queueAgentQueueActions.DeleteMessage(MSG);
                    }
                    赶上(StorageClientException前)
                    {
                        //截至2010年7月,这是检测这类异常的最好方法
                        //说明:TTP://blog.smarx.com/posts/deleting-windows-azure-queue-messages-handling-exceptions
                        如果(ex.ExtendedErrorInformation.Error code ==MessageNotFound)
                        {
                            //弹出收据必须是无效的
                            //忽略或记录(所以我们可以调整可见性超时)
                        }
                        其他
                        {
                            //不是我们期待的错误
                            扔;
                        }
                    }
                }
                其他
                {
                   //允许控制落到底部,睡眠定时器是...
                }
            }
            赶上(例外五)
            {
                //理由:螺纹不能失败。
                // TODO:登录此异常                //允许控制落到底部,睡眠定时器是...
                //理由:不这样做可能会导致在一个特定的腐败进入队列颠簸
            }            // TODO:Thread.sleep()方法是坏
            //更好的东西替换...
            Thread.sleep代码(9000);
        }


解决方案

  

问:是的DataContext此类适当的名称


在.NET中我们有很多的DataContext类的,所以在你想要的名称适当沟通类做什么,我觉得 XyzQueueDataContext 通讯正常是什么感觉类没有 - 虽然你不能从中查询

如果你想保持更一致为接受的模式语言 模式企业应用架构调用封装访问外部系统的任何一类的网关,而更具体地说,您可能需要使用术语的频道的语言企业集成模式的 - 这就是我会做


  

问:它是一个可怜的实践来命名队列动作名称的方式我已经做了


好吧,那肯定的紧耦合队列名称的类。这意味着,如果您稍后决定要分离的,你不能。

作为一般性评论,我认为这个类可能从试图做的少受益。使用队列不是一回事管理它,因此而不是让所有的队列管理code的存在,我建议的注射 CloudQueue到实例。以下是我实现我AzureChannel构造:

 私人只读CloudQueue队列;公共AzureChannel(CloudQueue队列)
{
    如果(队列== NULL)
    {
        抛出新的ArgumentNullException(排队);
    }    this.queue =队列中;
}

这更符合单一职责原则,现在您可以在自己的执行队列管理(可重复使用)类。

I'm building a T4 template that will help people construct Azure queues in a consistent and simple manner. I'd like to make this self-documenting, and somewhat consistent.

  1. First I made the queue name at the top of the file, the queue names have to be in lowercase so I added ToLower()

  2. The public constructor uses the built-in StorageClient API's to access the connection strings. I've seen many different approaches to this, and would like to get something that works in almost all situations. (ideas? do share)

  3. I dislike the unneeded HTTP requests to check if the queues have been created so I made is a static bool . I didn't implement a Lock(monitorObject) since I don't think one is needed.

  4. Instead of using a string and parsing it with commas (like most MSDN documentation) I'm serializing the object when passing it into the queue.

  5. For further optimization I'm using a JSON serializer extension method to get the most out of the 8k limit. Not sure if an encoding will help optimize this any more

  6. Added retry logic to handle certain scenarios that occur with the queue (see html link)

  7. Q: Is "DataContext" appropriate name for this class?

  8. Q: Is it a poor practice to name the Queue Action Name in the manner I have done?

What additional changes do you think I should make?

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

解决方案

Q: Is "DataContext" appropriate name for this class?

In .NET we have a lot of DataContext classes, so in the sense that you want names to appropriately communicate what the class does, I think XyzQueueDataContext properly communicates what the class does - although you can't query from it.

If you want to stay more aligned to accepted pattern languages, Patterns of Enterprise Application Architecture calls any class that encapsulates access to an external system for a Gateway, while more specifically you may want to use the term Channel in the language of Enterprise Integration Patterns - that's what I would do.

Q: Is it a poor practice to name the Queue Action Name in the manner I have done?

Well, it certainly tightly couples the queue name to the class. This means that if you later decide that you want to decouple those, you can't.

As a general comment I think this class might benefit from trying to do less. Using the queue is not the same thing as managing it, so instead of having all of that queue management code there, I'd suggest injecting a CloudQueue into the instance. Here's how I implement my AzureChannel constructor:

private readonly CloudQueue queue;

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

    this.queue = queue;
}

This better fits the Single Responsibility Principle and you can now implement queue management in its own (reusable) class.

这篇关于这是一个好/ preferable模式的Azure队列施工T4模板?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆