100 lines
2.8 KiB
Go
100 lines
2.8 KiB
Go
/*
|
|
* Copyright 2022 The Dragonfly Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package resolver
|
|
|
|
import (
|
|
"reflect"
|
|
|
|
"google.golang.org/grpc/grpclog"
|
|
"google.golang.org/grpc/resolver"
|
|
|
|
"d7y.io/dragonfly/v2/client/config"
|
|
)
|
|
|
|
const (
|
|
// SchedulerScheme is the scheduler schema used by resolver.
|
|
SchedulerScheme = "sched"
|
|
)
|
|
|
|
var (
|
|
// SchedulerVirtualTarget is scheduler virtual target.
|
|
SchedulerVirtualTarget = SchedulerScheme + "://localhost"
|
|
)
|
|
|
|
var plogger = grpclog.Component("scheduler_resolver")
|
|
|
|
// SchedulerResolver implement resolver.Builder
|
|
type SchedulerResolver struct {
|
|
addrs []resolver.Address
|
|
cc resolver.ClientConn
|
|
dynconfig config.Dynconfig
|
|
}
|
|
|
|
// RegisterScheduler registers the dragonfly resolver builder to the grpc with custom schema.
|
|
func RegisterScheduler(dynconfig config.Dynconfig) {
|
|
resolver.Register(&SchedulerResolver{dynconfig: dynconfig})
|
|
}
|
|
|
|
// Scheme returns the resolver scheme.
|
|
func (r *SchedulerResolver) Scheme() string {
|
|
return SchedulerScheme
|
|
}
|
|
|
|
// Build creates a new resolver for the given target.
|
|
//
|
|
// gRPC dial calls Build synchronously, and fails if the returned error is
|
|
// not nil.
|
|
func (r *SchedulerResolver) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
|
|
r.cc = cc
|
|
r.dynconfig.Register(r)
|
|
r.ResolveNow(resolver.ResolveNowOptions{})
|
|
return r, nil
|
|
}
|
|
|
|
// ResolveNow will be called by gRPC to try to resolve the target name again.
|
|
// gRPC will trigger resolveNow everytime SubConn connect fail. But we only need
|
|
// to refresh addresses from manager when all SubConn fail.
|
|
// So here we don't trigger resolving to reduce the pressure of manager.
|
|
func (r *SchedulerResolver) ResolveNow(resolver.ResolveNowOptions) {
|
|
addrs, err := r.dynconfig.GetResolveSchedulerAddrs()
|
|
if err != nil {
|
|
plogger.Errorf("resolve addresses error %v", err)
|
|
return
|
|
}
|
|
|
|
if reflect.DeepEqual(r.addrs, addrs) {
|
|
return
|
|
}
|
|
r.addrs = addrs
|
|
|
|
if err := r.cc.UpdateState(resolver.State{
|
|
Addresses: addrs,
|
|
}); err != nil {
|
|
plogger.Errorf("resolver update ClientConn error %v", err)
|
|
}
|
|
}
|
|
|
|
// Close closes the resolver.
|
|
func (r *SchedulerResolver) Close() {
|
|
r.dynconfig.Deregister(r)
|
|
}
|
|
|
|
// OnNotify is triggered and resolver address is updated.
|
|
func (r *SchedulerResolver) OnNotify(data *config.DynconfigData) {
|
|
r.ResolveNow(resolver.ResolveNowOptions{})
|
|
}
|