Centrales de tareas en Durable Functions (Azure Functions)

Una central de tareas en Durable Functions es una representación del estado actual de la aplicación en el almacenamiento, incluido todo el trabajo pendiente. Mientras se ejecuta una aplicación de funciones, el progreso de las funciones de orquestación, actividad y entidad se almacena continuamente en la central de tareas. Esto garantiza que la aplicación pueda reanudar el procesamiento donde se dejó, si es necesario reiniciarlo después de que se detenga o interrumpa temporalmente por algún motivo. Además, permite que la aplicación de funciones escale dinámicamente los trabajos de proceso.

Diagram showing concept of function app and task hub concept.

Conceptualmente, una central de tareas almacena la siguiente información:

  • Estados de instancia de todas las instancias de orquestación y entidad.
  • Los mensajes que se van a procesar, incluidos los siguientes:
    • Todos los mensajes de actividad que representan las actividades que están a la espera de ejecutarse.
    • Todos los mensajes de instancia que están a la espera de entregarse a instancias.

La diferencia entre los mensajes de actividad e instancia es que los mensajes de actividad no tienen estado y, por tanto, se pueden procesar en cualquier lugar, mientras que los mensajes de instancia deben entregarse a una instancia con estado determinada (orquestación o entidad), identificada por su identificador de instancia.

Internamente, cada proveedor de almacenamiento puede usar una organización diferente para representar mensajes y estados de instancia. Por ejemplo, el proveedor de Azure Storage almacena los mensajes en colas de Azure Storage, pero el proveedor de MSSQL los almacena en tablas relacionales. Estas diferencias no importan en cuanto al diseño de la aplicación, pero algunas de ellas pueden influir en las características de rendimiento. Las tratamos a continuación en la sección Representación en el almacenamiento.

Elementos de trabajo

Los mensajes de actividad y los mensajes de instancia de la central de tareas representan el trabajo que la aplicación de funciones necesita procesar. Mientras se ejecuta la aplicación de funciones, captura continuamente los elementos de trabajo de la central de tareas. Cada elemento de trabajo procesa uno o varios mensajes. Distinguimos entre dos tipos de elementos de trabajo:

  • Elementos de trabajo de actividad: ejecute una función de actividad para procesar un mensaje de actividad.
  • Elemento de trabajo de orquestador: ejecute una función de orquestador o entidad para procesar uno o varios mensajes de instancia.

Los trabajos pueden procesar varios elementos de trabajo al mismo tiempo, sujetos a los límites de simultaneidad por trabajo configurados.

Una vez que un trabajo completa un elemento de trabajo, confirma los efectos de nuevo en la central de tareas. Estos efectos varían según el tipo de función que se ejecutó:

  • Una función de actividad completada crea un mensaje de instancia que contiene el resultado, dirigido a la instancia de orquestador principal.
  • Una función de orquestador completada actualiza el estado y el historial de orquestación, y puede generar nuevos mensajes.
  • Una función de entidad completada actualiza el estado de la entidad y también puede crear nuevos mensajes de instancia.

Para las orquestaciones, cada elemento de trabajo representa un episodio de la ejecución de esa orquestación. Un episodio empieza cuando hay nuevos mensajes para que el orquestador procese. Ese mensaje puede indicar que la orquestación debe iniciarse, puede indicar que se ha completado una actividad, una llamada de entidad, un temporizador o una suborquestación, o bien puede representar un evento externo. El mensaje desencadena un elemento de trabajo que permite al orquestador procesar el resultado y continuar con el siguiente episodio. Ese episodio termina cuando se completa el orquestador o llega a un punto en el que debe esperar nuevos mensajes.

Ejemplo de ejecución

Considere una orquestación de distribución ramificada de entrada y salida que inicia dos actividades en paralelo y espera a que ambas se completen:

[FunctionName("Example")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
    Task t1 = context.CallActivityAsync<int>("MyActivity", 1);
    Task t2 = context.CallActivityAsync<int>("MyActivity", 2);
    await Task.WhenAll(t1, t2);
}

