Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
El control de versiones en Durable Functions es esencial porque las funciones se agregan, quitan y cambian inevitablemente durante la vigencia de una aplicación. Durable Functions le permite encadenar funciones de maneras que no eran posibles anteriormente y este encadenamiento afecta a cómo se controla el control de versiones.
Este artículo le ayudará a realizar las siguientes acciones:
- Identifique si el cambio de código es un cambio importante.
- Elija la estrategia de mitigación adecuada para implementar de forma segura.
Comparación rápida de estrategias
Si ya sabe que el cambio es problemático, use esta tabla para elegir una estrategia de mitigación.
| Estrategia | Más adecuado para | Detalles |
|---|---|---|
| Control de versiones de orquestación (recomendado) | La mayoría de las aplicaciones con cambios importantes. La característica en tiempo de ejecución integrada funciona con cualquier back-end de almacenamiento. | Ir a la sección |
| Implementaciones en paralelo | Aplicaciones que no pueden usar el control de versiones de orquestación o que necesitan aislamiento completo a través de centros de tareas independientes o cuentas de almacenamiento. | Ir a la sección |
| Detener todas las instancias en ejecución | La creación de prototipos y el desarrollo local donde se pierden orquestaciones en curso es aceptable. | Ir a la sección |
Sugerencia
Si busca la funcionalidad integrada de control de versiones de orquestación que activa el aislamiento automático de versiones en el entorno de ejecución, consulte Control de versiones de orquestación.
Importante
Antes de implementarlo, compruebe si el cambio es un cambio importante:
- ¿Ha cambiado el nombre, el tipo de entrada o el tipo de salida de una función de actividad o entidad?
- ¿Ha agregado, quitado o reordenado las llamadas a actividades, sub orquestaciones, temporizadores o eventos externos en el código de orquestador?
- ¿Cambió el nombre o quitó una función a la que podrían llamar las orquestaciones en curso?
Si respondió sí a cualquiera de estas opciones, use una de las estrategias de mitigación siguientes para evitar errores en la ejecución de orquestaciones.
Tipos de cambios importantes
Existen varios ejemplos de cambios disruptivos. En este artículo se describen los tipos más comunes. El tema principal detrás de todos ellos es que los cambios en el código de función afectan tanto a las orquestaciones de funciones nuevas como existentes.
Cambios en la firma de función de actividad o entidad
Un cambio de firma hace referencia a un cambio en el nombre, la entrada o la salida de una función. Si realiza este tipo de cambio en una función de actividad o entidad, podría interrumpir cualquier función orquestadora que dependa de ella. Este comportamiento es especialmente cierto para los lenguajes con seguridad de tipos. Si actualiza la función de orquestador para dar cabida a este cambio, se podrían interrumpir las instancias en curso existentes.
Por ejemplo, considera la siguiente función de orquestador.
[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
bool result = await context.CallActivityAsync<bool>("Foo");
await context.CallActivityAsync("Bar", result);
}
Esta función toma el resultado de Foo y la pasa a Bar. Supongamos que necesita cambiar el valor devuelto de Foo de un valor booleano a una cadena para admitir una variedad más amplia de valores de resultado. El resultado tiene este aspecto:
[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
string result = await context.CallActivityAsync<string>("Foo");
await context.CallActivityAsync("Bar", result);
}
Este cambio funciona bien en todas las nuevas instancias de la función de orquestador, pero interrumpe todas las instancias en curso. Por ejemplo, considere el caso en el que una instancia de orquestación llama a una función denominada Foo, obtiene un valor booleano y, a continuación, puntos de control. Si el cambio de firma se implementa en este momento, se producirá un error en la instancia con los puntos de control inmediatamente después de que se reanude y reproduzca la llamada a Foo. Este error se produce porque el resultado de la tabla de historial es un valor booleano, pero el nuevo código intenta deserializarlo en un valor string, lo que da lugar a un comportamiento inesperado o incluso a una excepción en tiempo de ejecución para lenguajes seguros de tipos.
Este ejemplo es una de las muchas maneras en que un cambio de firma de función puede interrumpir las instancias existentes. En general, si un orquestador necesita cambiar la forma en que llama a una función, es probable que el cambio sea problemático.
Cambios en la lógica de Orchestrator
La otra clase de problemas de versionado se deben a cambiar el código de la función del orquestador de una manera que modifica la ruta de ejecución para las instancias en ejecución.
Considere la función de orquestación siguiente:
[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
bool result = await context.CallActivityAsync<bool>("Foo");
await context.CallActivityAsync("Bar", result);
}
Ahora suponga que desea agregar una nueva llamada de función entre las dos llamadas de función existentes.
[FunctionName("FooBar")]
public static Task Run([OrchestrationTrigger] IDurableOrchestrationContext context)
{
bool result = await context.CallActivityAsync<bool>("Foo");
if (result)
{
await context.CallActivityAsync("SendNotification");
}
await context.CallActivityAsync("Bar", result);
}
Este cambio agrega una nueva llamada de función a SendNotification entre Foo y Bar. No existe ningún cambio de firma. El problema surge cuando una instancia existente se reanuda tras la llamada a Bar. Durante la reproducción, si la llamada original a Foo devolvió true, entonces el orquestador realiza nuevas llamadas a SendNotification, que no se encuentra en su historial de ejecución. El tiempo de ejecución detecta esta incoherencia y genera un error de orquestación no determinista porque encontró una llamada a SendNotification cuando esperaba ver una llamada a Bar. El mismo tipo de problema puede producirse al agregar llamadas API a otras operaciones duraderas, como crear temporizadores duraderos, esperar eventos externos o llamar a sub orchestraciones.
Estrategias de mitigación
Advertencia
La implementación de cambios disruptivos sin una estrategia de mitigación (el enfoque "no hacer nada") puede hacer que las orquestaciones produzcan errores de orquestación no determinista, queden atrapadas indefinidamente en un estado Running, o desencadenen errores de ejecución de bajo nivel, que degradan el rendimiento. Use siempre una de las estrategias siguientes al implementar cambios importantes.
Versión de orquestación (recomendado)
A diferencia de las otras estrategias de esta sección, el control de versiones de orquestación es una característica integrada en el entorno de ejecución que usa el aislamiento automático de versiones. No es necesario administrar implementaciones independientes, centros de tareas ni cuentas de almacenamiento. En su lugar, el propio tiempo de ejecución realiza un seguimiento de la información de versión y garantiza que las instancias de orquestación sean procesadas por trabajadores compatibles.
Con control de versiones de orquestación:
- Cada instancia de orquestación recibe una versión que se le asocia de manera permanente en el momento de su creación.
- Las funciones del orquestador pueden examinar su versión y ejecutar las correspondientes ramas, manteniendo tanto las rutas de código antiguas como las nuevas en el mismo código base.
- Los trabajadores que ejecutan versiones más recientes de la función del orquestador pueden continuar ejecutando instancias de orquestación creadas por versiones anteriores.
- El tiempo de ejecución impide que los trabajadores que ejecutan versiones anteriores de la función de orquestador ejecuten orquestaciones de versiones más recientes.
Este enfoque requiere una configuración mínima (una cadena de versión y una estrategia de coincidencia opcional) y es compatible con cualquier proveedor de almacenamiento. Es la estrategia recomendada para las aplicaciones que necesitan aceptar cambios importantes a la vez que mantienen implementaciones con 100 % de disponibilidad.
Para ver las instrucciones detalladas sobre configuración e implementación, consulte Control de versiones de orquestación.
Detener todas las instancias en curso
Otra opción es detener todas las instancias en curso. Si usa el proveedor predeterminado de Azure Storage para Durable Functions, la detención de todas las instancias se puede realizar borrando el contenido de las colas internas control-queue y workitem-queue. Como alternativa, detenga la aplicación de funciones, elimine estas colas y reinicie la aplicación. Las colas se vuelven a crear automáticamente una vez que se reinicia la aplicación. Las instancias de orquestación anteriores pueden permanecer en el estado "En ejecución" indefinidamente, pero no desordenan los registros con mensajes de error ni causan ningún daño a la aplicación. Este enfoque es ideal para el desarrollo rápido de prototipos, incluido el desarrollo local.
Advertencia
Este enfoque requiere acceso directo a los recursos de almacenamiento subyacentes y no es adecuado para todos los proveedores de almacenamiento admitidos por Durable Functions.
Implementaciones en paralelo
La forma más a prueba de errores para asegurarse de que los cambios importantes se implementan de forma segura es implementarlos en paralelo con las versiones anteriores. Puede usar cualquiera de las técnicas siguientes:
- Cuenta de almacenamiento diferente: implemente todas las actualizaciones como una nueva aplicación de funciones con una cuenta de almacenamiento diferente. Esto aísla completamente el estado de la nueva versión de la versión anterior.
- Centro de tareas diferente: implemente una nueva copia de la aplicación de funciones con la misma cuenta de almacenamiento, pero con un nombre de centro de tareas actualizado. Este enfoque crea nuevos artefactos de almacenamiento para la nueva versión mientras la versión anterior sigue usando sus artefactos existentes.
Al realizar implementaciones en paralelo en Azure, puede usar ranuras de implementación para ejecutar ambas versiones simultáneamente, con solo una como ranura de producción activa. Cuando estés listo para implementar la nueva lógica de orquestación, cambia la nueva versión al entorno de producción.
Nota:
Esta guía usa términos específicos de Azure Storage, pero se aplica generalmente a todos los proveedores de almacenamiento admitidos Durable Functions.
Nota:
Los intercambios de ranuras de implementación funcionan mejor con desencadenadores HTTP y webhook. En el caso de desencadenadores que no son HTTP, como colas o Event Hubs, la definición del desencadenador debe derivar de una configuración de aplicación que se actualiza como parte de la operación de intercambio.