Coder Social home page Coder Social logo

polly-contrib / simmy Goto Github PK

View Code? Open in Web Editor NEW
537.0 20.0 25.0 405 KB

Simmy is a chaos-engineering and fault-injection tool, integrating with the Polly resilience project for .NET

License: Other

Batchfile 0.02% C# 99.32% PowerShell 0.66%
chaos-engineering resilience resiliency resilient resilience-testing fault-injection polly-resilience fault-tolerance fault-based-testing fault-tolerant

simmy's People

Contributors

arnaudmaichac avatar bjorn-einar-bjartnes-4ss avatar joelhulen avatar reisenberger avatar vany0114 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

simmy's Issues

are there samples for using simmy with polly v8 constructs?

Hello, I tried to check this out in the slack channel but was not able to get in there. I have been trying to figure out if there are any samples of how to add simmy policies to polly v8 pipelines?

For example, I have created a ResiliencePipelineRegistry and added a Retry and NoOp pipeline to the registry. These items, since they are v8 polly contructs use a ResilienceContext.

Later on down in the code, if my app is in development mode, I try to AddChaosInjectors to the registry using an extension method that should iterate the pipelines in the registry and add MonkeyPolicies dynamically based on configuration values that are stored in the Context.

v7 of Polly uses Context. v8 of Polly uses ResilienceContext. Do the config values added to the ReslienceContext somehow get copied to a Context and should the expectation be that polly v8 can work with ResilienceContext and MonkeyPolices can still use Context?

Its just unclear how to attach MonkeyPolicy to v8 ResiliencePipelines so are there any samples for that or is it just not supported yet.

Create empty solution and projects

Create initial, empty Solution (.sln) and Projects to hold Simmy code.

We should avoid the 'Shared Projects' (.shproj) approach of current Polly, and go straight to the flattened structure exemplified in this PR on Polly. IE Could copy an (empty) structure from there, and just rename everything Polly to Simmy. This is also the MS recommendation for cross-platform targeting

'InjectLatencyAsyncOptions' does not contain a definition for 'Latency'

I'm trying to follow the README's example on using the Latency handler and am receiving this error with the new syntax.

'InjectLatencyAsyncOptions' does not contain a definition for 'Latency' and no accessible extension method 'Latency' accepting a first argument of type 'InjectLatencyAsyncOptions' could be found (are you missing a using directive or an assembly reference?)

Here is my code for reference:

var latencyPolicy = MonkeyPolicy.InjectLatencyAsync<HttpResponseMessage>(with =>
    with.Latency(TimeSpan.FromSeconds(5))
        .InjectionRate(1.0)
        .Enabled(true)
    );

For what it's worth, the obsolete syntax works, though it warns of CS0618 when compiled.

var latencyPolicy = MonkeyPolicy.InjectLatencyAsync<HttpResponseMessage>(TimeSpan.FromSeconds(5), 1.0, () => true);

I am using Polly.Contrib.Simmy version 0.3.0

Feature Proposal - Add callback to be run when chaos is injected

It would be nice to be able to run code when chaos is injected (by any of the simmy injection policies).

Example use-case:

