A region is a geographic provider area; availability zones are separate failure domains within it. Putting two processes on one host does not create two zone placements. Putting compute in two zones also does not remove a single-zone database dependency.
The local model labels one fictional region and zones a/b. They are architecture labels, not promises about a particular account’s physical zone mapping. We inspect what remains after each failure, then separately ask whether the complete API still has every dependency it needs.
Availability in this exercise means at least one healthy placement of a named tier remains. It says nothing about capacity, routing health checks or whether a database can fail over. Those are additional mechanisms that must be designed and tested.
Represent a failed zone as a(region,zone) pair. A zone with the same short label in another region is a different failure domain. Deduplicate service names in the result; two surviving API replicas do not mean two independent APIs for this report.
from dataclasses import dataclass
import ipaddress
import re
class PlanError(ValueError):
pass
def bounded_text(value, label):
if not isinstance(value,str) or not value.strip() or len(value)>200:
raise PlanError(label)
return value
def integer(value, low, high):
if type(value) is not int or not low<=value<=high:
raise PlanError("integer outside plan bounds")
return value
@dataclass(frozen=True)
class Replica:
service: str
region: str
zone: str
healthy: bool = True
def available_services(replicas, failed_regions=(), failed_zones=()):
"""Placement availability only; not capacity, health-check routing or failover."""
if not isinstance(replicas,(list,tuple)) or not 1<=len(replicas)<=20:
raise PlanError("bounded replicas required")
if not isinstance(failed_regions,(list,tuple)) or not isinstance(failed_zones,(list,tuple)):
raise PlanError("failure collections required")
for region in failed_regions:bounded_text(region,"failed region")
for pair in failed_zones:
if not isinstance(pair,(list,tuple)) or len(pair)!=2:raise PlanError("zone needs region and name")
bounded_text(pair[0],"zone region");bounded_text(pair[1],"zone name")
failed=set(tuple(pair) for pair in failed_zones)
available=set()
for replica in replicas:
if not isinstance(replica,Replica) or type(replica.healthy) is not bool:raise PlanError("typed replica required")
for value in (replica.service,replica.region,replica.zone):bounded_text(value,"replica field")
if replica.healthy and replica.region not in failed_regions and (replica.region,replica.zone) not in failed:
available.add(replica.service)
return tuple(sorted(available))
replicas=[Replica("api","r1","a"),Replica("api","r1","b"),Replica("database","r1","a")]
remaining=available_services(replicas,failed_zones=(("r1","a"),))
print(remaining)
print("complete API path", {"api","database"} <= set(remaining))For the reference plan, losing zone-a leaves edge and API compute in zone-b but removes the only database placement. Requests needing notes therefore cannot complete. Losing zone-b leaves the zone-a path intact in this placement model, subject to capacity/routing assumptions. Losing the whole region removes all tiers.
A multi-zone managed database may address one dependency, but failover behavior and recovery still need verification. Backups address a different problem from immediate availability. Keep these distinctions visible in the final explanation and failure table.
placements=[("api","a"),("api","b"),("database","a")]
for failed in ("a","b"):
remaining={service for service,zone in placements if zone!=failed}
print("lost",failed,"remaining",sorted(remaining))Implement placement availability, then explain the difference between a surviving API replica and a functioning API with all dependencies. Next trace network flows across those tiers.
Compute survives. Does the whole path?
Choose a placement failure. Two zones hold edge and API replicas, while the database has one zone-a placement. This model checks dependency presence; it does not measure real capacity, routing, failover or cloud availability.
zone-aplacements remain
44380805432zone-bplacements remain
4438080API depends on the database in zone-a.
Placement only. The healthy case is not a deployment or production-reliability claim.
Inspect the eight actual ingress decisions from the local checker
| Source | Destination | Port | Decision |
|---|---|---|---|
| internet | edge | 443 | allow |
| internet · IPv6 | edge | 443 | allow |
| edge | api | 8080 | allow |
| api | database | 5432 | allow |
| internet | api | 8080 | deny |
| internet | database | 5432 | deny |
| edge | database | 5432 | deny |
| edge | api | 22 | deny |