{"id":19101445,"url":"https://github.com/Polly-Contrib/Simmy","last_synced_at":"2025-04-18T18:32:28.732Z","repository":{"id":34233626,"uuid":"164600410","full_name":"Polly-Contrib/Simmy","owner":"Polly-Contrib","description":"Simmy is a chaos-engineering and fault-injection tool, integrating with the Polly resilience project for .NET","archived":false,"fork":false,"pushed_at":"2022-06-02T22:59:13.000Z","size":405,"stargazers_count":548,"open_issues_count":11,"forks_count":25,"subscribers_count":21,"default_branch":"master","last_synced_at":"2024-09-16T18:23:08.410Z","etag":null,"topics":["chaos-engineering","fault-based-testing","fault-injection","fault-tolerance","fault-tolerant","polly-resilience","resilience","resilience-testing","resiliency","resilient"],"latest_commit_sha":null,"homepage":null,"language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Polly-Contrib.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-08T08:24:20.000Z","updated_at":"2024-09-13T08:37:40.000Z","dependencies_parsed_at":"2022-08-08T00:02:14.245Z","dependency_job_id":null,"html_url":"https://github.com/Polly-Contrib/Simmy","commit_stats":null,"previous_names":["app-vnext/simmy"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polly-Contrib%2FSimmy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polly-Contrib%2FSimmy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polly-Contrib%2FSimmy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Polly-Contrib%2FSimmy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Polly-Contrib","download_url":"https://codeload.github.com/Polly-Contrib/Simmy/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223783090,"owners_count":17201907,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chaos-engineering","fault-based-testing","fault-injection","fault-tolerance","fault-tolerant","polly-resilience","resilience","resilience-testing","resiliency","resilient"],"created_at":"2024-11-09T03:53:18.109Z","updated_at":"2025-04-18T18:32:28.724Z","avatar_url":"https://github.com/Polly-Contrib.png","language":"C#","funding_links":[],"categories":["others","C# #"],"sub_categories":[],"readme":"# Simmy\n\n\n\nSimmy is a [chaos-engineering](http://principlesofchaos.org/) and fault-injection tool, integrating with the [Polly resilience project for .NET](https://github.com/App-vNext/Polly).  It is releasing April 2019 and works with [Polly v7.0.0](https://www.nuget.org/packages/Polly/7.1.0) onwards.\n\nSimmy allows you to introduce a chaos-injection policy or policies at any location where you execute code through Polly.\n\n[![NuGet version](https://badge.fury.io/nu/Polly.Contrib.Simmy.svg)](https://badge.fury.io/nu/Polly.Contrib.Simmy) [![Build status](https://ci.appveyor.com/api/projects/status/5v3bpgjkw4snv3no?svg=true)](https://ci.appveyor.com/project/Polly-Contrib/simmy) [![Slack Status](http://www.pollytalk.org/badge.svg)](http://www.pollytalk.org)\n\n\u003cimg src=\"./Simmy_lg.png\" alt=\"Simmy\"  width=\"300\"/\u003e\n\n# Motivation\n\nThere 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:\n\n* Is my system resilient enough?\n* Am I handling the right exceptions/scenarios?\n* How will my system behave if X happens?\n* How can I test without waiting for a handled (or even unhandled) exception to happen in my production environment?\n\nUsing Polly helps me introduce resilience to my project, but I don't want to have to wait for expected or unexpected failures to test it out. My resilience could be wrongly implemented; testing the scenarios is not straight forward; and mocking failure of some dependencies (for example a cloud SaaS or PaaS service) is not always straightforward.\n\n**What do I need, to simulate chaotic scenarios in my production environment?**\n\n* A way to mock failures of dependencies (any service dependency for example).\n* Define when to fail based on some external factors - maybe global configuration or some rule.\n* A way to revert easily, to control the blast radius.\n* Production grade, to run this in a production or near-production system with automation.\n\n# Chaos policies\n\nSimmy offers the following chaos-injection policies:\n\n|Policy| What does the policy do?|\n| ------------- |------------- |\n|**[Exception](#Inject-exception)**|Injects exceptions in your system.|\n|**[Result](#Inject-result)**|Substitute results to fake faults in your system.|\n|**[Latency](#Inject-latency)**|Injects latency into executions before the calls are made.|\n|**[Behavior](#Inject-behavior)**|Allows you to inject _any_ extra behaviour, before a call is placed. |\n\n# Usage\n## Step 1: Set up the Monkey Policy\n\n## Inject exception\n```csharp\nvar chaosPolicy = MonkeyPolicy.InjectException(Action\u003cInjectOutcomeOptions\u003cException\u003e\u003e);\n```\nFor example:\n```csharp\n// Following example causes the policy to throw SocketException with a probability of 5% if enabled\nvar fault = new SocketException(errorCode: 10013);\nvar chaosPolicy = MonkeyPolicy.InjectException(with =\u003e\n\twith.Fault(fault)\n\t\t.InjectionRate(0.05)\n\t\t.Enabled()\n\t);\n```\n\n## Inject result\n```csharp\nvar chaosPolicy = MonkeyPolicy.InjectResult(Action\u003cInjectOutcomeOptions\u003cTResult\u003e\u003e);\n```\nFor example:\n```csharp\n// Following example causes the policy to return a bad request HttpResponseMessage with a probability of 5% if enabled\nvar result = new HttpResponseMessage(HttpStatusCode.BadRequest);\nvar chaosPolicy = MonkeyPolicy.InjectResult\u003cHttpResponseMessage\u003e(with =\u003e\n\twith.Result(result)\n\t\t.InjectionRate(0.05)\n\t\t.Enabled()\n);\n```\n\n## Inject latency\n```csharp\nvar chaosPolicy = MonkeyPolicy.InjectLatency(Action\u003cInjectLatencyOptions\u003e);\n```\nFor example:\n```csharp\n// Following example causes policy to introduce an added latency of 5 seconds to a randomly-selected 10% of the calls.\nvar isEnabled = true;\nvar chaosPolicy = MonkeyPolicy.InjectLatency(with =\u003e\n\twith.Latency(TimeSpan.FromSeconds(5))\n\t\t.InjectionRate(0.1)\n\t\t.Enabled(isEnabled)\n\t);\n```\n\n## Inject behavior\n```csharp\nvar chaosPolicy = MonkeyPolicy.InjectBehaviour(Action\u003cInjectBehaviourOptions\u003e);\n```\nFor example:\n```csharp\n// Following example causes policy to execute a method to restart a virtual machine; the probability that method will be executed is 1% if enabled\nvar chaosPolicy = MonkeyPolicy.InjectBehaviour(with =\u003e\n\twith.Behaviour(() =\u003e restartRedisVM())\n\t\t.InjectionRate(0.01)\n\t\t.EnabledWhen((ctx, ct) =\u003e isEnabled(ctx, ct))\n\t);\n```\n\n## Parameters\nAll the parameters are expressed in a Fluent-builder syntax way.\n\n### Enabled\nDetermines whether the policy is enabled or not.\n\n* Configure that the monkey policy is enabled. \n```csharp\nPolicyOptions.Enabled();\n```\n\n* Receives a boolean value indicating whether the monkey policy is enabled.\n```csharp\nPolicyOptions.Enabled(bool);\n```\n\n* Receives a delegate which can be executed to determine whether the monkey policy should be enabled.\n```csharp\nPolicyOptions.EnabledWhen(Func\u003cContext, CancellationToken, bool\u003e);\n```\n\n### InjectionRate\nA decimal between 0 and 1 inclusive. The policy will inject the fault, randomly, that proportion of the time, eg: if 0.2, twenty percent of calls will be randomly affected; if 0.01, one percent of calls; if 1, all calls. \n\n* Receives a double value between [0, 1] indicating the rate at which this monkey policy should inject chaos.\n```csharp\nPolicyOptions.InjectionRate(Double);\n```\n\n* Receives a delegate which can be executed to determine the rate at which this monkey policy should inject chaos.\n```csharp\nPolicyOptions.InjectionRate(Func\u003cContext, CancellationToken, Double\u003e);\n```\n\n### Fault\nThe fault to inject. The `Fault` api has overloads to build the policy in a generic way: `PolicyOptions.Fault\u003cTResult\u003e(...)`\n\n* Receives an exception to configure the fault to inject with the monkey policy.\n```csharp\nPolicyOptions.Fault(Exception);\n```\n\n* Receives a delegate representing the fault to inject with the monkey policy.\n```csharp\nPolicyOptions.Fault(Func\u003cContext, CancellationToken, Exception\u003e);\n```\n\n### Result\nThe result to inject.\n\n* Receives a generic TResult value to configure the result to inject with the monkey policy.\n```csharp\nPolicyOptions.Result\u003cTResult\u003e(TResult);\n```\n\n* Receives a delegate representing the result to inject with the monkey policy.\n```csharp\nPolicyOptions.Result\u003cTResult\u003e(Func\u003cContext, CancellationToken, TResult\u003e);\n```\n\n### Latency\nThe latency to inject.\n\n* Receives a TimeSpan value to configure the latency to inject with the monkey policy.\n```csharp\nPolicyOptions.Latency(TimeSpan);\n```\n\n* Receives a delegate representing the latency to inject with the monkey policy.\n```csharp\nPolicyOptions.Latency(Func\u003cContext, CancellationToken, TimeSpan\u003e);\n```\n\n### Behaviour\nThe behaviour to inject. \n\n* Receives an Action to configure the behaviour to inject with the monkey policy.\n```csharp\nPolicyOptions.Behaviour(Action);\n```\n\n* Receives a delegate representing the Action to inject with the monkey policy.\n```csharp\nPolicyOptions.Behaviour(Action\u003cContext, CancellationToken\u003e);\n```\n\n### Context-driven behaviour\n\nAll parameters are available in a `Func\u003cContext, ...\u003e` form.  This allows you to control the chaos injected:\n\n+ in a **dynamic** manner: by eg driving the chaos from external configuration files\n+ in a **targeted** manner: by tagging your policy executions with a [`Context.OperationKey`](https://github.com/App-vNext/Polly/wiki/Keys-And-Context-Data#pre-defined-keys-on-context) and introducing chaos targeting particular tagged operations\n\nThe [example app](https://github.com/Polly-Contrib/Polly.Contrib.SimmyDemo_WebApi) demonstrates both these approaches in practice.\n\n\n## Step 2: Execute code through the Monkey Policy\n\n```csharp\n// Executes through the chaos policy directly\nchaosPolicy.Execute(() =\u003e someMethod());\n\n// Executes through the chaos policy using Context\nchaosPolicy.Execute((ctx) =\u003e someMethod(), context);\n\n// Wrap the chaos policy inside other Polly resilience policies, using PolicyWrap\nvar policyWrap = Policy\n  .Wrap(fallbackPolicy, timeoutPolicy, chaosLatencyPolicy);\npolicyWrap.Execute(() =\u003e someMethod())\n\n// All policies are also available in async forms.\nvar chaosLatencyPolicy = MonkeyPolicy.InjectLatencyAsync(with =\u003e\n\twith.Latency(TimeSpan.FromSeconds(5))\n\t\t.InjectionRate(0.1)\n\t\t.Enabled()\n\t);\nvar policyWrap = Policy\n  .WrapAsync(fallbackPolicy, timeoutPolicy, chaosLatencyPolicy);\nvar result = await policyWrap.ExecuteAsync(token =\u003e service.GetFoo(parametersBar, token), myCancellationToken);\n\n// For general information on Polly policy syntax see: https://github.com/App-vNext/Polly\n```\n\nIt is usual to place the Simmy policy innermost in a PolicyWrap. By placing the chaos policies innermost, they subvert the usual outbound call at the last minute, substituting their fault or adding extra latency. The existing Polly policies - further out in the PolicyWrap - still apply, so you can test how the Polly resilience you have configured handles the chaos/faults injected by Simmy.\n\n**Note:** The above examples demonstrate how to execute through a Simmy policy directly, and how to include a Simmy policy in an individual PolicyWrap. If your policies are configured by .NET Core DI at StartUp, for example via HttpClientFactory, there are also patterns which can configure Simmy into your app as a whole, at StartUp. See the Simmy Sample App discussed below.\n\n## Example app: Controlling chaos via configuration and Polly.Context\n\nThis [Simmy sample app](https://github.com/Polly-Contrib/Polly.Contrib.SimmyDemo_WebApi) shows different approaches/patterns for how you can configure Simmy to introduce chaos policies in a project.  Patterns demonstrated are:\n\n* Configuring `StartUp` so that Simmy chaos policies are only introduced in builds for certain environments (for instance, Dev but not Prod).\n* Configuring Simmy chaos policies to be injected into the app without changing any existing Polly configuration code.\n* Injecting faults or chaos by modifying external configuration. \n\nThe patterns shown in the sample app are intended as starting points but are not mandatory.  Simmy is very flexible, and we would love to hear how you use it!\n\n## Wrapping up\n\nAll chaos policies (Monkey policies) are designed to inject behavior randomly (faults, latency or custom behavior), so a Monkey policy allows you to specify an injection rate between 0 and 1 (0-100%) thus, the higher is the injection rate the higher is the probability to inject them. Also it allows you to specify whether or not the random injection is enabled, that way you can release/hold (turn on/off) the monkeys regardless of injection rate you specify, it means, if you specify an injection rate of 100% but you tell to the policy that the random injection is disabled, it will do nothing.\n\n## Further information\n\nSee [Issues](https://github.com/App-vNext/Simmy/issues) for latest discussions on taking Simmy forward!\n\n## Credits\n\nSimmy was [the brainchild of](https://github.com/App-vNext/Polly/issues/499) [@mebjas](https://github.com/mebjas) and [@reisenberger](https://github.com/reisenberger). The major part of the implementation was by [@vany0114](https://github.com/vany0114) and [@mebjas](https://github.com/mebjas), with contributions also from [@reisenberger](https://github.com/reisenberger) of the Polly team.\n\n## Blogs and architecture samples around Simmy\n\n### Blog posts\n* [Simmy, the monkey for making chaos](http://elvanydev.com/chaos-injection-with-simmy/) -by [Geovanny Alzate Sandoval](https://twitter.com/geovany0114)\n* [Simmy and Azure App Configuration](http://elvanydev.com/simmy-with-azure-app-configuration/) -by [Geovanny Alzate Sandoval](https://twitter.com/geovany0114)\n* [Simmy Chaos Engine for .NET – Part 1, Injecting Faults](https://nodogmablog.bryanhogan.net/2019/07/simmy-chaos-engine-for-net-part-1-injecting-faults/) -by [Bryan Hogan](https://twitter.com/bryanjhogan)\n* [Simmy Chaos Engine for .NET – Part 2, Resilience and Injected Faults](https://nodogmablog.bryanhogan.net/2019/07/simmy-chaos-engine-for-net-part-2-resilience-and-injected-faults/) -by [Bryan Hogan](https://twitter.com/bryanjhogan)\n* [Chaos Engineering your .NET applications using Simmy](http://josephwoodward.co.uk/2020/01/chaos-engineering-your-dot-net-application-simmy) -by [Joseph Woodward](https://twitter.com/joe_mighty)\n\n### Samples\n* [Dylan Reisenberger](http://www.thepollyproject.org/author/dylan/) presents an [intentionally simple example](https://github.com/Polly-Contrib/Polly.Contrib.SimmyDemo_WebApi) .NET Core WebAPI app demonstrating how we can set up Simmy chaos policies for certain environments and without changing any existing configuration code injecting faults or chaos by modifying external configuration.\n\n* [Geovanny Alzate Sandoval](https://github.com/vany0114) made a [microservices based sample application](https://github.com/vany0114/chaos-injection-using-simmy) to demonstrate how chaos engineering works with Simmy using chaos policies in a distributed system and how we can inject even a custom behavior given our needs or infrastructure, this time injecting custom behavior to generate chaos in our Service Fabric Cluster.\n\n * [Bjørn Einar Bjartnes](https://github.com/bjartwolf) made a [red-green load-testing resilience workshop](https://github.com/bjartnes/bounded-disturbances) to understand how errors and resiliency mechanisms affect a system under load. It has been used to run workshops at for example [NDC Oslo](https://ndcoslo.com/workshops/building-and-testing-resilient-services/dbb2ed362bcc) and there is a video from the workshop at [DotNext](https://www.youtube.com/watch?v=_UFiaNlfxjI).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPolly-Contrib%2FSimmy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPolly-Contrib%2FSimmy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPolly-Contrib%2FSimmy/lists"}