From 3ecc97de29efaf40d12259d12afed6b4dee5f5d9 Mon Sep 17 00:00:00 2001 From: Alan Protasio Date: Fri, 8 May 2026 18:38:11 +0000 Subject: [PATCH] user: avoid full metadata copy in ExtractFromGRPCRequest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use metadata.ValueFromIncomingContext to read only the x-scope-orgid key instead of metadata.FromIncomingContext which deep-copies the entire metadata map. FromIncomingContext copies every key-value pair in the metadata map on every call. With 10 metadata keys per request, this is 16 allocations and 1016 bytes per call. ValueFromIncomingContext only copies the single requested key's []string slice. Benchmark results (10 metadata keys): name old time/op new time/op delta ExtractFromGRPCRequest-48 1389ns ± 2% 135ns ± 1% -90.3% name old alloc/op new alloc/op delta ExtractFromGRPCRequest-48 1016B ± 0% 80B ± 0% -92.1% name old allocs/op new allocs/op delta ExtractFromGRPCRequest-48 16.0 ± 0% 3.0 ± 0% -81.2% Signed-off-by: Alan Protasio --- user/grpc.go | 9 ++------- user/grpc_test.go | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 7 deletions(-) create mode 100644 user/grpc_test.go diff --git a/user/grpc.go b/user/grpc.go index 64f0491a..ff26fdd2 100644 --- a/user/grpc.go +++ b/user/grpc.go @@ -8,13 +8,8 @@ import ( // ExtractFromGRPCRequest extracts the user ID from the request metadata and returns // the user ID and a context with the user ID injected. func ExtractFromGRPCRequest(ctx context.Context) (string, context.Context, error) { - md, ok := metadata.FromIncomingContext(ctx) - if !ok { - return "", ctx, ErrNoOrgID - } - - orgIDs, ok := md[lowerOrgIDHeaderName] - if !ok || len(orgIDs) != 1 { + orgIDs := metadata.ValueFromIncomingContext(ctx, lowerOrgIDHeaderName) + if len(orgIDs) != 1 { return "", ctx, ErrNoOrgID } diff --git a/user/grpc_test.go b/user/grpc_test.go new file mode 100644 index 00000000..b508873c --- /dev/null +++ b/user/grpc_test.go @@ -0,0 +1,31 @@ +package user + +import ( + "context" + "testing" + + "google.golang.org/grpc/metadata" +) + +func BenchmarkExtractFromGRPCRequest(b *testing.B) { + // Simulate a realistic incoming context with multiple metadata keys + md := metadata.MD{ + "content-type": []string{"application/grpc"}, + "user-agent": []string{"grpc-go/1.71.2"}, + "x-scope-orgid": []string{"tenant-12345"}, + "x-forwarded-for": []string{"10.0.0.1"}, + "x-request-id": []string{"abc-def-ghi-jkl"}, + "traceparent": []string{"00-abcdef1234567890abcdef1234567890-1234567890abcdef-01"}, + "grpc-accept-encoding": []string{"gzip"}, + "authorization": []string{"Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."}, + "x-amz-date": []string{"20260507T183000Z"}, + "x-amz-security-token": []string{"FwoGZXIvYXdzEBYaDH..."}, + } + ctx := metadata.NewIncomingContext(context.Background(), md) + + b.ReportAllocs() + b.ResetTimer() + for i := 0; i < b.N; i++ { + _, _, _ = ExtractFromGRPCRequest(ctx) + } +}