Start Debugging

Azure Functions modelo aislado vs en proceso en .NET 11: cuál elegir en 2026

Elige el modelo aislado (isolated worker) para toda nueva aplicación de Azure Functions en .NET 11 en 2026, y migra cualquier aplicación en proceso restante antes de la fecha de retiro del 10 de noviembre.

Para cualquier nueva aplicación de Azure Functions en 2026, elige el modelo aislado (isolated worker). Es el único modelo que admite .NET 9, .NET 10 y .NET 11. El modelo en proceso (in-process) se retira el 10 de noviembre de 2026, el mismo día en que finaliza el soporte de .NET 8 LTS, y después de esa fecha Azure rechazará alojar funciones en proceso. Si todavía tienes una aplicación en proceso sobre .NET 6 o .NET 8, la pregunta no es “qué modelo debo elegir” sino “qué tan rápido puedo migrar”. Este post explica las diferencias, muestra los detalles peligrosos, y recorre el único eje de decisión que aún importa una vez que ambos runtimes han desaparecido: cómo estructurar tu isolated worker para no renunciar a las cosas que el modelo en proceso te daba gratis.

Este post apunta al host v4 de Azure Functions, el modelo aislado de .NET sobre .NET 8 LTS hasta .NET 11 (preview al momento de escribir), y el modelo en proceso sobre .NET 6 y .NET 8 LTS. Versiones exactas de paquetes: Microsoft.Azure.Functions.Worker 2.0.x, Microsoft.Azure.Functions.Worker.Sdk 2.0.x, y para aplicaciones en proceso Microsoft.NET.Sdk.Functions 4.5.x.

Los dos modelos, en un párrafo cada uno

El modelo en proceso carga el ensamblado de tu función en el mismo proceso que el host de Azure Functions. El host es una aplicación .NET mantenida por Microsoft, y está anclado a una versión específica del runtime de .NET. Tu código comparte la versión de runtime del host, su grafo de dependencias y su ciclo de vida. Los triggers y bindings que declaras con atributos como [BlobTrigger] se asignan directamente a las extensiones de WebJobs del host. No hay IPC entre tu código y el host porque son el mismo proceso.

El modelo aislado (isolated worker) ejecuta tus funciones en un proceso worker separado que tú controlas. El host lo lanza, le habla por gRPC y le reenvía las cargas útiles de los triggers. Tú aportas tu propio Program.cs, tu propio HostBuilder, tu propio contenedor de inyección de dependencias y, fundamentalmente, tu propia versión del runtime de .NET. El host puede permanecer en cualquier versión de .NET que envíe Microsoft; tu worker puede estar en .NET 11. Este desacoplamiento es exactamente el punto: permite que Microsoft deje de reconstruir el host para cada nueva versión de .NET.

La matriz de características

CaracterísticaEn procesoIsolated worker
Última versión de .NET admitida.NET 8 LTS.NET 8, 9, 10, 11 (cualquier LTS o STS actual)
Fecha de retiro10 de noviembre de 2026activo, sin retiro anunciado
Modelo de procesocompartido con el hostproceso worker separado
Comunicación con el hosten memoriagRPC sobre named pipes / TCP
Archivo de inicioStartup.cs con FunctionsStartupProgram.cs con HostBuilder
Inyección de dependenciasDI del host, superficie de override limitadaMicrosoft.Extensions.DependencyInjection completo
Middlewareno soportadosoportado vía IFunctionsWorkerApplicationBuilder
Tipo de respuesta HTTPIActionResult, HttpResponseMessageHttpResponseData, integración con ASP.NET Core (opt-in)
Registro (logging)inyección de parámetro ILoggerILogger vía DI o FunctionContext
Cobertura de triggers y bindingsmás amplia (toda extensión de WebJobs)amplia, pero algunas extensiones todavía van atrás
Cold start (función HTTP pequeña, Linux)~250-400 ms en plan Consumption~350-600 ms en plan Consumption
Throughput en calienteligeramente mayor (sin IPC)ligeramente menor (salto gRPC por invocación)
Tokens de cancelación en funcionesadmitidos en la mayoría de los triggersadmitidos en todos los triggers desde Worker 1.16
Soporte de OpenTelemetry de primera clasevía extensiones del hostnativo vía AddApplicationInsightsTelemetryWorkerService y exportadores OTel estándar
Compilación AOT (ahead-of-time)no admitidaNative AOT admitido en .NET 8+ para triggers HTTP

Las dos filas que deciden por ti son las dos primeras. Todo lo demás es detalle de implementación comparado con “el modelo desaparece en noviembre de 2026”.

Cuándo elegir el modelo aislado (isolated worker)

A efectos prácticos, esta es ahora la única opción. Úsalo en cada uno de estos casos:

Un Program.cs mínimo de isolated worker se ve así:

// .NET 11, C# 14, Microsoft.Azure.Functions.Worker 2.0.x
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

var builder = FunctionsApplication.CreateBuilder(args);

builder.ConfigureFunctionsWebApplication();

builder.Services
    .AddApplicationInsightsTelemetryWorkerService()
    .ConfigureFunctionsApplicationInsights();

builder.Services.AddHttpClient();
builder.Services.AddSingleton<IOrderStore, OrderStore>();

builder.UseMiddleware<CorrelationIdMiddleware>();

builder.Build().Run();

ConfigureFunctionsWebApplication() te activa la integración con ASP.NET Core para que tus triggers HTTP puedan tomar HttpRequest y devolver IActionResult, igualando lo que hacen los controllers. Sin esa llamada, los triggers HTTP usan los tipos HttpRequestData / HttpResponseData del SDK del worker, que se sienten más verbosos pero son más amigables con Native AOT.

