Dzidek.Net.Yarp.RollingUpgrades 7.0.4

dotnet add package Dzidek.Net.Yarp.RollingUpgrades --version 7.0.4
NuGet\Install-Package Dzidek.Net.Yarp.RollingUpgrades -Version 7.0.4
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Dzidek.Net.Yarp.RollingUpgrades" Version="7.0.4" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Dzidek.Net.Yarp.RollingUpgrades --version 7.0.4
#r "nuget: Dzidek.Net.Yarp.RollingUpgrades, 7.0.4"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Dzidek.Net.Yarp.RollingUpgrades as a Cake Addin
#addin nuget:?package=Dzidek.Net.Yarp.RollingUpgrades&version=7.0.4

// Install Dzidek.Net.Yarp.RollingUpgrades as a Cake Tool
#tool nuget:?package=Dzidek.Net.Yarp.RollingUpgrades&version=7.0.4

Simple rolling upgrades and AB tests with scheduler

Yarp Rolling Upgrades is an extendable and easy-to-use extension for scheduled upgrades or AB test

Basic usage

Install Yarp.ReverseProxy with NuGet

Add to Program.cs Yarp and load config from appsettings file. Yarp documentation

builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
...
app.MapReverseProxy();

Install Dzidek.Net.Yarp.RollingUpgrades with NuGet

Replace

app.MapReverseProxy();

with

app.MapReverseProxy(proxyPipeline => { proxyPipeline.UseRollingUpgrades(new RollingUpgradesRules()); });

Create class RollingUpgradesRules with rolling upgrades configuration. This configuration can be static or dynamic from a file or database or whenever you want

internal sealed class RollingUpgradesRules : IRollingUpgradesRulesQuery
{
    public IEnumerable<RollingUpgradesRule> GetRules()
    {
        return new List<RollingUpgradesRule>()
        {
            new RollingUpgradesRule("ApiRoute", "Api2", new HeaderRule("TenantId", "1"))
        };
    }
}

Defined rules

  • BasicRule
    • AllRule - all request will be directed to defined cluster
    new AllRule()
    
    • CookieRule - request with contains cookie with defined value will be directed to defined cluster
    new CookieRule("CookieName", "CookieValue");
    
    • HeaderRule - request with contains header with defined value will be directed to defined cluster
    new HeaderRule("HeaderName", "HeaderValue");
    
    • UrlContainsRule - request with contains in url defined value will be directed to defined cluster
    new UrlContainsRule("UrlValue");
    
  • ScheduledRules - rules with allow to plan and defer changing about changing cluster. DateFrom, DateTo describe when rule is valid
    • AllRule - all request will be directed to defined cluster
    new AllRule(DateFrom, DateTo)
    
    • CookieRule - request with contains cookie with defined value will be directed to defined cluster
    new CookieRule("CookieName", "CookieValue", DateFrom, DateTo);
    
    • HeaderRule - request with contains header with defined value will be directed to defined cluster
    new HeaderRule("HeaderName", "HeaderValue", DateFrom, DateTo);
    
    • UrlContainsRule - request with contains in url defined value will be directed to defined cluster
    new UrlContainsRule("UrlValue", DateFrom, DateTo);
    

Example and testing environment

In the repository, there is a working docker-compose environment with a proxy and 2 clusters of API, with an easy way to upgrade API on the fly.

Project RollingUpgrade.Proxy contains the implementation of Yarp and Yarp.RollingUpgrades (configured to send a request to Api2 cluster when HTTP request header contains tenantId header with value 1). The proxy is running on port: 8000

Project RollingUpgrade.Api contains TestController with the get method which returns an integer

Project docker-compose can instantiate one proxy and 2 API instances in different clusters

To test you should download this repository and run:

docker-compose up -d --build

Next, you can check what you get calling API (it should return 1 in both cases)

curl http://localhost:8000/Test -H "TenantId: 1"
curl http://localhost:8000/Test -H "TenantId: 2"

Next, you should change the return value from 1 to whatever you want in the TestController file in RollingUpgrade.Api project

[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
    [HttpGet]
    public Task<int> Get()
    {
        return Task.FromResult(2);
    }
}

Next, you should upgrade only Api2 instance

docker-compose up -d --build rollingupgrade.api2

And check now what you get for different TenantId headers (for tenantId 1 you should get 2 instead of 1)

curl http://localhost:8000/Test -H "TenantId: 1"
curl http://localhost:8000/Test -H "TenantId: 2"

Create your own rolling upgrade rule

you have to implement the abstract class RuleBase with the method IsValid

public class CustomRule : RuleBase
{
    private readonly string _headerName1;
    private readonly string _headerValue1;
    private readonly string _headerName2;
    private readonly string _headerValue2;

    public CustomRule(string headerName1, string headerValue1, string headerName2, string headerValue2)
    {
        _headerName1 = headerName1;
        _headerValue1 = headerValue1;
        _headerName2 = headerName2;
        _headerValue2 = headerValue2;
    }

    public override bool IsValid(IClusterChooserHttpContext httpContext)
    {
        return httpContext.Headers.ContainsKey(_headerName1) && httpContext.Headers[_headerName1].Contains(_headerValue1)
            && httpContext.Headers.ContainsKey(_headerName2) && httpContext.Headers[_headerName2].Contains(_headerValue2);
    }
}

and yours it in the same way as predefined RuleBase

internal sealed class RollingUpgradesRules : IRollingUpgradesRulesQuery
{
    public IEnumerable<RollingUpgradesRule> GetRules()
    {
        return new List<RollingUpgradesRule>()
        {
            new RollingUpgradesRule("ApiRoute", "Api2", new CustomRule("TenantId", "1", "OtherHeader", "1"))
        };
    }
}

and that's it 😃

You can check it by doing the same steps as in 'Example and testing environment' but add an extra header in the curl request

curl http://localhost:8000/Test -H "TenantId: 1" -H "OtherHeader: 1"

HttpContext properties allowed in rules

public interface IClusterChooserHttpContext
{
    string Url { get; }
    string Method { get; }
    IDictionary<string, StringValues> Headers { get; }
    IEnumerable<KeyValuePair<string, string>> Cookies { get; }
    IEnumerable<KeyValuePair<string, StringValues>> Query { get; }
}

Changelog

  • 7.0.4 and 6.0.4
    • Error fix
  • 7.0.3 and 6.0.3
    • Add scheduler
    • Changing cluster only when at least one destination is healthy (if configured health check in yarp)
    • Extended allowed properties from HttpContext in rules

Roadmap

  • Add extension allow to configure rolling upgrades from API (API request allowed from localhost)
  • Load last configuration from saved file in API extension

Versioning policy

The project major version will be the same as the DotNetCore version

Nuget

Dzidek.Net.Yarp.RollingUpgrades

Authors

License

MIT

Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
7.0.4 308 1/14/2023
7.0.3 295 1/14/2023
7.0.2 271 1/13/2023
7.0.1 255 1/13/2023
7.0.0 264 1/13/2023
6.0.4 278 1/14/2023
6.0.3 304 1/14/2023
6.0.1 262 1/13/2023
6.0.0 253 1/13/2023