var  chaosExceptionPolicy = MonkeyPolicy
    .InjectExceptionAsync(with => with
        .Fault(new TimeoutException())
        .InjectionRate(0.2)
        .Enabled()
        .OnInject((context, exception, cancellation) => logger.LogInformation("Injecting Chaos"));

Alternative:
Using InjectBehavior rather than InjectException, and throwing the exception myself would also work without changes in Simmy.

Make Latency monkey no cancellable by configuration

Currently, all the monkeys are cancellable, which is fine, but we want to allow the user to make the latency monkey no cancellable for those scenarios where even if a token is signaled, they don't want to cancel the latency.

Proposal: add a new property to LatencyOptions/AyncLatencyOptions like this:

internal Func<Context, CancellationToken, Task<bool>> IsCancellable { get; set; }

Might be true by default, then validate it before to honor the token.

Build frequently fails on second build for PR (clean up build-numbering strategy)

A PR typically builds twice - for the branch and then the PR. The second build often fails with:

========================================
__UpdateAppVeyorBuildNumber
========================================
Executing task: __UpdateAppVeyorBuildNumber
Build with specified version already exists.

The cake build script intends to set the build number from the git metadata FullSemVer and clearly this repeats for the second build.

The following range of git metadata is typically available via the GitVersion tool used by the build (obtained by running GitVersion.exe in the repository root):

{
  "Major":0,
  "Minor":2,
  "Patch":1,
  "PreReleaseTag":"reisenberger-optionsSyntaxNamespace.1",
  "PreReleaseTagWithDash":"-reisenberger-optionsSyntaxNamespace.1",
  "PreReleaseLabel":"reisenberger-optionsSyntaxNamespace",
  "PreReleaseNumber":1,
  "BuildMetaData":14,
  "BuildMetaDataPadded":"0014",
  "FullBuildMetaData":"14.Branch.reisenberger-optionsSyntaxNamespace.Sha.7741373763fbb2a63c08229c6ccb5db99257e2b0",
  "MajorMinorPatch":"0.2.1",
  "SemVer":"0.2.1-reisenberger-optionsSyntaxNamespace.1",
  "LegacySemVer":"0.2.1-reisenberger-option1",
  "LegacySemVerPadded":"0.2.1-reisenberger-opt0001",
  "AssemblySemVer":"0.2.1.0",
  "AssemblySemFileVer":"0.2.1.0",
  "FullSemVer":"0.2.1-reisenberger-optionsSyntaxNamespace.1+14",
  "InformationalVersion":"0.2.1-reisenberger-optionsSyntaxNamespace.1+14.Branch.reisenberger-optionsSyntaxNamespace.Sha.7741373763fbb2a63c08229c6ccb5db99257e2b0",
  "BranchName":"reisenberger-optionsSyntaxNamespace",
  "Sha":"7741373763fbb2a63c08229c6ccb5db99257e2b0",
  "ShortSha":7741373,
  "NuGetVersionV2":"0.2.1-reisenberger-opt0001",
  "NuGetVersion":"0.2.1-reisenberger-opt0001",
  "NuGetPreReleaseTagV2":"reisenberger-opt0001",
  "NuGetPreReleaseTag":"reisenberger-opt0001",
  "CommitsSinceVersionSource":14,
  "CommitsSinceVersionSourcePadded":"0014",
  "CommitDate":"2019-11-30"
}

Suggested resolution

Change that line in the build script to use a more specific metadata like InformationalVersion (if not too long for AppVeyor)

  • The two builds of the PR do have different SHAs - one for the head-of-the-branch commit, one for the merge-commit; confirmed by the event metadata in AppVeyor. So this should provide distinct build numbers.

However, when we deploy releases directly out of AppVeyor, that "Appveyor build number" may also be tagged to the commit and be used as the release number (think that's the case). And InformationalVersion seems overkill for releases ...

So we possibly want something like:

appveyorBuildNumber = gitVersionOutput["BranchName"].ToString() == "master" ? gitVersionOutput["FullSemVer"].ToString() : gitVersionOutput["InformationalVersion"].ToString();

(A suggestion ... open to anyone refining this!)

Consider shorter syntax for result stubbing, for use in unit-tests in other systems on how those systems handle faults

All current overloads are of the form:

MonkeyPolicy.InjectX(/* what to inject */, Double injectionRate, bool enabled) // or similar Func variants for injectionRate and enabled

Unit tests are likely to always want to inject the fault/response (ie injectionRate: 1 and enabled: true). Propose: Add syntax overloads throughout, of the form:

MonkeyPolicy.InjectX(/* what to inject */)

which chain on to injectionRate: 1 and enabled: true.

Timing

Would be nice to have this before launch, as stubbing for unit-tests is a major use case we can advertise, as part of the launch

See also #16 . Makes sense to implement #16 before this.

Consider intuitive syntax for result stubbing, for use in unit-tests in other systems on how those systems handle faults

Alongside chaos-engineering, another significant use-case for Simmy is setting up calls to return stub/fake results, for unit tests.

We already have the functionality, InjectResultImplementation, but all our syntax uses the wording InjectFault.

Not all results one might want to inject, in unit testing, are faults. Success cases are valid to test. A more neutral syntax to support this would be InjectResult, eg:

MonkeyPolicy.InjectResult<HttpResponseMessage>(new HttpResponseMessage(HttpStatusCode.OK))

Proposal I

  • Rename the Fault namespaces to be Outcomes (ie Simmy.Outcomes), in both Simmy and Simmy.Specs,
  • Add files InjectResultSyntax and AsyncInjectResultSyntax, giving various overloads InjectResult<TResult>(...) and InjectResultAsync<TResult>(...)
  • These overloads would be identical to the existing InjectFault<TResult>(...) overloads. To avoid code duplication, likely the InjectResult(...) overloads should be the master code, and InjectFault(...) overloads should simply chain to the corresponding InjectResult(...) overload.

Advantages/disadvantages: Retains existing InjectFault<TResult>(...) syntax, but leaves some minor duplication, as there would be two syntaxes (InjectFault<TResult>(...) and InjectResult<TResult>(...)) which cause identical behaviour. But gives nice-reading syntax for each use case.

Proposal II

  • Rename the Fault namespaces to be Outcomes (ie Simmy.Outcomes), in both Simmy and Simmy.Specs,
  • Rename the existing InjectFault<TResult>(...) overloads to be InjectResult(...).
  • Rename the existing InjectFault(Exception ...) overloads to be InjectException(...).

Advantages/disadvantages: No duplication. Loss of InjectFault(...) syntax.

Timing

Would be nice to have this before launch, as stubbing for unit-tests is a major use case we can advertise, as part of the launch

Consider optimisations of async configuration hotpaths for synchronously-provided results

It seems reasonable that the delegates used to configure async MonkeyPolicy instances allow users to provide an async lambda. This permits users make async calls to consult some config source, for the enabled toggle, the injectionRate, or indeed what Exception, TResult, TimeSpan is going to be injected in fault scenarios. Currently the signatures we provide for such delegates are of the form Func<..., Task<bool>>, Func<..., Task<double>>, Func<..., Task<Exception>>, Func<..., Task<TResult>> etc.

That said, many (perhaps even a majority) usages might be sync. Simmy offers overloads taking constant values. Even for config-driven cases, it might be preferable for looking up the config to be a rapid in-memory check, with new values being pushed into that in-memory store by some other process (callback/monitor) when the underlying config source changes.

We want users to be able to include MonkeyPolicy in prod/whatever systems with minimal perf impact on executions, so want to optimise to minimise allocations and execution time.

Propose: Consider the use of ValueTask<>. Refs;

Implement new syntax

Implement the new syntax to avoid the proliferation of overloads in order to allow Simmy can grow easier and the new features can be added more flexibly avoiding breaking changes and deprecate too much code.

Syntax proposal:

.PolicyType(Action<IPolicyTypeConfiguration>)

Example:

var policy = MonkeyPolicy.InjectLatency(options => 
   {
        options.Latency = TimeSpan.FromMilliseconds(5),
        options.InjectionRate = 0.1,
        options.Enabled = true
   };
);

Add overloads taking CancellationToken, for async configuration-providing delegates

As @martincostello mentions here, given the Simmy API does offer async overloads to obtain configuration values in the async cases, those APIs might want take to a CancellationToken.

We would need to agree what the assumptions should be if cancellation was signalled for a config-obtaining delegate:

  • for delegates returning bool enabled, we would probably have no option but to assume cancellation means we return false
  • for delegates returning injectionRate or Timespan we would probably likewise have no better option than to assume cancellation means the fault-injection operation should default to not injecting the fault

Thoughst?


x-ref: #18 affects same APIs

Unable to catch fault policy exception in Function App

Hi,
I've wrote an sample Azure Function App to start learning about resilient systems using your cool project.

I inject a latency and a fault chaos policy but it seems that the raised exception is swallowed by the function runtime. From these specs I can see that the consumer code should be able to catch the exception.

This is the relevant part of my code:

static class PolicyBuilder
{
    public static Policy CreateLatency() => MonkeyPolicy.InjectLatency(with =>
        with.Latency(TimeSpan.FromSeconds(Settings.Latency.Seconds))
        .InjectionRate(Settings.Latency.InjectionRate)
        .Enabled(Settings.Latency.Enabled));

    public static Policy CreateFault() => MonkeyPolicy.InjectException(with =>
        with.Fault(new Exception("Something gone wrong."))
            .InjectionRate(Settings.Fault.InjectionRate)
            .Enabled(Settings.Fault.Enabled)
        );
}

public class ProductsFunction
{
    readonly ILogger _logger;
    readonly IBackend _backend = new FakeBackend();
    readonly Policy _latencyPolicy = PolicyBuilder.CreateLatency();
    readonly Policy _faultPolicy = PolicyBuilder.CreateFault();

    public ProductsFunction(ILoggerFactory loggerFactory)
    {
        _logger = loggerFactory.CreateLogger($"Acme.{nameof(ProductsFunction)}");
    }

    [FunctionName("ProductsFunction")]
    public Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req)
    {
        _logger.LogInformation($"{nameof(ProductsFunction)} trigger function processed a request.");

        var sku = string.IsNullOrEmpty(req.Query["sku"])
            ? (int?)null
            : Convert.ToInt32(req.Query["sku"]);

        var policyWrap = Policy.Wrap(_latencyPolicy, _faultPolicy);
            
        try {
            var products = policyWrap.ExecuteAndCapture(() => _backend.GetProducts(sku));
            return Task.FromResult<IActionResult>(new OkObjectResult(products));
        }
        catch (Exception e) {
            _logger.LogCritical(e, "Exception"); // breakpoint set here doesn't stop
            return Task.FromResult<IActionResult>(new BadRequestObjectResult(e.Message));
        }
    }
}

As commented in the code the catch block is never executed. Anyway when fault occurs instead of fake data the exception is rendered in JSON (with wrong 200 OK status code):

{
    "outcome": 1,
    "finalException": {
        "ClassName": "System.Exception",
        "Message": "Something gone wrong.",
        "Data": null,
        "InnerException": null,
        "HelpURL": null,
        "StackTraceString": "   at Polly.Contrib.Simmy.MonkeyEngine.InjectExceptionImplementation[TResult](Func`3 action, Context context, CancellationToken cancellationToken, Func`3 injectedException, Func`3 injectionRate, Func`3 enabled)\r\n   at Polly.Contrib.Simmy.Outcomes.InjectOutcomePolicy.Implementation[TResult](Func`3 action, Context context, CancellationToken cancellationToken)\r\n   at Polly.Policy.Execute[TResult](Func`3 action, Context context, CancellationToken cancellationToken)\r\n   at Polly.Wrap.PolicyWrapEngine.<>c__DisplayClass3_0`1.<Implementation>b__0(Context ctx, CancellationToken ct)\r\n   at Polly.Contrib.Simmy.MonkeyEngine.InjectBehaviourImplementation[TResult](Func`3 action, Context context, CancellationToken cancellationToken, Action`2 injectedBehaviour, Func`3 injectionRate, Func`3 enabled)\r\n   at Polly.Contrib.Simmy.Latency.InjectLatencyPolicy.Implementation[TResult](Func`3 action, Context context, CancellationToken cancellationToken)\r\n   at Polly.Policy.Execute[TResult](Func`3 action, Context context, CancellationToken cancellationToken)\r\n   at Polly.Wrap.PolicyWrapEngine.Implementation[TResult](Func`3 func, Context context, CancellationToken cancellationToken, ISyncPolicy outerPolicy, ISyncPolicy innerPolicy)\r\n   at Polly.Wrap.PolicyWrap.Implementation[TResult](Func`3 action, Context context, CancellationToken cancellationToken)\r\n   at Polly.Policy.Execute[TResult](Func`3 action, Context context, CancellationToken cancellationToken)\r\n   at Polly.Policy.ExecuteAndCapture[TResult](Func`3 action, Context context, CancellationToken cancellationToken)",
        "RemoteStackTraceString": null,
        "RemoteStackIndex": 0,
        "ExceptionMethod": null,
        "HResult": -2146233088,
        "Source": "Polly.Contrib.Simmy",
        "WatsonBuckets": null
    },
    "exceptionType": 1,
    "result": null,
    "finalHandledResult": null,
    "faultType": 1,
    "context": {}
}

Any help really appreciated.

Regards,
Giacomo S. S.

Unable to wrap fault policies?

I'm new to C#, Polly and Simmy but after reading all the docs and looking at the samples, I thought I'd try to update the Polly sample to use Simmy to generate failures instead of the custom throttling handler.

I copy/pasted the fault injection samples from https://github.com/Polly-Contrib/Simmy/blob/master/README.md ("Step 1") into ValuesController.cs. I then tried to wrap them together using PolicyWrap() before calling Execute but am getting a compiler error:

Severity Code Description Project File Line Suppression State
Error CS1503 Argument 1: cannot convert from 'Polly.Contrib.Simmy.Fault.InjectOutcomePolicy<System.Net.Sockets.SocketException>' to 'Polly.ISyncPolicy' PollyTestApp C:\src\Polly-Samples\PollyTestApp\Controllers\ValuesController.cs 39 Active

What am I missing? Why can't the fault policy be wrapped like the other policy types?

I forked the Polly-Sample repo and created a PR with my attempted changes which should make figuring out what I'm attempting easier to see:

https://github.com/App-vNext/Polly-Samples/pull/22/files

Decide launch version number

Decide whether we launch Simmy as a semver version number:

  • 0.1 : if we consider 'early' version
  • 0.9 ; if we are holding off a 1.0 at launch, but to indicate we are close to a 1.0 and confident in the product and public API (as feels like we will be)
  • 1.0 : to indicate this is the public API, we are confident in the public API not changing.

For decision as we go over any final clean-up of the code.

Comment welcome.

Create launch ReadMe and/or Wiki

ReadMe

Should:

  • provide brief overview of what the project is
  • how to install it
  • supported targets
  • immediate code examples

See Polly ReadMe for examples.

Wiki

Branching to a wiki can allow us to keep the ReadMe focused, and use a wiki page to deep-dive on any concept/example if it deserves it.

Start wiki when we feel there is critical mass to deserve it.

Changelog

Change log in Changelog.md and Simmy.nuspec files should also be filled out to describe v0.1.0

Add logo

We have an offer from a member of the App-vNext team to create a logo ...

Injected latency should be cancellable

Currently, latency injected by MonkeyPolicy.InjectLatency(...) or MonkeyPolicy.InjectLatencyAsync(...) is not cancellable, in either the sync (1; 2) or async (1; 2) implementations.

Async case

Not allowing cancellation doesn't seem right in the async case. Async APIs of typical systems called through Polly typically support cancellation. By providing a MonkeyPolicy.InjectLatencyAsync(...) that doesn't support cancellation, we don't allow users to test how their production system would respond if there was (say) an extra 20ms latency.

For example, if the call is to some Azure SDK API which accepts a CancellationToken and the user is using an TimeoutPolicyAsync() or their own timing-out CancellationToken, then the call would typically cancel when the token is signalled. To allow users to simulate (in prod; or unit tests) that that behaviour works, the injected latency would want to be cancellable too.

Recommend: Change MonkeyPolicy.InjectLatencyAsync(...) to honour the CancellationToken passed to the .ExecuteAsync(...) call through the policies.

Option (now or later): Add an bool isCancellable parameter to (some) overloads of MonkeyPolicy.InjectLatencyAsync(...), allowing the user choice over whether they are injecting cancellable or non-cancellable latency.

Sync case

The sync case seems opposite. Sync APIs typically don't support cancellation. Therefore, it would be a more realistic simulation for the sync MonkeyPolicy.InjectLatency(...) to not support cancellation, at least by default.

Recommend: Leave MonkeyPolicy.InjectLatency(...) not honouring the CancellationToken passed to the .Execute(...) call through the policies.

Option (now or later): Add an bool isCancellable parameter to (some) overloads of MonkeyPolicy.InjectLatency(...), allowing the user choice over whether they are injecting cancellable or non-cancellable latency.

Bring Simmy code over from the Polly repo

Bring Simmy code over from the Polly repo

Bring exactly the Monkey folders (code, and tests) over from App-vNext/Polly#553 . (Code may not need to be in Monkey sub-folders when part of the Simmy repo.)

After #2. After Polly v7.0 released.

New code will need to take a dependency (stated in nuspec; csprojs) on Polly >= v7.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.