Una vez que un cliente inicia esta orquestación, la aplicación de funciones la procesa como una secuencia de elementos de trabajo. Cada elemento de trabajo completado actualiza el estado de la central de tareas cuando se confirma. Estos son los pasos necesarios:

  1. Un cliente solicita iniciar una nueva orquestación con el identificador de instancia "123". Una vez que el cliente completa esta solicitud, la central de tareas contiene un marcador de posición para el estado de orquestación y un mensaje de instancia:

    workitems-illustration-step-1

    La etiqueta ExecutionStarted es uno de muchos tipos de eventos de historial que identifican los distintos tipos de mensajes y eventos que participan en el historial de una orquestación.

  2. Un trabajo ejecuta un elemento de trabajo de orquestador para procesar el mensaje ExecutionStarted. Llama a la función de orquestador que comienza a ejecutar el código de orquestación. Este código programa dos actividades y, a continuación, deja de ejecutarse cuando está esperando los resultados. Una vez que el trabajo confirma este elemento de trabajo, la central de tareas contiene lo siguiente:

    workitems-illustration-step-2

    El estado en tiempo de ejecución ahora es Running, se agregaron dos nuevos mensajes TaskScheduled y el historial ahora contiene los cinco eventos OrchestratorStarted, ExecutionStarted, TaskScheduled, TaskScheduled y OrchestratorCompleted. Estos eventos representan el primer episodio de la ejecución de esta orquestación.

  3. Un trabajo ejecuta un elemento de trabajo de actividad para procesar uno de los mensajes TaskScheduled. Llama a la función de actividad con la entrada "2". Cuando se completa la función de actividad, crea un mensaje TaskCompleted que contiene el resultado. Una vez que el trabajo confirma este elemento de trabajo, la central de tareas contiene lo siguiente:

    workitems-illustration-step-3

  4. Un trabajo ejecuta un elemento de trabajo de orquestador para procesar el mensaje TaskCompleted. Si la orquestación todavía está almacenada en la memoria caché, solo puede reanudar la ejecución. De lo contrario, el trabajo primero reproduce el historial para recuperar el estado actual de la orquestación. A continuación, continúa la orquestación y entrega el resultado de la actividad. Después de recibir este resultado, la orquestación sigue esperando el resultado de la otra actividad, por lo que una vez más deja de ejecutarse. Una vez que el trabajo confirma este elemento de trabajo, la central de tareas contiene lo siguiente:

    workitems-illustration-step-4

    El historial de orquestaciones ahora contiene tres eventos más OrchestratorStarted, TaskCompleted y OrchestratorCompleted. Estos eventos representan el segundo episodio de la ejecución de esta orquestación.

  5. Un trabajo ejecuta un elemento de trabajo de actividad para procesar el resto del mensaje TaskScheduled. Llama a la función de actividad con la entrada "1". Una vez que el trabajo confirma este elemento de trabajo, la central de tareas contiene lo siguiente:

    workitems-illustration-step-5

  6. Un trabajo ejecuta otro elemento de trabajo de orquestador para procesar el mensaje TaskCompleted. Después de recibir este segundo resultado, se completa la orquestación. Una vez que el trabajo confirma este elemento de trabajo, la central de tareas contiene lo siguiente:

    workitems-illustration-step-6

    El estado en tiempo de ejecución ahora es Completed, y el historial de orquestación ahora contiene cuatro eventos más OrchestratorStarted, TaskCompleted, ExecutionCompleted y OrchestratorCompleted. Estos eventos representan el tercer y último episodio de la ejecución de esta orquestación.

El historial final de la ejecución de esta orquestación contiene los 12 eventos OrchestratorStarted, ExecutionStarted, TaskScheduled, TaskScheduled, OrchestratorCompleted, OrchestratorStarted, TaskCompleted, OrchestratorCompleted, OrchestratorStarted, TaskCompleted, ExecutionCompleted y OrchestratorCompleted.

Nota:

La programación que se muestra no es la única: hay muchas posibles programaciones ligeramente diferentes. Por ejemplo, si la segunda actividad se completa anteriormente, un solo elemento de trabajo puede procesar ambos mensajes de instancia TaskCompleted. En ese caso, el historial de ejecución es un poco más corto, ya que solo hay dos episodios y contiene los siguientes 10 eventos: OrchestratorStarted, ExecutionStarted, TaskScheduled, TaskScheduled, OrchestratorCompleted, OrchestratorStarted, TaskCompleted, TaskCompleted, ExecutionCompleted y OrchestratorCompleted.

