Skip to main content
Chaos engineering is the discipline of experimenting on a system in order to build confidence in the system’s capability to withstand turbulent conditions in production. If you want to learn more about chaos engineering:

Chaos engineering with Simmy

Simmy is a major new addition to Polly library starting with v8.3.0, adding a chaos engineering and fault-injection dimension to Polly, through the provision of strategies to selectively inject faults, latency, custom behavior or fake results.
Chaos strategies are seamlessly integrated into Polly v8’s resilience pipeline architecture, allowing you to combine them with retry, circuit breaker, timeout, and other resilience strategies.

Basic usage

Here’s how to configure chaos strategies in your resilience pipeline:
It is usual to place the chaos strategy as the last strategy in the resilience pipeline. By placing the chaos strategies last, they subvert the usual outbound call at the last minute, substituting their fault or adding extra latency, etc. The existing resilience strategies - further out in the pipeline - still apply, so you can test how the Polly resilience strategies you have configured handle the chaos/faults injected by Simmy.
The AddChaosFault, AddChaosLatency, AddChaosOutcome, and AddChaosBehavior will take effect sequentially if you combine them together. In the above example, we use fault first then latency strategy, which can save fault waiting time. If you put AddChaosLatency before AddChaosFault, you will get different behavior.

Built-in chaos strategies

Common options across strategies

All chaos strategies share these configuration options:
With the V8 API, chaos strategies are enabled by default. You can opt-out of them one-by-one either via the Enabled or via the EnabledGenerator property. In previous Simmy versions you had to explicitly enable chaos policies.
  • If both InjectionRate and InjectionRateGenerator are specified then InjectionRate will be ignored.
  • If both Enabled and EnabledGenerator are specified then Enabled will be ignored.

Major differences from Polly.Contrib.Simmy

This section highlights the major differences compared to the Polly.Contrib.Simmy library:
  • From MonkeyPolicy to ChaosStrategy: We’ve updated the terminology from Monkey to Chaos to better align with the well-recognized principles of chaos engineering.
  • Unified configuration options: The InjectOptionsBase and InjectOptionsAsyncBase are now consolidated into ChaosStrategyOptions. This change brings Simmy in line with the Polly v8 API, offering built-in support for options-based configuration and seamless integration of synchronous and asynchronous executions.
  • Chaos strategies enabled by default: Adding a chaos strategy (previously known as monkey policy) now means it’s active right away. This is a departure from earlier versions, where the monkey policy had to be explicitly enabled.
  • API changes: The new version of Simmy introduces several API updates:
  • Sync and async unification: Before, Simmy had various methods to set policies like InjectLatency, InjectLatencyAsync, InjectLatency<T>, and InjectLatencyAsync<T>. With the new version based on Polly v8, these methods have been combined into a single AddChaosLatency extension that works for both ResiliencePipelineBuilder and ResiliencePipelineBuilder<T>. These rules are covering all types of chaos strategies (Outcome, Fault, Latency, and Behavior).

Inject chaos selectively

You can dynamically adjust the frequency and timing of chaos injection. For instance, in pre-production and test environments, it’s sensible to consistently inject chaos. This proactive approach helps in preparing for potential failures. In production environments, however, you may prefer to limit chaos to certain users and tenants, ensuring that regular users remain unaffected.
When simulating extreme scenarios by setting the injection rate to 1.0 (100%), exercise caution by restricting it to a subset of tenants and users to avoid rendering the system unusable for regular users.
Here’s how to configure chaos strategies to enable selective injection:

Centralize chaos management

We recommend encapsulating the chaos decisions and injection rate in a shared class, such as IChaosManager:
This approach allows you to consistently apply and manage chaos-related settings across various chaos strategies:
An alternative method involves using Microsoft.Extensions.AsyncState for storing information relevant to chaos injection decisions. This can be particularly useful in frameworks like ASP.NET Core. For instance, you could implement a middleware that retrieves user information from HttpContext, assesses the user type, and then stores this data in IAsyncContext<ChaosUser>. Subsequently, IChaosManager can access IAsyncContext<ChaosUser> to retrieve this information.

Telemetry

The telemetry of chaos strategies is seamlessly integrated with Polly’s telemetry infrastructure. The chaos strategies produce the following information events:
  • Chaos.OnFault - Reported when a fault is injected
  • Chaos.OnOutcome - Reported when an outcome is injected
  • Chaos.OnLatency - Reported when latency is injected
  • Chaos.OnBehavior - Reported when a behavior is injected
All chaos telemetry events are reported with Information severity.

Motivation

There are a lot of questions when it comes to chaos engineering and making sure that a system is actually ready to face the worst possible scenarios:
  • Is my system resilient enough?
  • Am I handling the right exceptions/scenarios?
  • How will my system behave if X happens?
  • How can I test without waiting for a handled (or even unhandled) exception to happen in my production environment?
Using Polly helps introduce resilience to a project, but we don’t want to have to wait for expected or unexpected failures to test it out. A resilience strategy could be wrongly implemented; testing the scenarios is not straightforward; and mocking failure of some dependencies (for example a cloud SaaS or PaaS service) is not always straightforward.

What is needed to simulate chaotic scenarios?

  • A way to simulate failures of dependencies (any service dependency for example).
  • Define when to fail based on some external factors - maybe global configuration or some rule.
  • A way to revert easily, to control the blast radius.
  • To be production grade, to run this in a production or near-production system with automation.

Next steps

Fault Injection

Inject exceptions to test error handling

Latency Injection

Add delays to simulate slow operations

Outcome Injection

Inject fake results or responses

Behavior Injection

Execute custom behavior before operations