mirror of https://github.com/linkerd/linkerd2.git
GetProfiles should always respond with a (possibly empty) profile immediately (#2146)
When `GetProfiles` is called for a destination that does not have a service profile, the proxy-api service does not return any messages until a service profile is created for that service. This can be interpreted as hanging, and can make it difficult to calculate response latency metrics. Change the behavior of the API to always return a service profile message immediately. If the service does not have a service profile, the default service profile is returned. Signed-off-by: Alex Leong <alex@buoyant.io>
This commit is contained in:
parent
3a5d506004
commit
d542571b65
|
@ -40,12 +40,14 @@ func (l *profileListener) Stop() {
|
|||
}
|
||||
|
||||
func (l *profileListener) Update(profile *sp.ServiceProfile) {
|
||||
if profile != nil {
|
||||
destinationProfile, err := profiles.ToServiceProfile(&profile.Spec)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
l.stream.Send(destinationProfile)
|
||||
if profile == nil {
|
||||
l.stream.Send(&profiles.DefaultServiceProfile)
|
||||
return
|
||||
}
|
||||
destinationProfile, err := profiles.ToServiceProfile(&profile.Spec)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
return
|
||||
}
|
||||
l.stream.Send(destinationProfile)
|
||||
}
|
||||
|
|
|
@ -177,6 +177,11 @@ var (
|
|||
RetryBudget: &profiles.DefaultRetryBudget,
|
||||
}
|
||||
|
||||
defaultPbProfile = &pb.DestinationProfile{
|
||||
Routes: []*pb.Route{},
|
||||
RetryBudget: &profiles.DefaultRetryBudget,
|
||||
}
|
||||
|
||||
multipleRequestMatches = &sp.ServiceProfile{
|
||||
Spec: sp.ServiceProfileSpec{
|
||||
Routes: []*sp.RouteSpec{
|
||||
|
@ -521,4 +526,23 @@ func TestProfileListener(t *testing.T) {
|
|||
t.Fatalf("Expected function to be completed after the cancel()")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Sends empty update", func(t *testing.T) {
|
||||
mockGetProfileServer := &mockDestinationGetProfileServer{profilesReceived: []*pb.DestinationProfile{}}
|
||||
|
||||
listener := &profileListener{
|
||||
stream: mockGetProfileServer,
|
||||
}
|
||||
|
||||
listener.Update(nil)
|
||||
|
||||
numProfiles := len(mockGetProfileServer.profilesReceived)
|
||||
if numProfiles != 1 {
|
||||
t.Fatalf("Expecting [1] profile, got [%d]. Updates: %v", numProfiles, mockGetProfileServer.profilesReceived)
|
||||
}
|
||||
actualPbProfile := mockGetProfileServer.profilesReceived[0]
|
||||
if !reflect.DeepEqual(actualPbProfile, defaultPbProfile) {
|
||||
t.Fatalf("Expected profile sent to be [%v] but was [%v]", defaultPbProfile, actualPbProfile)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -20,14 +20,21 @@ type profileTemplateConfig struct {
|
|||
ClusterZone string
|
||||
}
|
||||
|
||||
// DefaultRetryBudget is used for routes which do not specify one.
|
||||
var DefaultRetryBudget = pb.RetryBudget{
|
||||
MinRetriesPerSecond: 10,
|
||||
RetryRatio: 0.2,
|
||||
Ttl: &duration.Duration{
|
||||
Seconds: 10,
|
||||
},
|
||||
}
|
||||
var (
|
||||
// DefaultRetryBudget is used for routes which do not specify one.
|
||||
DefaultRetryBudget = pb.RetryBudget{
|
||||
MinRetriesPerSecond: 10,
|
||||
RetryRatio: 0.2,
|
||||
Ttl: &duration.Duration{
|
||||
Seconds: 10,
|
||||
},
|
||||
}
|
||||
// DefaultServiceProfile is used for services with no service profile.
|
||||
DefaultServiceProfile = pb.DestinationProfile{
|
||||
Routes: []*pb.Route{},
|
||||
RetryBudget: &DefaultRetryBudget,
|
||||
}
|
||||
)
|
||||
|
||||
// ToServiceProfile returns a Proxy API DestinationProfile, given a
|
||||
// ServiceProfile.
|
||||
|
|
Loading…
Reference in New Issue