Administración de la central de tareas

A continuación, echemos un vistazo más detenidamente a cómo se crean o eliminan las centrales de tareas, cómo usar las centrales de tareas correctamente al ejecutar varias aplicaciones de funciones y cómo se puede inspeccionar el contenido de las centrales de tareas.

Creación y eliminación

Una central de tareas vacía con todos los recursos necesarios se crea automáticamente en el almacenamiento cuando se inicia una aplicación de funciones por primera vez.

Si usa el proveedor de Azure Storage predeterminado, no se requiere ninguna configuración adicional. De lo contrario, siga las instrucciones para configurar proveedores de almacenamiento para asegurarse de que el proveedor de almacenamiento puede aprovisionar y acceder correctamente a los recursos de almacenamiento necesarios para la central de tareas.

Nota

La central de tareas no se elimina automáticamente al detener o eliminar la aplicación de funciones. Debe eliminar la central de tareas, su contenido o la cuenta de almacenamiento contenedora manualmente si ya no desea conservar esos datos.

Sugerencia

En un escenario de desarrollo, es posible que a menudo tenga que reiniciar desde un estado limpio. Para hacerlo rápidamente, puede cambiar el nombre configurado de la central de tareas. Esto forzará la creación de una central de tareas vacía al reiniciar la aplicación. Tenga en cuenta que los datos antiguos no se eliminan en este caso.

Varias aplicaciones de funciones

Si varias aplicaciones de funciones comparten una cuenta de almacenamiento, se debe configurar cada una de ellas con un nombre de central de tareas independiente. Este requisito también se aplica a los espacios de ensayo: cada espacio de ensayo se debe configurar con un nombre de central de tareas único. Una cuenta de almacenamiento única puede contener varias centrales de tareas. Esta restricción se suele aplicar también a otros proveedores de almacenamiento.

El siguiente diagrama muestra una central de tareas por cada aplicación de función en las cuentas de Azure Storage compartidas y dedicadas.

Diagram showing shared and dedicated storage accounts.

Nota:

La excepción a la regla de uso compartido dela central de tareas es si está configurando la aplicación para la recuperación ante desastres regional. Para más información, consulte el artículo sobre la recuperación ante desastres y la distribución geográfica.

Inspección de contenido

Hay varias maneras comunes de inspeccionar el contenido de una central de tareas:

  1. Dentro de una aplicación de funciones, el objeto cliente proporciona métodos para consultar el almacén de instancias. Para más información sobre qué tipos de consultas se admiten, consulte el artículo Administración de instancias.
  2. Del mismo modo, la API HTTP ofrece solicitudes REST para consultar el estado de las orquestaciones y las entidades. Consulte la referencia de la API HTTP para obtener más detalles.
  3. La herramienta Durable Functions Monitor puede inspeccionar las centrales de tareas y ofrece varias opciones para la representación visual.

Para algunos de los proveedores de almacenamiento, también es posible inspeccionar la central de tareas directamente desde el almacenamiento subyacente:

  • Si usa el proveedor de Azure Storage, los estados de instancia se almacenan en la tabla de instancias y en la tabla de historial que se pueden inspeccionar mediante herramientas como el Explorador de Azure Storage.
  • Si usa el proveedor de almacenamiento de MSSQL, se pueden usar consultas SQL y herramientas para inspeccionar el contenido de la central de tareas dentro de la base de datos.

Representación en el almacenamiento

Cada proveedor de almacenamiento usa una organización interna diferente para representar las centrales de tareas en el almacenamiento. Comprender esta organización, aunque no es necesario, puede resultar útil para solucionar problemas de una aplicación de funciones o al intentar garantizar objetivos de rendimiento, escalabilidad o costos. Por lo tanto, se explica brevemente, para cada proveedor de almacenamiento, cómo se organizan los datos en el almacenamiento. Para más información sobre las diversas opciones del proveedor de almacenamiento y cómo se comparan, consulte los proveedores de almacenamiento de Durable Functions.

