Skip to content

Commit 6cee9d2

Browse files
committed
feat: support singleton for interceptor
1 parent c14a196 commit 6cee9d2

File tree

9 files changed

+74
-15
lines changed

9 files changed

+74
-15
lines changed

go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,6 @@ require (
6666
golang.org/x/sys v0.28.0 // indirect
6767
golang.org/x/text v0.21.0 // indirect
6868
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
69-
google.golang.org/protobuf v1.35.2 // indirect
69+
google.golang.org/protobuf v1.36.0 // indirect
7070
gopkg.in/yaml.v3 v3.0.1 // indirect
7171
)

go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:
142142
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
143143
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
144144
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
145-
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
146-
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
145+
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
146+
google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
147147
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
148148
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
149149
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

interceptor/interceptor.go

+14
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package interceptor
22

33
import (
44
"context"
5+
6+
"github.com/go-kod/kod/internal/singleton"
57
)
68

79
// CallInfo contains information about the call.
@@ -56,6 +58,18 @@ func If(interceptor Interceptor, condition Condition) Interceptor {
5658
}
5759
}
5860

61+
// pool is a singleton for interceptors.
62+
var pool = singleton.New[Interceptor]()
63+
64+
// SingletonByFullMethod returns an Interceptor that is a singleton for the given method.
65+
func SingletonByFullMethod(initFn func() Interceptor) Interceptor {
66+
return func(ctx context.Context, info CallInfo, req, reply []any, invoker HandleFunc) error {
67+
interceptor := pool.Get(info.FullMethod, initFn)
68+
69+
return interceptor(ctx, info, req, reply, invoker)
70+
}
71+
}
72+
5973
// And groups conditions with the AND operator.
6074
func And(first, second Condition, conditions ...Condition) Condition {
6175
return func(ctx context.Context, info CallInfo) bool {

interceptor/interceptor_test.go

+45
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"context"
55
"errors"
66
"testing"
7+
8+
"github.com/stretchr/testify/require"
79
)
810

911
func TestIf(t *testing.T) {
@@ -299,3 +301,46 @@ func TestIsMethod(t *testing.T) {
299301
})
300302
}
301303
}
304+
305+
func TestSingleton(t *testing.T) {
306+
name := "FullMethod"
307+
308+
initCount := 0
309+
callCount := 0
310+
311+
// Create a mock invoker function
312+
initFn := func() Interceptor {
313+
initCount++
314+
return func(ctx context.Context, info CallInfo, req, reply []interface{}, invoker HandleFunc) error {
315+
callCount++
316+
return nil
317+
}
318+
}
319+
320+
// Create the singleton interceptor using the test case input
321+
singletonInterceptor := SingletonByFullMethod(initFn)
322+
323+
err := singletonInterceptor(context.Background(), CallInfo{
324+
FullMethod: name,
325+
}, nil, nil, nil)
326+
327+
require.Nil(t, err)
328+
require.Equal(t, 1, initCount)
329+
require.Equal(t, 1, callCount)
330+
331+
err = singletonInterceptor(context.Background(), CallInfo{
332+
FullMethod: name,
333+
}, nil, nil, nil)
334+
335+
require.Nil(t, err)
336+
require.Equal(t, 1, initCount)
337+
require.Equal(t, 2, callCount)
338+
339+
err = singletonInterceptor(context.Background(), CallInfo{
340+
FullMethod: "no cache",
341+
}, nil, nil, nil)
342+
343+
require.Nil(t, err)
344+
require.Equal(t, 2, initCount)
345+
require.Equal(t, 3, callCount)
346+
}

interceptor/kcircuitbreaker/circuitbreaker.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ import (
1212

1313
var (
1414
once sync.Once
15-
pool *singleton.Singleton[circuitbreaker.CircuitBreaker]
15+
pool *singleton.Singleton[*circuitbreaker.CircuitBreaker]
1616
)
1717

1818
// Interceptor returns an interceptor do circuit breaker.
1919
func Interceptor() interceptor.Interceptor {
2020
once.Do(func() {
21-
pool = singleton.NewSingleton[circuitbreaker.CircuitBreaker]()
21+
pool = singleton.New[*circuitbreaker.CircuitBreaker]()
2222
})
2323

2424
return func(ctx context.Context, info interceptor.CallInfo, req, reply []any, invoker interceptor.HandleFunc) error {

interceptor/kratelimit/ratelimit.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ import (
1212

1313
var (
1414
once sync.Once
15-
pool *singleton.Singleton[ratelimit.Ratelimit]
15+
pool *singleton.Singleton[*ratelimit.Ratelimit]
1616
)
1717

1818
// Interceptor returns an interceptor do rate limit.
1919
func Interceptor() interceptor.Interceptor {
2020
once.Do(func() {
21-
pool = singleton.NewSingleton[ratelimit.Ratelimit]()
21+
pool = singleton.New[*ratelimit.Ratelimit]()
2222
})
2323

2424
return func(ctx context.Context, info interceptor.CallInfo, req, reply []any, invoker interceptor.HandleFunc) error {

internal/singleton/singleton.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,19 @@ import (
66

77
// Singleton[T any] provides a common structure for components,
88
type Singleton[T any] struct {
9-
instances map[string]*T
9+
instances map[string]T
1010
mu sync.RWMutex
1111
}
1212

13-
// NewSingleton creates a new Singleton[T].
14-
func NewSingleton[T any]() *Singleton[T] {
13+
// New creates a new Singleton[T].
14+
func New[T any]() *Singleton[T] {
1515
return &Singleton[T]{
16-
instances: make(map[string]*T),
16+
instances: make(map[string]T),
1717
}
1818
}
1919

2020
// Get returns the instance of the component with the given name.
21-
func (s *Singleton[T]) Get(name string, initFn func() *T) *T {
21+
func (s *Singleton[T]) Get(name string, initFn func() T) T {
2222
s.mu.RLock()
2323

2424
if instance, exists := s.instances[name]; exists {

tests/go.mod

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,6 @@ require (
7878
golang.org/x/text v0.21.0 // indirect
7979
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect
8080
google.golang.org/grpc v1.69.2 // indirect
81-
google.golang.org/protobuf v1.35.2 // indirect
81+
google.golang.org/protobuf v1.36.0 // indirect
8282
gopkg.in/yaml.v3 v3.0.1 // indirect
8383
)

tests/go.sum

+2-2
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:
174174
google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU=
175175
google.golang.org/grpc v1.69.2 h1:U3S9QEtbXC0bYNvRtcoklF3xGtLViumSYxWykJS+7AU=
176176
google.golang.org/grpc v1.69.2/go.mod h1:vyjdE6jLBI76dgpDojsFGNaHlxdjXN9ghpnd2o7JGZ4=
177-
google.golang.org/protobuf v1.35.2 h1:8Ar7bF+apOIoThw1EdZl0p1oWvMqTHmpA2fRTyZO8io=
178-
google.golang.org/protobuf v1.35.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
177+
google.golang.org/protobuf v1.36.0 h1:mjIs9gYtt56AzC4ZaffQuh88TZurBGhIJMBZGSxNerQ=
178+
google.golang.org/protobuf v1.36.0/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
179179
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
180180
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
181181
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

0 commit comments

Comments
 (0)