reverse-proxy: LoadBalancingPolicy = First broken in preview 11
Describe the bug
Took us few hours to work this out. We deployed yarp preview 11 to prod for a small service. Worked as expected for 2 hours then service got restarted and yarp started using second destination. Previously this happened if first destination was unhealthy but with preview 11 it is random. This is not a problem with preview 10.
To Reproduce
Create new project and use the configurations below. Then run the https://localhost:5001/todo/v1. You’d have to run this few times by stopping the app and rebuilding it. Sometimes the configurations don’t get cleared until you rebuild the solution in VS (this is a another problem).
Here is my result I ran the project and yarp picked up second destination. If rebuild and re run few times destinations will randomly change.

{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Debug",
"Microsoft.Hosting.Lifetime": "Debug"
}
},
"AllowedHosts": "*",
"ReverseProxy": {
"Routes": {
"Route8": {
"ClusterId": "cluster1",
"Match": {
"Methods": [ "GET" ],
"Path": "/todo/v1"
},
"Transforms": [
{
"PathSet": ""
},
{
"ResponseHeader": "Access-Control-Expose-Headers",
"Append": "IsSuccessful",
"When": "Always"
},
{
"ResponseHeader": "Access-Control-Max-Age",
"Append": "86400",
"When": "Always"
}
]
}
},
"Clusters": {
"cluster1": {
"LoadBalancingPolicy": "First",
"HealthCheck": {
"Passive": {
"Enabled": "true",
"Policy": "TransportFailureRate",
"ReactivationPeriod": "00:01:01"
}
},
"HttpRequest": {
"Timeout": "00:01:00",
"Version": "1.1"
},
"Destinations": {
"cluster1_destination1": {
"Address": "https://jsonplaceholder.typicode.com/todos/1"
},
"cluster2_destination2": {
"Address": "https://jsonplaceholder.typicode.com/todos/2"
}
}
}
}
}
}
Startup
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddReverseProxy().LoadFromConfig(Configuration.GetSection("ReverseProxy"));
services.AddCors(options => options.AddPolicy("EnableCors", builder =>
{
builder.AllowAnyOrigin().SetPreflightMaxAge(TimeSpan.FromSeconds(86400));
builder.AllowAnyMethod().SetPreflightMaxAge(TimeSpan.FromSeconds(86400));
builder.AllowAnyHeader().SetPreflightMaxAge(TimeSpan.FromSeconds(86400));
}));
}
public void Configure(IApplicationBuilder app)
{
//app.UseMiddleware<ExceptionMiddleware>();
app.UseCors("EnableCors");
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapReverseProxy();
});
}
}
Further technical details
- Package Yarp.ReverseProxy - 1.0.0-preview.11.*
- The platform - Windows
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Comments: 17 (13 by maintainers)
I was investigating https://github.com/microsoft/reverse-proxy/issues/83#issuecomment-844565946 which deals with the available destinations list generation and briefly considered introducing sorting there, but First is the only policy proposed so far that depends on a strict ordering.
Proposal: Redefine
Firstfrom meaning “First available destination we find” [O(1)] to meaning “Alphabetically first available destination.” [O(n)]. The implementation would change accordingly fromavailableDestinations[0]to doing a single pass scan through the list to find the first entry by name. This has the benefit of working independent of the rest of the infrastructure, and being deterministic across reloads, adds, removes, etc… Since First is expected to be used with a small number of destinations this change shouldn’t add significant overhead.Thoughts?