Fix grpcserver rate limiter: move to Server field
The package-level defaultRateLimiter drained its token bucket across all test cases, causing later tests to hit ResourceExhausted. Move rateLimiter from a package-level var to a *grpcRateLimiter field on Server; New() allocates a fresh instance (10 req/s, burst 10) per server. Each test's newTestEnv() constructs its own Server, so tests no longer share limiter state. Production behaviour is unchanged: a single Server is constructed at startup and lives for the process lifetime.
This commit is contained in:
@@ -53,23 +53,27 @@ func claimsFromContext(ctx context.Context) *token.Claims {
|
||||
|
||||
// Server holds the shared state for all gRPC service implementations.
|
||||
type Server struct {
|
||||
db *db.DB
|
||||
cfg *config.Config
|
||||
logger *slog.Logger
|
||||
privKey ed25519.PrivateKey
|
||||
pubKey ed25519.PublicKey
|
||||
masterKey []byte
|
||||
db *db.DB
|
||||
cfg *config.Config
|
||||
logger *slog.Logger
|
||||
rateLimiter *grpcRateLimiter
|
||||
privKey ed25519.PrivateKey
|
||||
pubKey ed25519.PublicKey
|
||||
masterKey []byte
|
||||
}
|
||||
|
||||
// New creates a Server with the given dependencies (same as the REST Server).
|
||||
// A fresh per-IP rate limiter (10 req/s, burst 10) is allocated per Server
|
||||
// instance so that tests do not share state across test cases.
|
||||
func New(database *db.DB, cfg *config.Config, priv ed25519.PrivateKey, pub ed25519.PublicKey, masterKey []byte, logger *slog.Logger) *Server {
|
||||
return &Server{
|
||||
db: database,
|
||||
cfg: cfg,
|
||||
privKey: priv,
|
||||
pubKey: pub,
|
||||
masterKey: masterKey,
|
||||
logger: logger,
|
||||
db: database,
|
||||
cfg: cfg,
|
||||
privKey: priv,
|
||||
pubKey: pub,
|
||||
masterKey: masterKey,
|
||||
logger: logger,
|
||||
rateLimiter: newGRPCRateLimiter(10, 10),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -282,10 +286,6 @@ func (l *grpcRateLimiter) cleanup() {
|
||||
}
|
||||
}
|
||||
|
||||
// defaultRateLimiter is the server-wide rate limiter instance.
|
||||
// 10 req/s sustained, burst 10 — same parameters as the REST limiter.
|
||||
var defaultRateLimiter = newGRPCRateLimiter(10, 10)
|
||||
|
||||
// rateLimitInterceptor applies per-IP rate limiting using the same token-bucket
|
||||
// parameters as the REST rate limiter (10 req/s, burst 10).
|
||||
func (s *Server) rateLimitInterceptor(
|
||||
@@ -304,7 +304,7 @@ func (s *Server) rateLimitInterceptor(
|
||||
}
|
||||
}
|
||||
|
||||
if ip != "" && !defaultRateLimiter.allow(ip) {
|
||||
if ip != "" && !s.rateLimiter.allow(ip) {
|
||||
return nil, status.Error(codes.ResourceExhausted, "rate limit exceeded")
|
||||
}
|
||||
return handler(ctx, req)
|
||||
|
||||
Reference in New Issue
Block a user