Giter VIP home page Giter VIP 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 Introduction

Simmy

Simmy is a chaos-engineering and fault-injection tool, integrating with the Polly resilience project for .NET. It is releasing April 2019 and works with Polly v7.0.0 onwards.

Simmy allows you to introduce a chaos-injection policy or policies at any location where you execute code through Polly.

NuGet version Build status Slack Status

Simmy

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

What do I need, to simulate chaotic scenarios in my production environment?

  • A way to mock 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.
  • Production grade, to run this in a production or near-production system with automation.

Chaos policies

Simmy offers the following chaos-injection policies:

Policy What does the policy do?
Exception Injects exceptions in your system.
Result Substitute results to fake faults in your system.
Latency Injects latency into executions before the calls are made.
Behavior Allows you to inject any extra behaviour, before a call is placed.

Usage

Step 1: Set up the Monkey Policy

Inject exception

var chaosPolicy = MonkeyPolicy.InjectException(Action<InjectOutcomeOptions<Exception>>);

For example:

// 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 result

var chaosPolicy = MonkeyPolicy.InjectResult(Action<InjectOutcomeOptions<TResult>>);

For example:

// 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

var chaosPolicy = MonkeyPolicy.InjectLatency(Action<InjectLatencyOptions>);

For example:

// 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

var chaosPolicy = MonkeyPolicy.InjectBehaviour(Action<InjectBehaviourOptions>);

For example:

// 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

Determines whether the policy is enabled or not.

  • Configure that the monkey policy is enabled.
PolicyOptions.Enabled();
  • Receives a boolean value indicating whether the monkey policy is enabled.
PolicyOptions.Enabled(bool);
  • Receives a delegate which can be executed to determine whether the monkey policy should be enabled.
PolicyOptions.EnabledWhen(Func<Context, CancellationToken, bool>);

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.

  • Receives a double value between [0, 1] indicating the rate at which this monkey policy should inject chaos.
PolicyOptions.InjectionRate(Double);
  • Receives a delegate which can be executed to determine the rate at which this monkey policy should inject chaos.
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.
PolicyOptions.Fault(Exception);
  • Receives a delegate representing the fault to inject with the monkey policy.
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.
PolicyOptions.Result<TResult>(TResult);
  • Receives a delegate representing the result to inject with the monkey policy.
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.
PolicyOptions.Latency(TimeSpan);
  • Receives a delegate representing the latency to inject with the monkey policy.
PolicyOptions.Latency(Func<Context, CancellationToken, TimeSpan>);

Behaviour

The behaviour to inject.

  • Receives an Action to configure the behaviour to inject with the monkey policy.
PolicyOptions.Behaviour(Action);
  • Receives a delegate representing the Action to inject with the monkey policy.
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 and introducing chaos targeting particular tagged operations

The example app demonstrates both these approaches in practice.

Step 2: Execute code through the Monkey Policy

// Executes through the chaos policy directly
chaosPolicy.Execute(() => someMethod());

// Executes through the chaos policy using Context
chaosPolicy.Execute((ctx) => someMethod(), context);

// Wrap the chaos policy inside other Polly resilience policies, using PolicyWrap
var policyWrap = Policy
  .Wrap(fallbackPolicy, timeoutPolicy, chaosLatencyPolicy);
policyWrap.Execute(() => someMethod())

// All policies are also available in async forms.
var chaosLatencyPolicy = MonkeyPolicy.InjectLatencyAsync(with =>
	with.Latency(TimeSpan.FromSeconds(5))
		.InjectionRate(0.1)
		.Enabled()
	);
var policyWrap = Policy
  .WrapAsync(fallbackPolicy, timeoutPolicy, chaosLatencyPolicy);
var result = await policyWrap.ExecuteAsync(token => service.GetFoo(parametersBar, token), myCancellationToken);

// For general information on Polly policy syntax see: https://github.com/App-vNext/Polly

It 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.

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.

Example app: Controlling chaos via configuration and Polly.Context

This Simmy sample app shows different approaches/patterns for how you can configure Simmy to introduce chaos policies in a project. Patterns demonstrated are:

  • Configuring StartUp so that Simmy chaos policies are only introduced in builds for certain environments (for instance, Dev but not Prod).
  • Configuring Simmy chaos policies to be injected into the app without changing any existing Polly configuration code.
  • Injecting faults or chaos by modifying external configuration.

The 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!

Wrapping up

All 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.

Further information

See Issues for latest discussions on taking Simmy forward!

Credits

Simmy was the brainchild of @mebjas and @reisenberger. The major part of the implementation was by @vany0114 and @mebjas, with contributions also from @reisenberger of the Polly team.

Blogs and architecture samples around Simmy

Blog posts

Samples

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

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.

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.

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.

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.

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.

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

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.

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

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 logo

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

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

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 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;

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

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

'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

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.