Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Polly-Contrib/Simmy/llms.txt

Use this file to discover all available pages before exploring further.

One of the most powerful aspects of Simmy is that every option accepting a delegate receives a Polly Context object and a CancellationToken. This means chaos behaviour — whether it fires at all, how often, what fault to throw, how long to delay — can be computed at the moment of each individual call rather than fixed at application startup. By combining Context with an external configuration source such as an app-settings file, Azure App Configuration, or a feature-flag service, you can turn chaos on and off, adjust injection rates, and target individual operations without touching code or redeploying.

What is Polly Context?

A Polly Context is a dictionary-like object that travels with every policy execution. It can carry arbitrary key/value data, but its most important built-in property for targeting purposes is OperationKey — a free-text string you set at call time that identifies the logical operation being performed.
// Tagging an execution with an OperationKey
var context = new Context("MyDatabaseOperation");
chaosPolicy.Execute(ctx => myDb.Query(), context);
Every delegate you supply to Simmy builder methods (EnabledWhen, InjectionRate, Fault, Latency, Behaviour) receives this context as its first argument. Reading ctx.OperationKey lets a single shared chaos policy make different decisions for different callers.

Targeting Specific Operations

Rather than creating one policy per operation, build one policy that reads ctx.OperationKey inside its delegates and applies different behaviour based on which operation is executing.
var chaosPolicy = MonkeyPolicy.InjectException(with =>
    with.Fault((ctx, ct) =>
        {
            // Return a domain-appropriate exception per operation
            return ctx.OperationKey switch
            {
                "DatabaseQuery"  => new TimeoutException("DB timeout injected"),
                "PaymentGateway" => new HttpRequestException("Payment gateway fault"),
                _                => new InvalidOperationException("Generic chaos fault")
            };
        })
        .InjectionRate(0.1)
        .EnabledWhen((ctx, ct) =>
        {
            // Only inject chaos for operations that are opted-in
            return ctx.OperationKey is "DatabaseQuery" or "PaymentGateway";
        })
);

// Caller tags the execution
var dbContext   = new Context("DatabaseQuery");
var httpContext = new Context("PaymentGateway");

chaosPolicy.Execute(ctx => database.RunQuery(), dbContext);
chaosPolicy.Execute(ctx => payment.Charge(amount), httpContext);

Driving Chaos from External Configuration

Hard-coding injection rates and enabled flags makes chaos policies rigid. The delegate overloads let you call out to a configuration service on every execution, so the chaos settings can change at runtime.
1

Create a configuration service

Define a service that reads the current chaos settings. This might wrap Azure App Configuration, a database table, or a simple in-memory store toggled by an admin endpoint.
public interface IChaosConfigService
{
    bool   IsChaosEnabled(string operationKey);
    double GetInjectionRate(string operationKey);
}
2

Build the policy with delegate overloads

Wire the policy so that each execution reads live configuration.
var chaosPolicy = MonkeyPolicy.InjectException(with =>
    with.Fault(new TimeoutException())
        .InjectionRate((ctx, ct) =>
        {
            return configService.GetInjectionRate(ctx.OperationKey);
        })
        .EnabledWhen((ctx, ct) =>
        {
            return configService.IsChaosEnabled(ctx.OperationKey);
        })
);
3

Tag executions with OperationKey

At each call site, attach a context that identifies the logical operation.
var context = new Context("OrderService.PlaceOrder");
var result  = chaosPolicy.Execute(ctx => orderService.PlaceOrder(order), context);
4

Change chaos settings at runtime

Update the configuration store — flip a feature flag, change a value in App Configuration, call an admin API — and the next execution will pick up the new settings automatically. No restart required.

The EnabledWhen + InjectionRate Pattern

This is the full production pattern combining environment checks, per-operation targeting, and dynamic rates:
var chaosPolicy = MonkeyPolicy.InjectException(with =>
    with.Fault(new TimeoutException())
        .InjectionRate((ctx, ct) =>
        {
            // Read the live injection rate for this specific operation
            return configService.GetChaosRate(ctx.OperationKey);
        })
        .EnabledWhen((ctx, ct) =>
        {
            // Only inject chaos in Dev/Staging environments
            return configService.IsChaosEnabled(ctx.OperationKey);
        })
);
The EnabledWhen delegate acts as a master gate. When it returns false the policy is entirely dormant — InjectionRate is not even evaluated — so there is zero cost to leaving chaos policies registered in production builds so long as IsChaosEnabled returns false.
Keep IsChaosEnabled cheap. It is called on every policy execution, so a blocking I/O call here would add latency to every request. Use an in-memory cache that is refreshed in the background by your configuration system.

Passing Custom Data via Context

Beyond OperationKey, Context can hold arbitrary entries via its dictionary interface. This lets callers pass extra information to chaos delegates.
var context = new Context("UserRegistration");
context["userId"]      = currentUser.Id;
context["environment"] = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");

chaosPolicy.Execute(ctx =>
{
    var userId = ctx["userId"] as string;
    return registrationService.Register(userId);
}, context);
Inside the chaos delegate you can then read those entries:
.EnabledWhen((ctx, ct) =>
{
    var env = ctx["environment"] as string;
    return env is "Development" or "Staging";
})

Reference: The Simmy Sample App

The Simmy Demo WebAPI sample provides a complete, runnable illustration of these patterns, demonstrating:
  • Startup-only injection: chaos policies are registered only when the hosting environment is Development or Staging, ensuring they never execute in production builds.
  • Runtime configuration: chaos settings (enabled flag, injection rate, fault type) are stored in an external configuration store and read at execution time through delegate overloads, so a developer can turn chaos on and off by updating configuration without touching code.
  • Per-operation targeting: each outbound HTTP call is tagged with an OperationKey matching the downstream service name, and the configuration store holds per-operation settings.
The patterns shown in the sample app are starting points, not requirements. Simmy is intentionally flexible — the delegate-based API places no constraints on where or how you read your chaos configuration.

Benefits Summary

CapabilityHow Simmy enables it
Enable / disable chaos without redeployingEnabledWhen reads live flag from config service
Adjust injection rate at runtimeInjectionRate delegate reads live value from config service
Target one operation, not allRead ctx.OperationKey inside any delegate
Different faults per operationFault delegate switches on ctx.OperationKey
Pass extra call-site data to delegatesStore in Context dictionary, read in delegate

Build docs developers (and LLMs) love