|
|
|
package serverinterceptors
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"github.com/zeromicro/go-zero/core/load"
|
|
|
|
"github.com/zeromicro/go-zero/core/stat"
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
"google.golang.org/grpc/codes"
|
|
|
|
"google.golang.org/grpc/status"
|
|
|
|
)
|
|
|
|
|
|
|
|
const serviceType = "rpc"
|
|
|
|
|
|
|
|
var (
|
|
|
|
sheddingStat *load.SheddingStat
|
|
|
|
lock sync.Mutex
|
|
|
|
)
|
|
|
|
|
|
|
|
// UnarySheddingInterceptor returns a func that does load shedding on processing unary requests.
|
|
|
|
func UnarySheddingInterceptor(shedder load.Shedder, metrics *stat.Metrics) grpc.UnaryServerInterceptor {
|
|
|
|
ensureSheddingStat()
|
|
|
|
|
|
|
|
return func(ctx context.Context, req any, info *grpc.UnaryServerInfo,
|
|
|
|
handler grpc.UnaryHandler) (val any, err error) {
|
|
|
|
sheddingStat.IncrementTotal()
|
|
|
|
var promise load.Promise
|
|
|
|
promise, err = shedder.Allow()
|
|
|
|
if err != nil {
|
|
|
|
metrics.AddDrop()
|
|
|
|
sheddingStat.IncrementDrop()
|
|
|
|
err = status.Error(codes.ResourceExhausted, err.Error())
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
defer func() {
|
|
|
|
if errors.Is(err, context.DeadlineExceeded) {
|
|
|
|
promise.Fail()
|
|
|
|
} else {
|
|
|
|
sheddingStat.IncrementPass()
|
|
|
|
promise.Pass()
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return handler(ctx, req)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func ensureSheddingStat() {
|
|
|
|
lock.Lock()
|
|
|
|
if sheddingStat == nil {
|
|
|
|
sheddingStat = load.NewSheddingStat(serviceType)
|
|
|
|
}
|
|
|
|
lock.Unlock()
|
|
|
|
}
|