Является ли это хорошим/предпочтительным шаблоном для построения очереди Azure для шаблона T4?

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

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

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

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

person halfbit    schedule 23.01.2011    source источник
comment
Я немного запутался - при чем здесь Т4?   -  person GarethJ    schedule 23.01.2011
comment
@Garethj Я намерен использовать ответ на этот вопрос для создания шаблона T4. Люди, заинтересованные в T4, могут заинтересоваться решением для своих целей.   -  person halfbit    schedule 18.02.2011


Ответы (1)


Q: Является ли имя "DataContext" подходящим для этого класса?

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

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

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

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

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

private readonly CloudQueue queue;

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

    this.queue = queue;
}

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

person Mark Seemann    schedule 23.01.2011
comment
Спасибо! Я полагаю, что мои классы для Blob тоже должны называться «канал»? Кроме того, как насчет таблицы Azure? Должен ли это быть xyzDataContext, поскольку я могу выставить IQueryable? - person halfbit; 22.02.2011
comment
Хотел бы услышать ваше мнение о DRY и структуре проекта на это и связанные с ним вопросы - person halfbit; 24.02.2011
comment
Этот вопрос — довольно хороший пример того, почему не следует реализовывать логику приложения в контроллерах. Единственной обязанностью контроллера должна быть обработка входящих запросов и создание веб-результатов (обычно HTML). Это должно быть сделано путем делегирования независимой от фреймворка библиотеке: часто модели предметной области. - person Mark Seemann; 24.02.2011