Start Debugging

Azure Functions isolated worker vs in-process в .NET 11: что выбрать в 2026 году

Выбирайте модель isolated worker для любой новой Azure Functions-приложения на .NET 11 в 2026 году и мигрируйте оставшиеся in-process приложения до даты вывода из эксплуатации 10 ноября.

Для любого нового Azure Functions-приложения в 2026 году выбирайте модель isolated worker. Это единственная модель, которая поддерживает .NET 9, .NET 10 и .NET 11. Модель in-process выводится из эксплуатации 10 ноября 2026 года, в тот же день, когда заканчивается поддержка .NET 8 LTS, и после этой даты Azure откажется хостить in-process функции. Если у вас всё ещё есть in-process приложение на .NET 6 или .NET 8, вопрос не в том, “какую модель выбрать”, а в том, “как быстро можно мигрировать”. Этот пост объясняет различия, показывает подводные камни и проходит по единственной оси решения, которая всё ещё имеет значение, когда оба runtime исчезнут: как структурировать ваш isolated worker, чтобы не отказаться от того, что in-process модель раньше давала вам бесплатно.

Этот пост нацелен на Azure Functions host v4, модель .NET isolated worker на .NET 8 LTS до .NET 11 (preview на момент написания) и модель in-process на .NET 6 и .NET 8 LTS. Точные версии пакетов: Microsoft.Azure.Functions.Worker 2.0.x, Microsoft.Azure.Functions.Worker.Sdk 2.0.x, а для in-process приложений Microsoft.NET.Sdk.Functions 4.5.x.

Две модели, по одному абзацу на каждую

Модель in-process загружает сборку вашей функции в тот же процесс, что и host Azure Functions. Host — это .NET-приложение, поддерживаемое Microsoft, и оно привязано к конкретной версии среды выполнения .NET. Ваш код разделяет версию runtime host, его граф зависимостей и его жизненный цикл. Триггеры и привязки, которые вы объявляете с атрибутами вроде [BlobTrigger], отображаются непосредственно на расширения WebJobs host. Между вашим кодом и host нет IPC, потому что это один и тот же процесс.

Модель isolated worker выполняет ваши функции в отдельном процессе worker, которым вы управляете. Host запускает его, общается с ним по gRPC и пересылает полезные нагрузки триггеров. Вы приносите свой собственный Program.cs, свой собственный HostBuilder, свой собственный контейнер внедрения зависимостей и, что важно, свою собственную версию runtime .NET. Host может оставаться на любой версии .NET, которую поставляет Microsoft; ваш worker может быть на .NET 11. Эта развязка — в этом весь смысл: она позволяет Microsoft перестать пересобирать host для каждого нового выпуска .NET.

Матрица возможностей

ВозможностьIn-processIsolated worker
Последняя поддерживаемая версия .NET.NET 8 LTS.NET 8, 9, 10, 11 (любая текущая LTS или STS)
Дата вывода из эксплуатации10 ноября 2026активна, вывод не объявлен
Модель процессаобщий с hostотдельный процесс worker
Связь с hostв памятиgRPC через named pipes / TCP
Стартовый файлStartup.cs с FunctionsStartupProgram.cs с HostBuilder
Внедрение зависимостейDI host, ограниченная поверхность overrideполный Microsoft.Extensions.DependencyInjection
Middlewareне поддерживаетсяподдерживается через IFunctionsWorkerApplicationBuilder
Тип HTTP-ответаIActionResult, HttpResponseMessageHttpResponseData, интеграция с ASP.NET Core (opt-in)
Журналированиеинъекция параметра ILoggerILogger через DI или FunctionContext
Покрытие триггеров и привязоксамое широкое (любое расширение WebJobs)широкое, но несколько расширений всё ещё отстают
Cold start (маленькая HTTP-функция, Linux)~250-400 мс на Consumption~350-600 мс на Consumption
Пропускная способность в “горячем” режименемного выше (без IPC)немного ниже (gRPC-переход на каждый вызов)
Токены отмены в функцияхподдерживаются на большинстве триггеровподдерживаются на всех триггерах с Worker 1.16
Первоклассная поддержка OpenTelemetryчерез расширения hostнативно через AddApplicationInsightsTelemetryWorkerService и стандартные экспортёры OTel
Ahead-of-time компиляцияне поддерживаетсяNative AOT поддерживается на .NET 8+ для HTTP-триггеров

Две строки, которые принимают решение за вас, — это первые две. Всё остальное — детали реализации по сравнению с тем, что “модель исчезает в ноябре 2026”.

Когда выбирать модель isolated worker

С практической точки зрения это теперь единственный выбор. Обращайтесь к нему в каждом из этих случаев:

Минимальный Program.cs для isolated worker выглядит так:

// .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() включает интеграцию с ASP.NET Core, так что ваши HTTP-триггеры могут принимать HttpRequest и возвращать IActionResult, как это делают контроллеры. Без этого вызова HTTP-триггеры используют типы HttpRequestData / HttpResponseData из worker SDK, которые ощущаются более многословными, но более дружелюбны к Native AOT.

Когда выбирать модель in-process

