grpc / grpc/grpc-dotnet

When to call Resolver.Refresh?

Open
#2,351 1 comment 0 reactions 0 assignees View on GitHub
question
Dominant language
C#
Stars
4.5k
Forks
835
Avg merge
6d 3h
Merged PRs (30d)
7

Description

I was recently experimenting with use of a [custom resolver](https://learn.microsoft.com/en-us/aspnet/core/grpc/loadbalancing?view=aspnetcore-8.0#write-custom-resolvers-and-load-balancers) for a use case I have where our grpc services can change addresses as they are stopped/started. We currently have a bunch of try/catch/reresolve/retry code littered around our clients because of this, and I was hoping this feature might tidy this up and better centralize the logic.

My initial attempt at implementing a custom resolver with the default load balancing strategy worked almost exactly like I wanted. The only problem is that currently the load balancer seems to be responsible for calling `Resolver.Refresh` unless you kick off a periodic refresh via a timer or something like that. That's fine except that the `PickFirstBalancer` calls [RefreshResolver](https://github.com/grpc/grpc-dotnet/blob/371d74fc95da5e16f74b42f3177e179b201e56fb/src/Grpc.Net.Client/Balancer/PickFirstBalancer.cs#L135) when the subchannel moves to the `Idle` state. This was a little surprising to me since I thought it would have made more sense to delay this until moving back to the `Connecting` state. Because of this, the custom resolver doesn't really help me unless I also:
- Write a custom load balancer so I can refresh the address when reconnecting the channel instead of when the channel goes idle. This is doable but seems like a waste since I basically end up forking the implementation of the `PickFirstBalancer`. I couldn't find any way to customize the behavior, and the class is `internal` and `sealed` so I can't derive from it or instantiate it so I can wrap it and forward calls to it.
- Add a timer that continuously runs and makes refresh calls at some interval similar to `DnsResolver`. This isn't ideal since it's difficult to pick an interval that doesn't seem like it's flooding the resolution server unnecessarily and yet seems responsive from the client side.

So I guess the question is if there is a better way to about this that I'm not seeing? Is there a reason refresh is called from `Idle` rather than `Connecting`? I'm sure there must be, but it's not immediately obvious to me. I'm not sure if moving the call to `Idle` might present challenges with not resolving twice upon initial connection for the channel as opposed to reconnecting after going idle.

Contributor guide

Open the contributing guide

Research direction

Start with src/Grpc.Net.Client/Balancer/PickFirstBalancer.cs, especially RefreshResolver and the subchannel Idle and Connecting transitions, then review the custom resolver and load-balancer guidance linked in the issue. Determine whether refresh timing should be configurable or changed, and define the expected behavior for initial connection and reconnection.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
api, networking
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.