Pregunta

Estoy construyendo una plantilla T4 que ayudará a las personas a construir colas de Azure de manera consistente y simple. Me gustaría hacer este autodocumento y algo consistente.

  1. Primero hice el nombre de la cola en la parte superior del archivo, los nombres de la cola deben estar en minúsculas, así que agregué tolower ()

  2. El constructor público utiliza las API StorageClient integradas para acceder a las cadenas de conexión. He visto muchos enfoques diferentes a esto, y me gustaría obtener algo que funcione en casi todas las situaciones. (¿Ideas? Comparta)

  3. No me gustan las solicitudes HTTP innecesarias para verificar si las colas se han creado, por lo que hice es un static bool . No implementé un bloqueo (monitorObject) ya que no creo que sea necesario.

  4. En lugar de usar una cadena y analizarla con comas (como la mayoría de la documentación de MSDN), estoy serializando el objeto al pasarlo a la cola.

  5. Para una mayor optimización, estoy usando un Método de extensión de serializador JSON para aprovechar al máximo el límite de 8k. No estoy seguro de si una codificación ayudará a optimizar esto más

  6. Se agregó la lógica de reintento para manejar ciertos escenarios que ocurren con la cola (ver el enlace HTML)

  7. P: ¿Es el nombre apropiado de "DataContext" para esta clase?

  8. P: ¿Es una mala práctica nombrar el nombre de la acción de la cola de la manera que he hecho?

¿Qué cambios adicionales crees que debería hacer?

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);
        }
¿Fue útil?

Solución

P: ¿El "DataContext" es el nombre apropiado para esta clase?

En .NET tenemos muchas clases de DataContext, por lo que en el sentido de que desea que los nombres comuniquen adecuadamente lo que hace la clase, creo que XyzQueueDataContext Comunica correctamente lo que hace la clase, aunque no puede consultarlo.

Si quieres quedarte más alineado con Idiomas de patrones aceptados, Patrones de arquitectura de aplicaciones empresariales llama a cualquier clase que encapsule el acceso a un sistema externo para un Puerta, mientras que más específicamente es posible que desee usar el término Canal en el idioma de Patrones de integración empresarial - eso es lo que yo haría.

P: ¿Es una mala práctica nombrar el nombre de la acción de la cola de la manera que he hecho?

Bueno, ciertamente parejas apretadas El nombre de la cola a la clase. Esto significa que si luego decides que quieres desacoplarlos, no puedes.

Como comentario general, creo que esta clase podría beneficiarse de tratar de hacer menos. Usar la cola no es lo mismo que administrarlo, por lo que en lugar de tener todo ese código de gestión de la cola allí, sugeriría inyección una CloudQueue en la instancia. Así es como implemento mi constructor de Azurechannel:

private readonly CloudQueue queue;

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

    this.queue = queue;
}

Esto mejor se adapta al Principio de responsabilidad única Y ahora puede implementar la gestión de colas en su propia clase (reutilizable).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top