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.

The InjectBehaviour policy is Simmy’s most flexible chaos tool: it runs any arbitrary Action before the wrapped call executes. Where InjectException and InjectResult are constrained to fault types that Polly can model directly, InjectBehaviour gives you a free canvas — restart a virtual machine, poison a cache entry, toggle a feature flag, emit a monitoring alert, or trigger any other side effect your chaos scenario requires. The injected behaviour fires before the wrapped call, and provided no exception is thrown inside it, execution continues normally.

Factory method signatures

// Synchronous
InjectBehaviourPolicy MonkeyPolicy.InjectBehaviour(
    Action<InjectBehaviourOptions> configureOptions
)

// Asynchronous
AsyncInjectBehaviourPolicy MonkeyPolicy.InjectBehaviourAsync(
    Action<InjectBehaviourAsyncOptions> configureOptions
)
Both return their respective policy types and share the same fluent-builder pattern. The async variant’s Behaviour delegate returns Task, allowing await inside the injected action.

Quick start

1

Define the behaviour to inject

Write the action you want Simmy to execute. This can be any side-effecting code — calling an infrastructure API, modifying shared state, or writing to a log.
void restartRedisVM() { /* infrastructure restart logic */ }
2

Build the chaos policy

Configure the behaviour, injection rate, and an enabled predicate through the fluent builder.
var chaosPolicy = MonkeyPolicy.InjectBehaviour(with =>
    with.Behaviour(() => restartRedisVM())
        .InjectionRate(0.01)
        .EnabledWhen((ctx, ct) => isEnabled(ctx, ct))
);
An injection rate of 0.01 means roughly 1% of calls trigger the behaviour. .EnabledWhen accepts a Func<Context, CancellationToken, bool> delegate, so you can read a feature flag or configuration value at call time to decide whether chaos is active.
3

Execute through the policy

Pass your wrapped call to Execute as normal. On approximately 1 in 100 calls, restartRedisVM() runs first, then someMethod() executes.
chaosPolicy.Execute(() => someMethod());

Fluent option methods

.Behaviour(action)

An Action (or Action<Context, CancellationToken>) containing the side-effecting code to run before the wrapped call.

.InjectionRate(double)

A value between 0.0 and 1.0 controlling how often the behaviour fires.

.EnabledWhen(func)

A delegate that is evaluated at execution time to determine whether the monkey policy should be active.

Context-aware behaviour delegate

Pass Action<Context, CancellationToken> to receive the Polly Context and the execution’s CancellationToken inside the injected behaviour. This lets you target specific operations by OperationKey, read context data, or respect cooperative cancellation.
var chaosPolicy = MonkeyPolicy.InjectBehaviour(with =>
    with.Behaviour((ctx, ct) =>
        {
            Console.WriteLine($"Injecting behaviour for: {ctx.OperationKey}");
            SimulateInfrastructureEvent(ctx.OperationKey);
        })
        .InjectionRate(0.05)
        .Enabled()
);

Async variant

For async code paths, use MonkeyPolicy.InjectBehaviourAsync. The behaviour delegate is Func<Task> or Func<Context, CancellationToken, Task>, which means your injected action can await infrastructure calls.
var chaosPolicy = MonkeyPolicy.InjectBehaviourAsync(with =>
    with.Behaviour(async (ctx, ct) =>
        {
            await NotifyMonitoringSystemAsync("chaos-event", ct);
            await FlushCacheAsync(ct);
        })
        .InjectionRate(0.02)
        .Enabled()
);

await chaosPolicy.ExecuteAsync(
    async ct => await myService.ProcessRequestAsync(ct),
    cancellationToken
);

Use cases

Infrastructure simulation

Restart services, clear caches, or modify configuration stores to simulate node failures and infrastructure events without touching real infrastructure.
with.Behaviour(() => restartRedisVM())

Shared state mutation

Corrupt or clear shared state (queues, caches, counters) to verify that dependent services degrade gracefully rather than producing incorrect results.
with.Behaviour(() => _cache.Clear())

Monitoring and alerting

Emit synthetic events to your monitoring system to test that alerts fire correctly and that on-call runbooks are accurate.
with.Behaviour((ctx, ct) =>
    _alerting.Emit("synthetic-error", ctx.OperationKey))

Feature flag toggling

Flip feature flags mid-execution to test how application code behaves when a feature is enabled or disabled during an in-flight request.
with.Behaviour(() => _featureFlags.Toggle("new-checkout"))

Execution order

The injected behaviour always runs before the wrapped call. If the behaviour throws an exception, the wrapped call is skipped and the exception propagates. If the behaviour completes without error, execution continues normally and the wrapped call runs regardless of what the behaviour did.
Execution flow (when injection fires):
  1. InjectBehaviour evaluates Enabled and InjectionRate
  2. Behaviour action executes   ← side effects happen here
  3. Wrapped call executes       ← only reached if behaviour did not throw
  4. Result returned to caller
If your injected behaviour throws an exception, it propagates up the policy chain just like any other exception. Make sure outer resilience policies are configured to handle the exception types your behaviour might raise, or guard against exceptions inside the behaviour itself.

Using inside a PolicyWrap

Place the InjectBehaviour policy innermost in a PolicyWrap so that outer resilience policies handle any knock-on effects of the injected behaviour — for example, if the behaviour clears a cache and the subsequent call to refill it fails.
var policyWrap = Policy.Wrap(fallbackPolicy, retryPolicy, chaosPolicy);
policyWrap.Execute(() => myService.GetCachedData());

Dynamic injection rate and enabled flag

Both InjectionRate and EnabledWhen support delegate forms, so chaos settings can be read from an external configuration service at call time without restarting the application.
var chaosPolicy = MonkeyPolicy.InjectBehaviour(with =>
    with.Behaviour(() => SimulateDiskPressure())
        .InjectionRate((ctx, ct) => _config.GetDouble("chaos:diskPressureRate"))
        .EnabledWhen((ctx, ct) => _config.GetBool("chaos:enabled"))
);

Reference

See Policy Options for the full reference on shared fluent options, including all delegate overloads for InjectionRate, Enabled, and EnabledWhen.

Build docs developers (and LLMs) love