Proveedor de Azure Storage

El proveedor de Azure Storage representa la central de tareas en el almacenamiento mediante los componentes siguientes:

  • Dos tablas de Azure almacenan los estados de la instancia.
  • Una cola de Azure almacena los mensajes de actividad.
  • Una o varias colas de Azure almacenan los mensajes de instancia. Cada una de estas denominadas colas de control representa una partición que se asigna a un subconjunto de todos los mensajes de instancia, en función del hash del identificador de instancia.
  • Algunos contenedores de blobs adicionales se usan para conceder blobs o mensajes grandes.

Por ejemplo, una central de tareas denominada xyz con PartitionCount = 4 contiene las colas y tablas siguientes:

Diagram showing Azure Storage provider storage storage organization for 4 control queues.

A continuación, describimos estos componentes y el rol que desempeñan con más detalle.

Para más información sobre cómo el proveedor de Azure Storage representa las centrales de tareas, consulte la documentación del proveedor de Azure Storage.

Proveedor de almacenamiento de Netherite

Netherite crea particiones de todo el estado de la central de tareas en un número especificado de particiones. En el almacenamiento, se usan los siguientes recursos:

  • Un contenedor de blobs de Azure Storage que contiene todos los blobs, agrupados por partición.
  • Una tabla de Azure que contiene métricas publicadas sobre las particiones.
  • Un espacio de nombres de Azure Event Hubs para entregar mensajes entre particiones.

Por ejemplo, una central de tareas denominada mytaskhub con PartitionCount = 32 se representa en el almacenamiento de la siguiente manera:

Diagram showing Netherite storage organization for 32 partitions.

Nota:

Todo el estado de la central de tareas se almacena dentro del contenedor de blobs x-storage. La tabla DurableTaskPartitions y el espacio de nombres de EventHubs contienen datos redundantes: si se pierde su contenido, se pueden recuperar automáticamente. Por lo tanto, no es necesario configurar el espacio de nombres de Azure Event Hubs para conservar los mensajes después de la hora de expiración predeterminada.

Netherite usa un mecanismo de aprovisionamiento de eventos, basado en un registro y puntos de comprobación, para representar el estado actual de una partición. Se usan blobs en bloques y blobs en páginas. No es posible leer este formato directamente desde el almacenamiento, por lo que la aplicación de funciones debe ejecutarse al consultar el almacén de instancias.

Para obtener más información sobre las centrales de tareas para el proveedor de almacenamiento de Netherite, consulte Información de la central de tareas para el proveedor de almacenamiento de Netherite.

Proveedor de almacenamiento de MSSQL

Todos los datos de la central de tareas se almacenan en una base de datos relacional única mediante varias tablas:

  • Las tablas dt.Instances y dt.History almacenan los estados de la instancia.
  • La tabla dt.NewEvents almacena los mensajes de instancia.
  • La tabla dt.NewTasks almacena los mensajes de actividad.

Diagram showing MSSQL storage organization.

Para permitir que varias centrales de tareas coexistan de forma independiente en la misma base de datos, cada tabla incluye una columna TaskHub como parte de su clave principal. A diferencia de los otros dos proveedores, el proveedor de MSSQL no tiene un concepto de particiones.

Para obtener más información sobre las centrales de tareas para el proveedor de almacenamiento de MSSQL, consulte Información de la central de tareas para el proveedor de almacenamiento de Microsoft SQL (MSSQL).

Nombres de las centrales de tareas

Las centrales de tareas se identifican mediante un nombre que debe ajustarse a estas reglas:

  • Solo contiene caracteres alfanuméricos.
  • Comienza con una letra.
  • Tiene una longitud mínima de 3 caracteres, con una longitud máxima de 45 caracteres.

El nombre de la central de tareas se declara en el archivo host.json, como se muestra en el ejemplo siguiente:

host.json (Functions 2.0)

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": "MyTaskHub"
    }
  }
}

host.json (Functions 1.x)

{
  "durableTask": {
    "hubName": "MyTaskHub"
  }
}

