1. Turn constraints into compute candidates
Start with a requirements sheet for each component. In the fictional example, a query API accompanies a legacy engine whose vendor requires an operating-system driver. The first wave cannot change that engine. A VM is a candidate for retaining the necessary control, but support, licensing, capacity and maintenance still need confirmation. The API can have another hosting option. Include integration and operating effort in the decision rather than comparing only unit price. For each alternative, write down the constraint it satisfies, the responsibility retained by the team and the evidence still needed. The PM turns that responsibility into an owner, effort and a work window. A technically possible choice remains incomplete if nobody can maintain it after transition to RUN. Record accepted limitations alongside the selected service.
2. Choose the container control boundary
A container describes packaging but does not determine the platform on its own. If the solution requires a custom operator using Kubernetes APIs, include AKS in the comparison. If services need managed hosting without those APIs, evaluate Container Apps against actual requirements. Then address isolation. In the exercise, two trusted internal teams receive namespaces but still need suitable network policies and permissions. In another component, untrusted code requires privileges incompatible with the internal cluster; that boundary needs stronger analysis, including separate clusters. Do not use namespace count as isolation evidence. Ask the team to explain which action a consumer can attempt, which control prevents it and which exercise demonstrates that outcome. Also record the operating cost of the chosen boundaries and who maintains the controls throughout the application lifecycle.
3. Separate accepted requests from completed work
A fictional export takes eight minutes. Its consumer needs to know that the request was accepted and later retrieve the result. An asynchronous contract with an identifier, queryable status and explicit failure avoids making the interaction depend on one long HTTP response. Then choose the execution mechanism: finite work can fit a job; a continuous consumer has another lifecycle. Document what happens if the process stops midway, the request repeats or the platform interrupts execution. A timeout without a configured bound does not make memory durable. The exercise asks for an observable sequence: durably accept, execute, validate and publish the result. An acceptance acknowledgement must not appear to the user as completion. Support needs to distinguish those states to respond correctly during an incident and identify which recovery action is safe.
4. Accept partitioned processing results
The fictional process has a closed manifest: partitions A, B and C, all at version v7. Every output has an identity, version and validation state. After a retry, A-v7, a second A-v7 copy and B-v7 exist. Three files do not satisfy three partitions. The code below models that acceptance rule; it rejects duplicates, unexpected partitions, incorrect versions and invalid results. It does not represent any service API or simulate distributed concurrency. In a Batch design, the scheduler organizes execution while the application defines the result contract. The owner must decide how to recover only missing work or publish a new set under control. The financial estimate includes consumed resources and usage duration. Even a service without an additional fee can execute work with material compute, storage and networking costs.
5. Design policies and freshness on the actual path
Follow a request from its consumer. If validation exists only at the gateway, a direct backend connection does not traverse it. Draw that second path and decide how to restrict or protect it. Then check the freshness of delivered data. In the example, a local cache retains an old limit while another process changes the database. A high cache hit rate can coexist with incorrect decisions. The contract must specify where stale information is tolerable and where demonstrably current reading is necessary. Exercises involving external writers and different instances reveal gaps that an isolated test misses. Cache review also includes lifecycle: migration to Azure Managed Redis requires checking the client, authentication and endpoint. Provisioning the destination is one step; accepting application behavior requires additional evidence. Record the distinction in the migration checklist.
6. Choose routing by protocol and scope
The network sheet should identify protocol, scope, termination and health requirements. In the exercise, the public portal uses HTTP/S across regions while an internal service uses UDP in one region. Selection should reflect that difference. Check current capabilities before excluding options: Application Gateway also presents TCP/TLS support, and Load Balancer has options beyond regional scope. Traffic Manager works through DNS, so clients can continue using a cached address during a change. The exercise should observe that behavior and its effect on service. Also review the health endpoint: always returning 200 can hide an unavailable essential dependency. Relevant evidence is the ability to serve the agreed path. A frequent probe measuring the wrong thing still supplies an insufficient signal. Document both detection and the client behavior after routing changes.
7. Interpret migration assessments and dependencies
An assessment reflects data and assumptions at a point in time. In the fictional case, collection was complete across five quiet days but excluded monthly close. Data coverage can be high while the period fails to represent the demand determining required capacity. The PM requests representative measurements, revised assumptions and a destination exercise. Apply the same care to the dependency map: a monthly integration absent during two observed days has not ceased to exist. Reconcile observed connections with configuration, schedules and owners. When splitting an application into waves, measure the temporary hybrid path, including latency and connection failures. The duration of that phase affects budget and support. A list of migrated servers should be accompanied by evidence about business services that continue functioning and the limitations accepted during transition.
8. Prepare cutover, rollback and decommissioning
A test copy can retain source credentials and jobs. Before booting it, prevent submissions to the real partner and prepare authorized exercise destinations. During production cutover, define which environment may write and how to handle in-flight work. Changing DNS does not stop a scheduler. If the target has already accepted new instructions, returning to the old snapshot requires handling that data; traffic rollback does not transport it. The out-of-hours plan should reserve time to reconcile, decide and recover within the approved window. In the exercise, twenty minutes remain and reconciliation requires thirty; do not assume an extension because nobody responds. Finally, decommissioning needs acceptance, recovery and retention criteria, an owner and a date. RUN should receive exercised procedures and decision capability alongside the resource inventory.
# Fictional closed-manifest acceptance model; no Azure calls or concurrency claims.
def accepts(expected, version, outputs):
if not expected or len(expected)!= len(set(expected)):
raise ValueError("expected IDs must be nonempty and unique")
seen = set
for item in outputs:
key = item["id"]
if key not in expected or key in seen:
return False
if item["version"]!= version or item["valid"] is not True:
return False
seen.add(key)
return seen == set(expected)
def output(key, version="v7", valid=True):
return {"id": key, "version": version, "valid": valid}
manifest = ["A", "B", "C"]
assert accepts(manifest, "v7", [output(x) for x in manifest])
assert not accepts(manifest, "v7", [output("A"), output("A"), output("B")])
assert not accepts(manifest, "v7", [output("A"), output("B")])
assert not accepts(manifest, "v7", [output("A"), output("B"), output("D")])
assert not accepts(manifest, "v7", [output("A"), output("B"), output("C", "v6")])
assert not accepts(manifest, "v7", [output("A"), output("B"), output("C", valid=False)])
assert accepts(manifest, "v7", [output("C"), output("A"), output("B")])
assert not accepts(manifest, "v7", [])
print("eight fictional manifest checks passed")
Fictional exercise: the manifest requires A, B and C at version v7. Two A outputs and one B output do not authorize publication. Identify missing work and design replay preserving valid results.
Common pitfalls
Choosing by service name; accepting only VM boot; counting files without checking identity; ignoring copied-job effects; treating traffic rollback as data recovery.
Related topics: Idempotent processing · Change governance · Capacity and FinOps · Operational acceptance
Choose compute by constraints and operating capacity. Accept work through its results. Migrate with known dependencies, controlled writing and demonstrated recovery.
Reference: Choose an Azure compute service · AZ-305 objectives 2026-04-17