Skip to content

Commit afa71db

Browse files
sync upstream
1 parent c2605c4 commit afa71db

File tree

5 files changed

+84
-9
lines changed

5 files changed

+84
-9
lines changed

pkg/idempotency/interceptor.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package idempotency
2+
3+
import (
4+
"context"
5+
6+
"github.com/google/uuid"
7+
"google.golang.org/grpc"
8+
"google.golang.org/grpc/metadata"
9+
)
10+
11+
// Interceptor add idempotency key to context.
12+
func Interceptor() grpc.UnaryClientInterceptor {
13+
return func(
14+
ctx context.Context,
15+
method string,
16+
req, reply any,
17+
cc *grpc.ClientConn,
18+
invoker grpc.UnaryInvoker,
19+
opts ...grpc.CallOption,
20+
) error {
21+
ctx = addIdempotencyToken(ctx)
22+
return invoker(ctx, method, req, reply, cc, opts...)
23+
}
24+
}
25+
26+
func addIdempotencyToken(ctx context.Context) context.Context {
27+
const idempotencyTokenMetadataKey = "idempotency-key"
28+
29+
idempotencyTokenPresent := false
30+
md, ok := metadata.FromOutgoingContext(ctx)
31+
if ok {
32+
_, idempotencyTokenPresent = md[idempotencyTokenMetadataKey]
33+
}
34+
35+
if !idempotencyTokenPresent {
36+
ctx = metadata.AppendToOutgoingContext(ctx, idempotencyTokenMetadataKey, uuid.New().String())
37+
}
38+
39+
return ctx
40+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package idempotency
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/stretchr/testify/require"
8+
"google.golang.org/grpc/metadata"
9+
)
10+
11+
const idempotencyKey = "idempotency-key"
12+
13+
func TestAddIdempotencyKey(t *testing.T) {
14+
t.Run("have no idempotency key before", func(t *testing.T) {
15+
ctx := context.Background()
16+
actualContext := addIdempotencyToken(ctx)
17+
actualMetadata, ok := metadata.FromOutgoingContext(actualContext)
18+
require.True(t, ok)
19+
require.NotNil(t, actualMetadata.Get(idempotencyKey))
20+
21+
_, ok = metadata.FromOutgoingContext(ctx)
22+
require.False(t, ok)
23+
})
24+
25+
t.Run("have idempotency key before", func(t *testing.T) {
26+
expectedCtx := context.Background()
27+
expectedCtx = metadata.AppendToOutgoingContext(expectedCtx, idempotencyKey, "somevalue")
28+
actualContext := addIdempotencyToken(expectedCtx)
29+
30+
expectedMetadata, ok := metadata.FromOutgoingContext(expectedCtx)
31+
require.True(t, ok)
32+
33+
actualMetadata, ok := metadata.FromOutgoingContext(actualContext)
34+
require.True(t, ok)
35+
require.EqualValues(
36+
t,
37+
expectedMetadata.Get(idempotencyKey),
38+
actualMetadata.Get(idempotencyKey),
39+
)
40+
})
41+
}

pkg/retry/interceptor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616
// Without any option, it uses default options, that basically retries nothing.
1717
// Default retry quantity is 0, backoff function is nil, retry codes are DefaultRetriableCodes, AttemptHeader is false, and perCallTimeout is 0.
1818
//
19-
// Deprecated: RetryDialOption function to provide standard gRPC retries.
19+
// Deprecated: RetryDialOption function to provide standard gRPC retries. For idempotency keys use idempotency.Interceptor
2020
func Interceptor(callOpts ...grpc.CallOption) grpc.UnaryClientInterceptor {
2121
i := unaryInterceptor{opts: *defaultOptions.applyOptions(callOpts)}
2222
return i.InterceptUnary

pkg/retry/interceptor_test.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import (
1616
"google.golang.org/grpc/status"
1717
"google.golang.org/protobuf/proto"
1818

19-
grpc_insight "bb.yandex-team.ru/cloud/cloud-go/api/pkg/grpc/middleware/insight"
2019
"github.com/yandex-cloud/go-genproto/yandex/cloud/compute/v1"
2120
"github.com/yandex-cloud/go-sdk/pkg/testutil"
2221
)
@@ -97,12 +96,7 @@ func initTestService(t *testing.T, handler ZoneServerHandler, interceptor grpc.D
9796
testutil.Message("Test server failed to start."),
9897
)
9998

100-
so.c, err = grpc_insight.CreateGRPCClient(so.l.Addr().String(),
101-
grpc_insight.WithDialOptions(
102-
grpc.WithTransportCredentials(insecure.NewCredentials()),
103-
interceptor,
104-
),
105-
)
99+
so.c, err = grpc.Dial(so.l.Addr().String(), grpc.WithTransportCredentials(insecure.NewCredentials()), interceptor)
106100
require.NoError(t, err)
107101
res = compute.NewZoneServiceClient(so.c)
108102
return

pkg/retry/options.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"google.golang.org/grpc/codes"
88
)
99

10-
// WithDefaultInterceptor returns interceptor that DOESN'T retry anything.
10+
// WithDefaultInterceptor returns interceptor that DOESN'T retrу anything.
1111
// Its possible to change its behaviour with call options.
1212
//
1313
// Deprecated: use retry/v1 package instead of this options

0 commit comments

Comments
 (0)