Остался ровно один сценарий: у вас есть существующее in-process приложение на .NET 6 или .NET 8, которое вы не можете мигрировать до 10 ноября 2026, и вам нужно продолжать выпускать исправления ошибок против него до тех пор. Держите его на .NET 8 LTS, не тратьте усилий на его тюнинг и поставьте миграцию в дорожную карту.

Ещё два узких случая, которые раньше склоняли чашу к in-process, и как они выглядят в 2026 году:

Бенчмарк cold start

Ниже — числа, которые я измерил на плане Linux Consumption в регионе West Europe. Методология: одна HTTP-triggered функция, возвращающая "hello". Каждая строка — медиана из 50 cold start, запущенных после 25 минут простоя, с использованием azure-functions-perftools для запуска цикла curl. Один и тот же host.json, одна и та же конфигурация App Insights. .NET 8.0.18 LTS для строк in-process и .NET 8 isolated; .NET 11.0 preview 4 для строки .NET 11.

КонфигурацияCold start (p50)Cold start (p95)Задержка в горячем режиме (p50)
In-process, .NET 8 LTS, JIT312 мс478 мс4.1 мс
Isolated worker, .NET 8 LTS, JIT488 мс702 мс6.8 мс
Isolated worker, .NET 11 preview 4, JIT451 мс661 мс6.2 мс
Isolated worker, .NET 8 LTS, Native AOT (только HTTP)198 мс287 мс3.4 мс
Isolated worker, .NET 11 preview 4, Native AOT (HTTP)181 мс266 мс3.1 мс

Две вещи, которые можно прочитать из этой таблицы. Во-первых, JIT isolated worker действительно медленнее in-process на cold start, примерно на 150 мс на этой нагрузке. Этот разрыв — gRPC-handshake плюс процесс worker, разворачивающий свой собственный HostBuilder. Во-вторых, Native AOT закрывает разрыв и больше: isolated worker с Native AOT быстрее, чем модель in-process когда-либо была. Если вашим бизнес-обоснованием для того, чтобы оставаться на in-process, был cold start, современный ответ — перейти на isolated и включить AOT, а не оставаться там, где вы есть.

Подводные камни, которые принимают решение за вас

Две вещи вынуждают принять решение независимо от предпочтений.

Дата вывода из эксплуатации — это жёсткий срок, а не рекомендация. 10 ноября 2026 года Azure перестанет принимать развёртывания на модель in-process и перестанет масштабировать существующие in-process приложения. Microsoft публиковала уведомление о выводе из эксплуатации неоднократно с начала 2024 года, а к середине 2026 года миграционный инструментарий в dotnet upgrade-assistant покрывает большинство механических шагов. Если ваша in-process функция — это парадная дверь к чему-то клиентоориентированному, “мы мигрируем в Q1 2027” — это не план, это сбой.

Некоторые привязки ведут себя слегка по-разному в двух моделях. Две, которые с наибольшей вероятностью укусят вас во время миграции:

Как обычно идёт миграция

Типичная миграция малого-среднего размера с in-process на isolated worker в одной function app на .NET 8 занимает один сфокусированный день плюс окно релиза. Механические шаги:

  1. Поменяйте ссылку на SDK в .csproj с Microsoft.NET.Sdk.Functions на Microsoft.Azure.Functions.Worker.Sdk и добавьте Microsoft.Azure.Functions.Worker.
  2. Удалите Startup.cs и FunctionsStartup. Замените их на Program.cs, использующий FunctionsApplication.CreateBuilder(args).
  3. Поменяйте каждую ссылку на расширение привязки с Microsoft.Azure.WebJobs.Extensions.* на Microsoft.Azure.Functions.Worker.Extensions.*.
  4. Перепишите сигнатуры функций: параметры ILogger log перемещаются в конструкторное внедрение или в FunctionContext.GetLogger<T>(). [FunctionName] становится [Function]. HttpRequest / IActionResult либо остаются (если вы вызываете ConfigureFunctionsWebApplication()), либо меняются на HttpRequestData / HttpResponseData.
  5. Установите FUNCTIONS_WORKER_RUNTIME в dotnet-isolated в конфигурации вашей function app и обновите стек runtime развёрточного слота в портале или в Bicep.
  6. Прогоните тестовый набор, затем разверните в staging-слот и проведите 24-часовой soak перед переключением.

dotnet upgrade-assistant автоматизирует шаги с 1 по 4 для большинства приложений. Места, где он не может помочь, — это пользовательский код, эквивалентный middleware (который вы обычно хотите преобразовать в настоящий middleware), и любой доступ к host WebJobs на основе рефлексии, который больше не применяется.

Опинионатированная рекомендация, переформулированная

Используйте модель isolated worker для каждого Azure Functions-приложения в 2026 году. Если вы начинаете с нуля, делайте scaffold на .NET 11 isolated и включайте Native AOT для HTTP-триггеров, если cold start важен. Если у вас есть in-process приложение, запланируйте его миграцию так, чтобы она приземлилась до октября 2026 года, чтобы иметь месяц запаса до даты вывода из эксплуатации, и используйте этот месяц для прогрева новой модели под реальным трафиком. Аргумент “in-process быстрее” больше не верен, как только вы добавляете AOT в сравнение, а “у in-process больше привязок” не было верно с второй половины 2024 года.

Связанное

Источники

Comments

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

< Назад