Skip to content

Commit

Permalink
Merge pull request Polly-Contrib#60 from Polly-Contrib/v0_2_1
Browse files Browse the repository at this point in the history
V0.3
  • Loading branch information
vany0114 committed Jan 4, 2020
2 parents 9e7e483 + ff7e3b9 commit ec7cb54
Show file tree
Hide file tree
Showing 75 changed files with 6,899 additions and 96 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ TestResults
*.sln.docstates
.vs/
.vscode/
.idea

# Build results
[Dd]ebug/
Expand Down Expand Up @@ -118,4 +119,4 @@ tools

*.lock.json
*.nuget.targets
*.nuget.props
*.nuget.props
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 0.3.0
- Add a new Fluent-builder syntax
- Add intuitive syntax for result stubbing, for use in unit-tests or in other systems on how those systems handle faults
- Compiles on mac and linux
- Add support for .NET Standard 2.1
- Validates constant `injectionRate` at Policy configuration time

## 0.2.0
- Makes InjectLatency policies cancellable (both sync and async)
- Add support for cancellation on async configuration-providing delegates
Expand Down
2 changes: 1 addition & 1 deletion GitVersionConfig.yaml
Original file line number Diff line number Diff line change
@@ -1 +1 @@
next-version: 0.2.0
next-version: 0.3.0
183 changes: 129 additions & 54 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,94 +34,169 @@ Simmy offers the following chaos-injection policies:

|Policy| What does the policy do?|
| ------------- |------------- |
|**[Fault](#Inject-fault)**|Injects exceptions or substitute results, to fake faults in your system.|
|**[Exception](#Inject-exception)**|Injects exceptions in your system.|
|**[Result](#Inject-result)**|Substitute results to fake faults in your system.|
|**[Latency](#Inject-latency)**|Injects latency into executions before the calls are made.|
|**[Behavior](#Inject-behavior)**|Allows you to inject _any_ extra behaviour, before a call is placed. |

# Usage
## Step 1: Set up the Monkey Policy

## Inject exception
```csharp
var chaosPolicy = MonkeyPolicy.InjectException(Action<InjectOutcomeOptions<Exception>>);
```
For example:
```csharp
// Following example causes the policy to throw SocketException with a probability of 5% if enabled
var fault = new SocketException(errorCode: 10013);
var chaosPolicy = MonkeyPolicy.InjectException(with =>
with.Fault(fault)
.InjectionRate(0.05)
.Enabled()
);
```

## Inject fault
## Inject result
```csharp
var chaosPolicy = MonkeyPolicy.InjectFault(
Exception | Func<Context, CancellationToken, Exception> fault,
double | Func<Context, CancellationToken, double> injectionRate,
Func<bool> | Func<Context, CancellationToken, bool> enabled
var chaosPolicy = MonkeyPolicy.InjectResult(Action<InjectOutcomeOptions<TResult>>);
```
For example:
```csharp
// Following example causes the policy to return a bad request HttpResponseMessage with a probability of 5% if enabled
var result = new HttpResponseMessage(HttpStatusCode.BadRequest);
var chaosPolicy = MonkeyPolicy.InjectResult<HttpResponseMessage>(with =>
with.Result(result)
.InjectionRate(0.05)
.Enabled()
);
```

## Inject latency
```csharp
var chaosPolicy = MonkeyPolicy.InjectLatency(
TimeSpan | Func<Context, CancellationToken, Timespan> latency,
double | Func<Context, CancellationToken, double> injectionRate,
Func<bool> | Func<Context, CancellationToken, bool> enabled
);
var chaosPolicy = MonkeyPolicy.InjectLatency(Action<InjectLatencyOptions>);
```
For example:
```csharp
// Following example causes policy to introduce an added latency of 5 seconds to a randomly-selected 10% of the calls.
var isEnabled = true;
var chaosPolicy = MonkeyPolicy.InjectLatency(with =>
with.Latency(TimeSpan.FromSeconds(5))
.InjectionRate(0.1)
.Enabled(isEnabled)
);
```

## Inject behavior
```csharp
var chaosPolicy = MonkeyPolicy.InjectBehaviour(
Action | Action<Context, CancellationToken> behaviour,
double | Func<Context, CancellationToken, double> injectionRate,
Func<bool> | Func<Context, CancellationToken, bool> enabled
);
var chaosPolicy = MonkeyPolicy.InjectBehaviour(Action<InjectBehaviourOptions>);
```
For example:
```csharp
// Following example causes policy to execute a method to restart a virtual machine; the probability that method will be executed is 1% if enabled
var chaosPolicy = MonkeyPolicy.InjectBehaviour(with =>
with.Behaviour(() => restartRedisVM())
.InjectionRate(0.01)
.EnabledWhen((ctx, ct) => isEnabled(ctx, ct))
);
```

## Parameters
All the parameters are expressed in a Fluent-builder syntax way.

* **enabled:** Faults are only injected when returns true.
* **injectionRate:** A 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.
* **fault:** The fault to inject.
* **latency:** The latency to inject.
* **behaviour:** The behaviour to inject.
### Enabled
Determines whether the policy is enabled or not.

### Context-driven behaviour
* Configure that the monkey policy is enabled.
```csharp
PolicyOptions.Enabled();
```

All parameters are available in a `Func<Context, ...>` form. This allows you to control the chaos injected:
* Receives a boolean value indicating whether the monkey policy is enabled.
```csharp
PolicyOptions.Enabled(bool);
```

+ in a **dynamic** manner: by eg driving the chaos from external configuration files
+ 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
* Receives a delegate which can be executed to determine whether the monkey policy should be enabled.
```csharp
PolicyOptions.EnabledWhen(Func<Context, CancellationToken, bool>);
```

The [example app](https://github.com/Polly-Contrib/Polly.Contrib.SimmyDemo_WebApi) demonstrates both these approaches in practice.
### InjectionRate
A 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.

# Basic examples
* Receives a double value between [0, 1] indicating the rate at which this monkey policy should inject chaos.
```csharp
PolicyOptions.InjectionRate(Double);
```

## Step 1: Set up the Monkey Policy
* Receives a delegate which can be executed to determine the rate at which this monkey policy should inject chaos.
```csharp
PolicyOptions.InjectionRate(Func<Context, CancellationToken, Double>);
```

### Fault
The fault to inject. The `Fault` api has overloads to build the policy in a generic way: `PolicyOptions.Fault<TResult>(...)`

* Receives an exception to configure the fault to inject with the monkey policy.
```csharp
// Following example causes the policy to throw SocketException with a probability of 5% if enabled
var fault = new SocketException(errorCode: 10013);
var faultPolicy = MonkeyPolicy.InjectFault<SocketException>(
fault,
injectionRate: 0.05,
enabled: () => isEnabled()
);
PolicyOptions.Fault(Exception);
```

* Receives a delegate representing the fault to inject with the monkey policy.
```csharp
PolicyOptions.Fault(Func<Context, CancellationToken, Exception>);
```

### Result
The result to inject.

* Receives a generic TResult value to configure the result to inject with the monkey policy.
```csharp
PolicyOptions.Result<TResult>(TResult);
```

* Receives a delegate representing the result to inject with the monkey policy.
```csharp
PolicyOptions.Result<TResult>(Func<Context, CancellationToken, TResult>);
```

### Latency
The latency to inject.

* Receives a TimeSpan value to configure the latency to inject with the monkey policy.
```csharp
PolicyOptions.Latency(TimeSpan);
```

// Following example causes policy to introduce an added latency of 5 seconds to a randomly-selected 10% of the calls.
var chaosPolicy = MonkeyPolicy.InjectLatency(
latency: TimeSpan.FromSeconds(5),
injectionRate: 0.1,
enabled: () => isEnabled()
);
* Receives a delegate representing the latency to inject with the monkey policy.
```csharp
PolicyOptions.Latency(Func<Context, CancellationToken, TimeSpan>);
```

### Behavior
### Behaviour
The behaviour to inject.

* Receives an Action to configure the behaviour to inject with the monkey policy.
```csharp
// Following example causes policy to execute a method to restart a virtual machine; the probability that method will be executed is 1% if enabled
var chaosPolicy = MonkeyPolicy.InjectBehaviour(
behaviour: () => restartRedisVM(),
injectionRate: 0.01,
enabled: () => isEnabled()
);
PolicyOptions.Behaviour(Action);
```

* Receives a delegate representing the Action to inject with the monkey policy.
```csharp
PolicyOptions.Behaviour(Action<Context, CancellationToken>);
```

### Context-driven behaviour

All parameters are available in a `Func<Context, ...>` form. This allows you to control the chaos injected:

+ in a **dynamic** manner: by eg driving the chaos from external configuration files
+ 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

The [example app](https://github.com/Polly-Contrib/Polly.Contrib.SimmyDemo_WebApi) demonstrates both these approaches in practice.


## Step 2: Execute code through the Monkey Policy

```csharp
Expand All @@ -137,10 +212,10 @@ var policyWrap = Policy
policyWrap.Execute(() => someMethod())

// All policies are also available in async forms.
var chaosLatencyPolicy = MonkeyPolicy.InjectLatencyAsync(
latency: TimeSpan.FromSeconds(5),
injectionRate: 0.1,
enabled: () => isEnabled()
var chaosLatencyPolicy = MonkeyPolicy.InjectLatencyAsync(with =>
with.Latency(TimeSpan.FromSeconds(5))
.InjectionRate(0.1)
.Enabled()
);
var policyWrap = Policy
.WrapAsync(fallbackPolicy, timeoutPolicy, chaosLatencyPolicy);
Expand Down Expand Up @@ -180,10 +255,10 @@ Simmy was [the brainchild of](https://github.com/App-vNext/Polly/issues/499) [@m
### Blog posts
* [Simmy, the monkey for making chaos](http://elvanydev.com/chaos-injection-with-simmy/) -by [Geovanny Alzate Sandoval](https://twitter.com/geovany0114)
* [Simmy and Azure App Configuration](http://elvanydev.com/simmy-with-azure-app-configuration/) -by [Geovanny Alzate Sandoval](https://twitter.com/geovany0114)
* [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)
* [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)
* [Simmy series on No Dogma blog](https://nodogmablog.bryanhogan.net/tag/simmy/) -by [Bryan Hogan](https://twitter.com/bryanjhogan)

### Samples
* [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.

* [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.

2 changes: 1 addition & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
os: Visual Studio 2017
os: Visual Studio 2019

# Build script
build_script:
Expand Down
10 changes: 5 additions & 5 deletions build.cake
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ var configuration = Argument<string>("configuration", "Release");
// EXTERNAL NUGET TOOLS
//////////////////////////////////////////////////////////////////////

#Tool "xunit.runner.console"
#Tool "GitVersion.CommandLine"
#Tool "Brutal.Dev.StrongNameSigner"
#tool nuget:?package=xunit.runner.console&version=2.4.1
#tool nuget:?package=GitVersion.CommandLine&version=5.0.1
#tool nuget:?package=Brutal.Dev.StrongNameSigner&version=2.4.0

//////////////////////////////////////////////////////////////////////
// EXTERNAL NUGET LIBRARIES
//////////////////////////////////////////////////////////////////////

#addin "Cake.FileHelpers"
#addin nuget:?package=Cake.FileHelpers&version=3.2.1

///////////////////////////////////////////////////////////////////////////////
// GLOBAL VARIABLES
Expand Down Expand Up @@ -192,7 +192,7 @@ Task("__BuildSolutions")
settings
.SetConfiguration(configuration)
.WithProperty("TreatWarningsAsErrors", "true")
.UseToolVersion(MSBuildToolVersion.VS2017)
.UseToolVersion(MSBuildToolVersion.VS2019)
.SetVerbosity(Verbosity.Minimal)
.SetNodeReuse(false));
}
Expand Down
2 changes: 1 addition & 1 deletion build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ if(-Not $SkipToolPackageRestore.IsPresent)
# Install just Cake if missing config
else
{
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install Cake -Version 0.25.0 -ExcludeVersion" # Pin Cake version to 0.25.0; see https://github.com/App-vNext/Polly/issues/416
$NuGetOutput = Invoke-Expression "&`"$NUGET_EXE`" install Cake -Version 0.35.0 -ExcludeVersion"
Write-Verbose ($NuGetOutput | Out-String)
}
Pop-Location
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
namespace Polly.Contrib.Simmy.Specs.Behavior
{
[Collection(Helpers.Constants.AmbientContextDependentTestCollection)]
[Obsolete]
public class InjectBehaviourAsyncSpecs : IDisposable
{
public InjectBehaviourAsyncSpecs()
Expand Down
Loading

0 comments on commit ec7cb54

Please sign in to comment.