A test-first way to compare in-process and isolated worker behavior before release
Migrating an Azure Functions app from .NET in-process to the isolated worker model is not a successful upgrade simply because the project compiles. Triggers still need to fire, HTTP responses must preserve their contracts, background work must avoid duplicate side effects, and operators need usable signals when something fails. This guide turns those expectations into a migration test matrix that can be reviewed before a deployment, rather than a vague “test everything” instruction.
Microsoft documents November 10, 2026 as the end of support for the Azure Functions .NET in-process execution model. That is a model-specific support deadline, not a claim that all Functions apps, all .NET versions, or isolated-worker deployments stop running on that date. Treat the date as a reason to verify your estate and plan a supported migration; it is not evidence of an incident in your application.
Scope and prerequisites
The worked plan assumes a C# class-library Functions app on Azure Functions runtime 4.x, with an in-process .NET 8 baseline and a proposed isolated-worker target. Confirm the actual target framework and hosting plan from current Microsoft support tables before copying any version choice. The examples below are test designs, not executed tests, and no deployed function, repository, or production telemetry was provided for this article.
Before modifying a branch, capture the .csproj, package lock or resolved dependencies, host.json, local.settings.json keys without secrets, deployment settings, trigger inventory, extensions, identity permissions, and the current release process. Record what success looks like for each public endpoint, queue subscription, timer, durable orchestration and outbound integration. Without a baseline, “it worked after migration” is difficult to distinguish from “the feature has never been exercised.”
What really changes between the models
In-process code runs in the Functions host process. Isolated-worker functions run in a separate .NET worker process. Microsoft’s comparison documents differences in project packages, trigger and output types, startup composition, dependency injection, binding extensions and logging. HTTP handlers may use HttpRequestData/HttpResponseData, or ASP.NET Core types when the supported integration is configured; those are different paths and should not be treated as interchangeable without tests.
The target project also needs an appropriate isolated-worker SDK and worker packages, not leftover in-process WebJobs extension references. Microsoft’s migration guide calls for testing locally with Functions Core Tools 4.x before updating the hosted app. Application settings such as FUNCTIONS_WORKER_RUNTIME must match the execution model. Those steps establish a plausible configuration, but not evidence that business behavior is preserved.
The binding, hosting and CI test matrix
Give every affected subsystem one observable contract, a reproducible test and a failure gate. A passing build is a prerequisite, not a release decision. The matrix below is a proposed worksheet: its rows require evidence from your own codebase, a representative test environment and deployment logs.
Area / risk | Target test | Release evidence / stop condition |
Runtime + packages | Inventory .NET target, Functions 4.x, worker packages and extensions; build from clean restore. | PASS only on a supported target combination; STOP on unresolved legacy references. |
Startup + DI | Boot locally and in staging; resolve injected services, settings and middleware. | Capture startup traces; UNKNOWN if configuration differs. |
HTTP contract | Replay routes, payloads, auth, status codes and serialization including invalid input. | Compare baseline with captured responses; FAIL for contractual drift. |
Queues + bindings | Send test messages; verify trigger dispatch, serialization, retries and poison handling. | Trace each message to outcome; FAIL for lost or duplicate work. |
Durable state (if used) | Check API mapping; test new and resumed orchestrations with a specific state plan. | HOLD without evidence for state continuity and recovery. |
Deployment + hosting | Stage on the intended plan; inspect worker setting, managed identity and extensions. | STOP if deployment config or permissions disagree with tests. |
Telemetry + rollback | Trigger a controlled failure; inspect host and worker logs, alerts and reversal path. | HOLD if alerts, evidence or recovery procedure are missing. |
How to use each gate
For every row, write the baseline behavior, the target behavior, an owner, the exact test command or manual procedure, a timestamped output location and a verdict: PASS, FAIL or UNKNOWN. UNKNOWN is not PASS. The gate should reference a recorded artifact such as a CI job run, a redacted request/response comparison, a trace ID, or a reviewed configuration diff. A failed test blocks the corresponding release slice until repaired and rerun.
Do not collapse the matrix into a single green pipeline badge. A CI job can prove the package builds while providing no evidence that a Service Bus trigger consumes messages under the intended identity, that an HTTP endpoint maintains its status codes, or that failed queue processing remains recoverable. Test observables at the boundary users and dependent systems actually see.
Hypothetical migration: an HTTP-to-queue workflow
Consider a hypothetical app with an HTTP function that accepts a job, writes a queue message and returns an acknowledgement; a queue-triggered function performs the work. The existing behavior contract is not “the HTTP function returns 200.” It is: a valid request receives the documented status and correlation ID, the payload reaches the queue once per accepted logical job, the worker processes the message under its expected identity, and a transient failure follows the configured retry or poison-message path.
First record a baseline response and a sanitized queue message in a controlled test account. Next migrate the project structure and bindings in a branch. Run HTTP contract tests, validate the serialized queue message, introduce a controlled downstream failure, inspect retry behavior, and compare trace correlation across ingress and worker execution. None of those outcomes can be marked PASS until a real run produces evidence. If the app uses Durable Functions, add a separate stateful migration review rather than assuming ordinary queue tests cover orchestration semantics.
An important false positive: a test that only asserts that a message was queued can pass while the isolated-worker consumer never starts. Another: a request-handler unit test can pass while the deployed Function lacks the identity permissions needed to reach storage. A third: a smoke test sees one successful message but never evaluates concurrent or retried delivery. Each false pass points to a missing observation, not automatically to a broken framework.
CI sequencing and rollback conditions
A practical pipeline separates checks into four stages. Stage one inventories packages, target framework and forbidden legacy references; it fails on unresolved build or dependency issues. Stage two runs unit and serialization tests against business contracts. Stage three starts the Functions host in a controlled environment and exercises real triggers, permissions and failure paths. Stage four deploys to a nonproduction slot or equivalent isolated environment, checks telemetry, verifies infrastructure configuration, and records a rollback or traffic-reversal plan suited to the hosting plan.
Keep deploy configuration under review alongside code. The local configuration file does not automatically prove the hosted FUNCTIONS_WORKER_RUNTIME value, connection-string or managed-identity arrangement. Logging behavior can differ because the host and worker have separate responsibilities; validate that errors, correlation identifiers and alerts still reach the tools used by the on-call team. A staging PASS cannot substitute for a production-readiness sign-off when environment settings differ.
Stop a release when a critical trigger fails, data or response contracts drift, dependency versions cannot be explained, retries may create uncontrolled side effects, observability is missing, or rollback cannot be performed safely. If a test is flaky, record the flake and its scope rather than treating a later lucky pass as proof. For a hosting-plan or .NET target that is not supported in the official table, stop before deployment design rather than trying to repair it with more tests.
A reviewable definition of done
The migration is ready for human release review when every inventory item has a mapped owner; each critical contract has a baseline and target assertion; the matrix contains links to successful test evidence; no critical row is FAIL or UNKNOWN; a staged deployment has run with realistic identities and configurations; and rollback plus operational monitoring have named owners. That is a measurable decision standard, not a claim of zero risk.
Use the matrix to expose uncertainty early. It is intentionally narrower than a comprehensive migration manual: it does not replace Microsoft’s version-specific instructions, extension compatibility documentation, or tests written around your application’s own domain. A small amount of falsifiable evidence is more useful than a large checklist with no recordings of what actually happened.
Join the conversation! Your thoughts help the community grow.