Skip to content

Commit bbfc0ac

Browse files
authored
fix(storage): disable gax retries for gRPC (#9747)
All gRPC ops are retried as needed at the handwritten layer. Disable gax retries.
1 parent 6a7cd4f commit bbfc0ac

3 files changed

Lines changed: 52 additions & 1 deletion

File tree

storage/client_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@ package storage
1616

1717
import (
1818
"context"
19+
"errors"
1920
"fmt"
2021
"log"
22+
"net/url"
2123
"os"
2224
"strconv"
2325
"strings"
@@ -26,7 +28,10 @@ import (
2628

2729
"cloud.google.com/go/iam/apiv1/iampb"
2830
"github.com/google/go-cmp/cmp"
31+
"github.com/googleapis/gax-go/v2/apierror"
32+
"github.com/googleapis/gax-go/v2/callctx"
2933
"google.golang.org/api/iterator"
34+
"google.golang.org/grpc/codes"
3035
)
3136

3237
var emulatorClients map[string]storageClient
@@ -1342,6 +1347,47 @@ func TestObjectConditionsEmulated(t *testing.T) {
13421347
})
13431348
}
13441349

1350+
// Test that RetryNever prevents any retries from happening in both transports.
1351+
func TestRetryNeverEmulated(t *testing.T) {
1352+
transportClientTest(t, func(t *testing.T, project, bucket string, client storageClient) {
1353+
ctx := context.Background()
1354+
1355+
attrs, err := client.CreateBucket(ctx, project, bucket, &BucketAttrs{}, nil)
1356+
if err != nil {
1357+
t.Fatalf("creating bucket: %v", err)
1358+
}
1359+
1360+
// Need the HTTP hostname to set up a retry test, as well as knowledge of
1361+
// underlying transport to specify instructions.
1362+
host := os.Getenv("STORAGE_EMULATOR_HOST")
1363+
endpoint, err := url.Parse(host)
1364+
if err != nil {
1365+
t.Fatalf("parsing endpoint: %v", err)
1366+
}
1367+
var transport string
1368+
if _, ok := client.(*httpStorageClient); ok {
1369+
transport = "http"
1370+
} else {
1371+
transport = "grpc"
1372+
}
1373+
1374+
et := emulatorTest{T: t, name: "testRetryNever", resources: resources{},
1375+
host: endpoint}
1376+
et.create(map[string][]string{"storage.buckets.get": {"return-503"}}, transport)
1377+
ctx = callctx.SetHeaders(ctx, "x-retry-test-id", et.id)
1378+
_, err = client.GetBucket(ctx, attrs.Name, nil, withRetryConfig(&retryConfig{policy: RetryNever}))
1379+
1380+
var ae *apierror.APIError
1381+
if errors.As(err, &ae) {
1382+
// We espect a 503/UNAVAILABLE error. For anything else including a nil
1383+
// error, the test should fail.
1384+
if ae.GRPCStatus().Code() != codes.Unavailable && ae.HTTPCode() != 503 {
1385+
t.Errorf("GetBucket: got unexpected error %v; want 503", err)
1386+
}
1387+
}
1388+
})
1389+
}
1390+
13451391
// createObject creates an object in the emulator and returns its name, generation, and
13461392
// metageneration.
13471393
func createObject(ctx context.Context, bucket string) (string, int64, int64, error) {

storage/grpc_client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ type grpcStorageClient struct {
116116
func newGRPCStorageClient(ctx context.Context, opts ...storageOption) (storageClient, error) {
117117
s := initSettings(opts...)
118118
s.clientOption = append(defaultGRPCOptions(), s.clientOption...)
119+
// Disable all gax-level retries in favor of retry logic in the veneer client.
120+
s.gax = append(s.gax, gax.WithRetry(nil))
119121

120122
config := newStorageConfig(s.clientOption...)
121123
if config.readAPIWasSet {

storage/retry_conformance_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,9 @@ var methods = map[string][]retryFunc{
576576
}
577577

578578
func TestRetryConformance(t *testing.T) {
579+
// This endpoint is used only to call the testbench retry test API, which is HTTP
580+
// based. The endpoint called by the client library is determined inside of the
581+
// client constructor and will differ depending on the transport.
579582
host := os.Getenv("STORAGE_EMULATOR_HOST")
580583
if host == "" {
581584
t.Skip("This test must use the testbench emulator; set STORAGE_EMULATOR_HOST to run.")
@@ -759,7 +762,7 @@ func (et *emulatorTest) create(instructions map[string][]string, transport strin
759762

760763
et.host.Path = "retry_test"
761764
resp, err := c.Post(et.host.String(), "application/json", buf)
762-
if resp.StatusCode == 501 {
765+
if resp != nil && resp.StatusCode == 501 {
763766
et.T.Skip("This retry test case is not yet supported in the testbench.")
764767
}
765768
if err != nil || resp.StatusCode != 200 {

0 commit comments

Comments
 (0)