Это хороший / предпочтительный шаблон для построения очереди Azure для шаблона T4? - PullRequest
3 голосов
/ 23 января 2011

Я создаю шаблон T4, который поможет людям создавать очереди Azure единообразным и простым способом.Я хотел бы сделать это самодокументируемым и несколько непротиворечивым.

  1. Сначала я сделал имя очереди вверху файла, имена очереди должны быть в нижнем регистре, поэтому ядобавлено ToLower ()

  2. Публичный конструктор использует встроенные API StorageClient для доступа к строкам соединения.Я видел много разных подходов к этому, и хотел бы получить что-то, что работает почти во всех ситуациях.(идеи? делитесь)

  3. Мне не нравятся ненужные HTTP-запросы, чтобы проверить, были ли созданы очереди, поэтому я создал static bool.Я не реализовал блокировку (monitorObject), так как не думаю, что она нужна.

  4. Вместо использования строки и ее синтаксического анализа с запятыми (как в большинстве документов MSDN) я 'm сериализации объекта при передаче его в очередь.

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

1 Ответ

2 голосов
/ 23 января 2011

В: Является ли «DataContext» подходящим именем для этого класса?

В .NET у нас много классов DataContext, поэтому в том смысле, что вы хотите, чтобы имена надлежащим образом сообщали о том, что делает класс, я думаю, XyzQueueDataContext правильно сообщает о том, что делает класс - хотя вы не можете запрашивать у него .

Если вы хотите быть более согласованными с принятыми языками шаблонов , Шаблоны архитектуры приложений предприятия вызывает любой класс, который инкапсулирует доступ к внешней системе для Шлюза , а более конкретно вы можете использовать термин Канал на языке Шаблоны интеграции предприятия - это то, что я бы сделал.

В: Плохо ли называть имя действия очереди так, как я это сделал?

Ну, это, конечно, тесно связывает имя очереди с классом. Это означает, что если вы позже решите, что хотите отделить их, вы не сможете.

В качестве общего комментария я думаю, что этот класс мог бы выиграть от попыток делать меньше. Использование очереди - это не то же самое, что управление ею, поэтому вместо того, чтобы иметь весь этот код управления очередью, я бы предложил ввести CloudQueue в экземпляр. Вот как я реализую свой конструктор AzureChannel:

private readonly CloudQueue queue;

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

    this.queue = queue;
}

Это лучше соответствует принципу единой ответственности , и теперь вы можете реализовать управление очередью в своем собственном (повторно используемом) классе.

...