diff --git a/grpc-mongo/client/main.go b/grpc-mongo/client/main.go index 09226b92..407a8344 100644 --- a/grpc-mongo/client/main.go +++ b/grpc-mongo/client/main.go @@ -35,23 +35,35 @@ func main() { defer conn.Close() //nolint:errcheck c := pb.NewTokenServiceClient(conn) - ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) - defer cancel() + + // Per-call deadlines: each RPC gets its own bounded context so the client's + // deliberate inter-call pacing (and the slow proxyless-capture warmup on a + // loaded CI runner) never eats into a later call's budget. A single shared + // absolute 20s deadline conflated all 11 calls plus their 1s pacing sleeps + // into one window, so under contention NextToken #9 sporadically tripped + // "DeadlineExceeded". A genuinely hung RPC still times out at callTimeout. + const callTimeout = 10 * time.Second // Seed 10 tokens (order matters, first popped = first returned) seed := []string{"alpha", "beta", "gamma", "delta", "epsilon", "zeta", "eta", "theta", "iota", "kappa"} - ack, err := c.SeedTokens(ctx, &pb.SeedRequest{Tokens: seed}) + seedCtx, cancelSeed := context.WithTimeout(context.Background(), callTimeout) + ack, err := c.SeedTokens(seedCtx, &pb.SeedRequest{Tokens: seed}) + cancelSeed() if err != nil { log.Fatalf("seed: %v", err) } fmt.Println("Seed:", ack.Message) + time.Sleep(1 * time.Second) // Make 10 identical requests -> 10 different replies for i := 1; i <= 10; i++ { - r, err := c.NextToken(ctx, &pb.NextTokenRequest{}) + callCtx, cancelCall := context.WithTimeout(context.Background(), callTimeout) + r, err := c.NextToken(callCtx, &pb.NextTokenRequest{}) + cancelCall() if err != nil { log.Fatalf("NextToken #%d: %v", i, err) } fmt.Printf("NextToken #%d: %s\n", i, r.Token) + time.Sleep(1 * time.Second) } }