Policies and Context¶
This document focuses on policy registration, selection, and scoped application.
Policy Model¶
A policy is a named set of optional fields:
latency(duration string like “50ms”)jitter(duration string like “10ms”)packet_loss(percentage or ppm)burst_loss(string like “3”)rate(bandwidth string like “10mbps”)timeout(dict withconnectand/orrecvkeys)dns(delay,timeout,nxdomain)session_budget(max tx/rx, operations, or duration limits with terminal action; action=timeout requires budget_timeout, action=connection_error accepts optional error)payload_mutation(R7 payload transform profile fields)targets(list of target rules for selective fault application)schedule(temporal profile: ramp, spike, or flapping)seed(optional random seed for deterministic behavior)
Policies are stored in a process-local registry protected by a lock.
Policy Lifecycle Sequence¶
sequenceDiagram
participant User as User code
participant Reg as Policy registry
participant Ctx as Thread policy context
participant Wrap as Decorator wrapper
participant SHM as SHM writer
User->>Reg: register_policy(name, fields)
alt Explicit binding
User->>Wrap: @fault(name)
Wrap->>Reg: resolve name
else Auto binding
User->>Ctx: with policy_context(name)
User->>Wrap: @fault()
Wrap->>Ctx: read current thread policy
Wrap->>Reg: resolve policy by context
end
Wrap->>SHM: write selected fields
Wrap->>SHM: clear on exit/finally
Diagram focus: registration, selection path, and cleanup behavior.
Register and Inspect Policies¶
import faultcore
faultcore.register_policy(
"slow_link",
latency="50ms",
jitter="10ms",
packet_loss="1%",
burst_loss="3",
rate="2mbps",
timeout={"connect": "20ms", "recv": "20ms"},
)
print(faultcore.list_policies()) # ["slow_link"]
print(faultcore.get_policy("slow_link"))
Remove a policy:
faultcore.unregister_policy("slow_link")
Apply Policy Explicitly¶
@faultcore.fault("slow_link")
def op():
return "ok"
If the policy is missing when the wrapped function is called, fault() executes the function without applying policy fields.
Auto Policy with Thread Context¶
fault() defaults to policy_name="auto" and reads thread-local policy.
import faultcore
faultcore.register_policy("inner", packet_loss="0.1%")
with faultcore.policy_context("inner"):
@faultcore.fault()
def op():
return "ok"
op()
The previous thread policy is restored on context exit.
policy_context(...) usage contract:
pass a policy name:
policy_context("my_policy"), orpass inline policy kwargs:
policy_context(latency="50ms", packet_loss="1%"),but do not pass both in the same call (
ValueError).
Inline Policy Context¶
policy_context allows inline policy definition without registering a named policy:
import faultcore
with faultcore.policy_context(latency="50ms", jitter="10ms", packet_loss="1%"):
@faultcore.fault()
def op():
return "ok"
op()
This creates a temporary policy that is automatically unregistered on context exit.
Async usage is also supported:
async with faultcore.policy_context("inner"):
...
Load Policies from File¶
JSON and YAML are supported:
count = faultcore.load_policies("policies.json")
print(count)
File format:
{
"policy_name": {
"latency": "7ms",
"jitter": "3ms",
"packet_loss": "0.2%",
"burst_loss": "2",
"rate": "1mbps",
"timeout": {"connect": "9ms", "recv": "9ms"},
"targets": [
{"target": "tcp://10.0.0.0/8", "priority": 10},
{"target": "tcp://127.0.0.1:9000", "priority": 100}
],
"schedule": {"kind": "spike", "every": "30s", "duration": "5s"}
}
}
Notes:
YAML support requires optional
PyYAML.Root value must be an object keyed by policy name.
targetsmust be a non-empty list when provided.
Target rule validation highlights:
String
targetentries supportany://,tcp://, andudp://prefixes.hostnameandsniare mutually exclusive in the same rule.host/cidrcannot be combined withhostname/sniin one rule.
Target Observability Rules¶
When targets are combined with policy effects, the registry enforces observability constraints:
DNS effects (
dns) require at least one hostname-only target selector (noportand noprotocol).Transport effects (for example
latency,rate,timeout,session_budget,payload_mutation) require target selectors observable in transport flow (host,cidr,hostname, orsni).
If these constraints are violated, register_policy() raises ValueError.
Timeout Notes¶
Use the
timeoutparameter with a dict containingconnectand/orrecvkeys.Example:
timeout={"connect": "200ms", "recv": "500ms"}Missing timeout fields are omitted from the policy.