Las centrales de tareas también se pueden configurar mediante la configuración de la aplicación, tal como se muestra en el siguiente archivo de ejemplo host.json:

host.json (Functions 1.0)

{
  "durableTask": {
    "hubName": "%MyTaskHub%"
  }
}

host.json (Functions 2.0)

{
  "version": "2.0",
  "extensions": {
    "durableTask": {
      "hubName": "%MyTaskHub%"
    }
  }
}

El nombre de la central de tareas se establecerá en el valor de la configuración MyTaskHub de la aplicación. El siguiente valor de local.settings.json muestra cómo definir la configuración MyTaskHub como samplehubname:

{
  "IsEncrypted": false,
  "Values": {
    "MyTaskHub" : "samplehubname"
  }
}

Nota:

Al utilizar ranuras de implementación, se recomienda configurar el nombre de la central de tareas mediante la configuración de la aplicación. Si desea asegurarse de que una ranura determinada utilice siempre una central de tareas determinada, use la configuración de la aplicación "slot-sticky".

Además de host.json, los nombres de central de tareas también se pueden configurar en los metadatos de enlace de cliente de orquestación. Esta opción resulta útil si necesita acceder a orquestaciones o entidades que se encuentran en una aplicación de función aparte. En el siguiente código se muestra cómo escribir una función que usa el enlace del cliente de orquestación para trabajar con una central de tareas definida como configuración de la aplicación:

[FunctionName("HttpStart")]
public static async Task<HttpResponseMessage> Run(
    [HttpTrigger(AuthorizationLevel.Function, methods: "post", Route = "orchestrators/{functionName}")] HttpRequestMessage req,
    [DurableClient(TaskHub = "%MyTaskHub%")] IDurableOrchestrationClient starter,
    string functionName,
    ILogger log)
{
    // Function input comes from the request content.
    object eventData = await req.Content.ReadAsAsync<object>();
    string instanceId = await starter.StartNewAsync(functionName, eventData);

    log.LogInformation($"Started orchestration with ID = '{instanceId}'.");

    return starter.CreateCheckStatusResponse(req, instanceId);
}

Nota

El ejemplo anterior corresponde a Durable Functions 2.x. En el caso de Durable Functions 1.x, debe usar DurableOrchestrationContext en lugar de IDurableOrchestrationContext. Para obtener más información sobre las diferencias entre versiones, vea el artículo Versiones de Durable Functions.

Nota

La configuración de nombres de central de tareas en los metadatos de enlace de cliente solo es necesaria cuando se usa una aplicación de funciones para acceder a orquestaciones y entidades de otra aplicación de funciones. Si las funciones de cliente se definen en la misma aplicación de funciones que las orquestaciones y las entidades, debe evitar especificar nombres de central de tareas en los metadatos de enlace. De forma predeterminada, todos los enlaces de cliente obtienen sus metadatos de central de tareas de la configuración de host.jsconfiguración.

Los nombres de la central de tareas deben empezar por una letra y estar formados únicamente por letras y números. Si no se especifica, se usará un nombre de central de tareas predeterminado, tal y como se muestra en la tabla siguiente:

Versión de la extensión de Durable Nombre de central de tareas predeterminado
2.x Cuando se implementa en Azure, el nombre de la central de tareas se deriva del nombre de la aplicación de funciones. Cuando se ejecuta fuera de Azure, el nombre predeterminado de la central de tareas es TestHubName.
1.x El nombre predeterminado de la central de tareas para todos los entornos es DurableFunctionsHub.

Para obtener más información sobre las diferencias entre versiones de extensión, consulte el artículo Versiones de Durable Functions.

Nota

El nombre es lo que diferencia una central de tareas de otra cuando hay varias de ellas en una cuenta de almacenamiento compartido. Si tiene varias aplicaciones de función que comparten una cuenta de almacenamiento, deberá configurar explícitamente nombres diferentes para cada central de tareas en el archivo host.json. En caso contrario, las diversas aplicaciones de funciones competirán entre sí por los mensajes, lo cual podría provocar un comportamiento indefinido, como, por ejemplo, orquestaciones que se "atascan" inesperadamente en el estado Pending o Running.

Pasos siguientes