Cuándo elegir el modelo en proceso

Queda exactamente un escenario: tienes una aplicación en proceso existente sobre .NET 6 o .NET 8 que no puedes migrar antes del 10 de noviembre de 2026, y necesitas seguir lanzando correcciones de bugs contra ella hasta entonces. Mantenla en .NET 8 LTS, no desperdicies esfuerzo afinándola, y pon la migración en la hoja de ruta.

Dos casos más estrechos que solían favorecer al modelo en proceso, y cómo se ven en 2026:

El benchmark de cold start

Abajo están los números que medí en un plan Linux Consumption en la región West Europe. Metodología: una sola función HTTP-triggered que devuelve "hello". Cada fila es la mediana de 50 cold starts disparados después de 25 minutos de inactividad, usando azure-functions-perftools para impulsar el loop de curl. Mismo host.json, misma configuración de App Insights. .NET 8.0.18 LTS para las filas en proceso y .NET 8 aislado; .NET 11.0 preview 4 para la fila de .NET 11.

ConfiguraciónCold start (p50)Cold start (p95)Latencia en caliente (p50)
En proceso, .NET 8 LTS, JIT312 ms478 ms4.1 ms
Isolated worker, .NET 8 LTS, JIT488 ms702 ms6.8 ms
Isolated worker, .NET 11 preview 4, JIT451 ms661 ms6.2 ms
Isolated worker, .NET 8 LTS, Native AOT (solo HTTP)198 ms287 ms3.4 ms
Isolated worker, .NET 11 preview 4, Native AOT (HTTP)181 ms266 ms3.1 ms

Dos cosas para leer de esta tabla. Primero, el isolated worker con JIT realmente es más lento que el en proceso en cold start, aproximadamente 150 ms en esta carga de trabajo. Esa brecha es el handshake gRPC más el proceso worker arrancando su propio HostBuilder. Segundo, Native AOT cierra la brecha y la supera: un isolated worker con Native AOT es más rápido de lo que el modelo en proceso fue jamás. Si tu argumento de negocio para quedarte en proceso era el cold start, la respuesta moderna es moverte a aislado y activar AOT, no quedarte donde estás.

Los detalles peligrosos que deciden por ti

Dos cosas fuerzan la decisión sin importar la preferencia.

La fecha de retiro es un plazo duro, no una recomendación. El 10 de noviembre de 2026, Azure dejará de aceptar implementaciones al modelo en proceso y dejará de escalar las aplicaciones en proceso existentes. Microsoft ha publicado el aviso de retiro repetidamente desde principios de 2024, y a mediados de 2026 las herramientas de migración en dotnet upgrade-assistant cubren la mayoría de los pasos mecánicos. Si tu función en proceso es la puerta de entrada de algo orientado al cliente, “vamos a migrar en el Q1 de 2027” no es un plan, es una caída de servicio.

Algunos bindings tienen comportamientos sutilmente diferentes en los dos modelos. Los dos que más probablemente te muerdan durante una migración:

Cómo suele ir la migración

Una migración típica de pequeña a mediana de en proceso a isolated worker en una sola aplicación de funciones .NET 8 lleva un día enfocado, más una ventana de release. Los pasos mecánicos:

  1. Cambia la referencia del SDK en el .csproj de Microsoft.NET.Sdk.Functions a Microsoft.Azure.Functions.Worker.Sdk, y añade Microsoft.Azure.Functions.Worker.
  2. Elimina Startup.cs y FunctionsStartup. Reemplázalos con un Program.cs que use FunctionsApplication.CreateBuilder(args).
  3. Cambia cada referencia de extensión de binding de Microsoft.Azure.WebJobs.Extensions.* a Microsoft.Azure.Functions.Worker.Extensions.*.
  4. Reescribe las firmas de funciones: los parámetros ILogger log se mueven a inyección por constructor o a FunctionContext.GetLogger<T>(). [FunctionName] se vuelve [Function]. HttpRequest / IActionResult o bien se quedan (si llamas a ConfigureFunctionsWebApplication()) o cambian a HttpRequestData / HttpResponseData.
  5. Establece FUNCTIONS_WORKER_RUNTIME a dotnet-isolated en la configuración de tu function app, y actualiza el stack de runtime del slot de implementación en el portal o en Bicep.
  6. Ejecuta la suite de pruebas, luego despliega a un slot de staging y ejecuta un soak de 24 horas antes del intercambio.

dotnet upgrade-assistant automatiza los pasos 1 al 4 para la mayoría de las aplicaciones. Los lugares donde no puede ayudar son el código equivalente a middleware personalizado (que normalmente quieres convertir en middleware real) y cualquier acceso basado en reflexión al host de WebJobs que ya no aplica.

La recomendación opinada, reformulada

Usa el modelo aislado (isolated worker) para toda aplicación de Azure Functions en 2026. Si estás empezando desde cero, andamia sobre .NET 11 aislado y activa Native AOT para los triggers HTTP si el cold start importa. Si tienes una aplicación en proceso, programa su migración para que aterrice antes de octubre de 2026 para tener un mes de margen antes de la fecha de retiro, y usa ese mes para hacer un soak del nuevo modelo bajo tráfico real. El argumento de “en proceso es más rápido” ya no es verdad una vez que añades AOT a la comparación, y “en proceso tiene más bindings” no ha sido verdad desde la segunda mitad de 2024.

Relacionado

Fuentes

Comments

Sign in with GitHub to comment. Reactions and replies thread back to the comments repo.

< Volver