Skip to content

Commit 21237bb

Browse files
committed
feat: Cache awss3/awssqs Client
1 parent 2b9475b commit 21237bb

File tree

4 files changed

+125
-115
lines changed

4 files changed

+125
-115
lines changed

aws/awscognito/awscognito.go

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,16 @@ import (
1616
// aws-sdk-go v2 GetCredentialsForIdentity
1717
//
1818
// Mocks: Using ctxawslocal.WithContext, you can make requests for local mocks.
19-
func GetCredentialsForIdentity(ctx context.Context, region awsconfig.Region, identityId string, logins map[string]string) (*cognitoidentity.GetCredentialsForIdentityOutput, error) {
19+
func GetCredentialsForIdentity(
20+
ctx context.Context, region awsconfig.Region, identityId string, logins map[string]string,
21+
) (*cognitoidentity.GetCredentialsForIdentityOutput, error) {
2022
localProfile, _ := getLocalEndpoint(ctx)
2123
// Cognito Client
2224
awsCfg, err := awsConfig.LoadDefaultConfig(ctx, awsConfig.WithRegion(region.String()))
2325
if err != nil {
2426
return nil, fmt.Errorf("unable to load SDK config, %w", err)
2527
}
2628
client := cognitoidentity.NewFromConfig(awsCfg)
27-
if err != nil {
28-
return nil, err
29-
}
30-
3129
res, err := client.GetCredentialsForIdentity(
3230
ctx,
3331
&cognitoidentity.GetCredentialsForIdentityInput{

aws/awsdynamo/client.go

Lines changed: 15 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package awsdynamo
22

33
import (
44
"context"
5-
"fmt"
65
"sync"
76
"time"
87

@@ -17,16 +16,14 @@ import (
1716
"github.com/88labs/go-utils/aws/ctxawslocal"
1817
)
1918

20-
var dynamoDBClient *dynamodb.Client
21-
var once sync.Once
22-
23-
func GetClient(ctx context.Context, region awsconfig.Region, limitAttempts int, limitBackOffDelay time.Duration) (*dynamodb.Client, error) {
19+
func GetClient(
20+
ctx context.Context, region awsconfig.Region, limitAttempts int, limitBackOffDelay time.Duration,
21+
) (*dynamodb.Client, error) {
2422
if localProfile, ok := getLocalEndpoint(ctx); ok {
2523
return getClientLocal(ctx, *localProfile)
2624
}
27-
var responseError error
28-
once.Do(func() {
29-
// S3 Client
25+
fn := sync.OnceValues(func() (*dynamodb.Client, error) {
26+
// DynamoDB Client
3027
awsCfg, err := awsConfig.LoadDefaultConfig(ctx, awsConfig.WithRegion(region.String()),
3128
awsConfig.WithRetryer(func() aws.Retryer {
3229
r := retry.AddWithMaxAttempts(retry.NewStandard(), limitAttempts)
@@ -42,20 +39,19 @@ func GetClient(ctx context.Context, region awsconfig.Region, limitAttempts int,
4239
}),
4340
)
4441
if err != nil {
45-
responseError = fmt.Errorf("unable to load SDK config, %w", err)
46-
} else {
47-
responseError = nil
42+
return nil, err
4843
}
49-
dynamoDBClient = dynamodb.NewFromConfig(awsCfg)
44+
return dynamodb.NewFromConfig(awsCfg), nil
5045
})
51-
return dynamoDBClient, responseError
46+
return fn()
5247
}
5348

5449
func getClientLocal(ctx context.Context, localProfile LocalProfile) (*dynamodb.Client, error) {
55-
var responseError error
56-
once.Do(func() {
50+
fn := sync.OnceValues(func() (*dynamodb.Client, error) {
5751
// https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/endpoints/
58-
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
52+
customResolver := aws.EndpointResolverWithOptionsFunc(func(
53+
service, region string, options ...interface{},
54+
) (aws.Endpoint, error) {
5955
if service == dynamodb.ServiceID {
6056
return aws.Endpoint{
6157
PartitionID: "aws",
@@ -77,14 +73,11 @@ func getClientLocal(ctx context.Context, localProfile LocalProfile) (*dynamodb.C
7773
}),
7874
)
7975
if err != nil {
80-
responseError = fmt.Errorf("unable to load SDK config, %w", err)
81-
return
82-
} else {
83-
responseError = nil
76+
return nil, err
8477
}
85-
dynamoDBClient = dynamodb.NewFromConfig(awsCfg)
78+
return dynamodb.NewFromConfig(awsCfg), nil
8679
})
87-
return dynamoDBClient, responseError
80+
return fn()
8881
}
8982

9083
type LocalProfile struct {

aws/awss3/client.go

Lines changed: 66 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ var (
2525

2626
customMu sync.Mutex
2727
customEndpointClient *s3.Client
28+
29+
s3Client *s3.Client
30+
once sync.Once
2831
)
2932

3033
// GetClient
@@ -41,65 +44,72 @@ func GetClient(ctx context.Context, region awsconfig.Region) (*s3.Client, error)
4144
customEndpointClient, err = getClientLocal(ctx, *localProfile)
4245
return customEndpointClient, err
4346
}
44-
awsHttpClient := awshttp.NewBuildableClient()
45-
if GlobalDialer != nil {
46-
awsHttpClient.WithDialerOptions(func(dialer *net.Dialer) {
47-
if GlobalDialer.Timeout != 0 {
48-
dialer.Timeout = GlobalDialer.Timeout
49-
}
50-
if GlobalDialer.Deadline != nil {
51-
dialer.Deadline = *GlobalDialer.Deadline
52-
}
53-
if GlobalDialer.KeepAlive != 0 {
54-
dialer.KeepAlive = GlobalDialer.KeepAlive
55-
}
56-
})
57-
}
58-
// S3 Client
59-
awsCfg, err := awsConfig.LoadDefaultConfig(
60-
ctx,
61-
awsConfig.WithRegion(region.String()),
62-
awsConfig.WithHTTPClient(awsHttpClient),
63-
)
64-
if err != nil {
65-
return nil, fmt.Errorf("unable to load SDK config, %w", err)
66-
}
67-
return s3.NewFromConfig(awsCfg), nil
47+
fn := sync.OnceValues(func() (*s3.Client, error) {
48+
// S3 Client
49+
awsHttpClient := awshttp.NewBuildableClient()
50+
if GlobalDialer != nil {
51+
awsHttpClient.WithDialerOptions(func(dialer *net.Dialer) {
52+
if GlobalDialer.Timeout != 0 {
53+
dialer.Timeout = GlobalDialer.Timeout
54+
}
55+
if GlobalDialer.Deadline != nil {
56+
dialer.Deadline = *GlobalDialer.Deadline
57+
}
58+
if GlobalDialer.KeepAlive != 0 {
59+
dialer.KeepAlive = GlobalDialer.KeepAlive
60+
}
61+
})
62+
}
63+
// S3 Client
64+
awsCfg, err := awsConfig.LoadDefaultConfig(
65+
ctx,
66+
awsConfig.WithRegion(region.String()),
67+
awsConfig.WithHTTPClient(awsHttpClient),
68+
)
69+
if err != nil {
70+
return nil, err
71+
}
72+
return s3.NewFromConfig(awsCfg), nil
73+
})
74+
return fn()
6875
}
6976

7077
func getClientLocal(ctx context.Context, localProfile LocalProfile) (*s3.Client, error) {
71-
awsHttpClient := awshttp.NewBuildableClient()
72-
if GlobalDialer != nil {
73-
awsHttpClient.WithDialerOptions(func(dialer *net.Dialer) {
74-
if GlobalDialer.Timeout != 0 {
75-
dialer.Timeout = GlobalDialer.Timeout
76-
}
77-
if GlobalDialer.Deadline != nil {
78-
dialer.Deadline = *GlobalDialer.Deadline
79-
}
80-
if GlobalDialer.KeepAlive != 0 {
81-
dialer.KeepAlive = GlobalDialer.KeepAlive
82-
}
83-
})
84-
}
85-
awsCfg, err := awsConfig.LoadDefaultConfig(ctx,
86-
awsConfig.WithHTTPClient(awsHttpClient),
87-
awsConfig.WithCredentialsProvider(credentials.StaticCredentialsProvider{
88-
Value: aws.Credentials{
89-
AccessKeyID: localProfile.AccessKey,
90-
SecretAccessKey: localProfile.SecretAccessKey,
91-
SessionToken: localProfile.SessionToken,
92-
},
93-
}),
94-
awsConfig.WithDefaultRegion(awsconfig.RegionTokyo.String()),
95-
)
96-
if err != nil {
97-
return nil, fmt.Errorf("unable to load SDK config, %w", err)
98-
}
99-
return s3.NewFromConfig(awsCfg, func(o *s3.Options) {
100-
o.BaseEndpoint = aws.String(localProfile.Endpoint)
101-
o.UsePathStyle = true
102-
}), nil
78+
fn := sync.OnceValues(func() (*s3.Client, error) {
79+
awsHttpClient := awshttp.NewBuildableClient()
80+
if GlobalDialer != nil {
81+
awsHttpClient.WithDialerOptions(func(dialer *net.Dialer) {
82+
if GlobalDialer.Timeout != 0 {
83+
dialer.Timeout = GlobalDialer.Timeout
84+
}
85+
if GlobalDialer.Deadline != nil {
86+
dialer.Deadline = *GlobalDialer.Deadline
87+
}
88+
if GlobalDialer.KeepAlive != 0 {
89+
dialer.KeepAlive = GlobalDialer.KeepAlive
90+
}
91+
})
92+
}
93+
awsCfg, err := awsConfig.LoadDefaultConfig(ctx,
94+
awsConfig.WithHTTPClient(awsHttpClient),
95+
awsConfig.WithCredentialsProvider(credentials.StaticCredentialsProvider{
96+
Value: aws.Credentials{
97+
AccessKeyID: localProfile.AccessKey,
98+
SecretAccessKey: localProfile.SecretAccessKey,
99+
SessionToken: localProfile.SessionToken,
100+
},
101+
}),
102+
awsConfig.WithDefaultRegion(awsconfig.RegionTokyo.String()),
103+
)
104+
if err != nil {
105+
return nil, fmt.Errorf("unable to load SDK config, %w", err)
106+
}
107+
return s3.NewFromConfig(awsCfg, func(o *s3.Options) {
108+
o.BaseEndpoint = aws.String(localProfile.Endpoint)
109+
o.UsePathStyle = true
110+
}), nil
111+
})
112+
return fn()
103113
}
104114

105115
type LocalProfile struct {

aws/awssqs/client.go

Lines changed: 41 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package awssqs
33
import (
44
"context"
55
"fmt"
6+
"sync"
67

78
"github.com/aws/aws-sdk-go-v2/aws"
89
awsConfig "github.com/aws/aws-sdk-go-v2/config"
@@ -14,48 +15,56 @@ import (
1415
)
1516

1617
// GetClient
17-
// Get s3 client for aws-sdk-go v2.
18+
// Get sqs client for aws-sdk-go v2.
1819
// Using ctxawslocal.WithContext, you can make requests for local mocks
1920
func GetClient(ctx context.Context, region awsconfig.Region) (*sqs.Client, error) {
2021
if localProfile, ok := getLocalEndpoint(ctx); ok {
2122
return getClientLocal(ctx, *localProfile)
2223
}
23-
// SQS Client
24-
awsCfg, err := awsConfig.LoadDefaultConfig(ctx, awsConfig.WithRegion(region.String()))
25-
if err != nil {
26-
return nil, fmt.Errorf("unable to load SDK config, %w", err)
27-
}
28-
return sqs.NewFromConfig(awsCfg), nil
24+
fn := sync.OnceValues(func() (*sqs.Client, error) {
25+
// SQS Client
26+
awsCfg, err := awsConfig.LoadDefaultConfig(ctx, awsConfig.WithRegion(region.String()))
27+
if err != nil {
28+
return nil, err
29+
}
30+
return sqs.NewFromConfig(awsCfg), nil
31+
})
32+
return fn()
2933
}
3034

3135
func getClientLocal(ctx context.Context, localProfile LocalProfile) (*sqs.Client, error) {
32-
// https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/endpoints/
33-
customResolver := aws.EndpointResolverWithOptionsFunc(func(service, region string, options ...interface{}) (aws.Endpoint, error) {
34-
if service == sqs.ServiceID {
35-
return aws.Endpoint{
36-
PartitionID: "aws",
37-
URL: localProfile.Endpoint,
38-
SigningRegion: region,
39-
HostnameImmutable: true,
40-
}, nil
36+
fn := sync.OnceValues(func() (*sqs.Client, error) {
37+
// https://aws.github.io/aws-sdk-go-v2/docs/configuring-sdk/endpoints/
38+
customResolver := aws.EndpointResolverWithOptionsFunc(func(
39+
service, region string, options ...interface{},
40+
) (aws.Endpoint, error) {
41+
if service == sqs.ServiceID {
42+
return aws.Endpoint{
43+
PartitionID: "aws",
44+
URL: localProfile.Endpoint,
45+
SigningRegion: region,
46+
HostnameImmutable: true,
47+
}, nil
48+
}
49+
// returning EndpointNotFoundError will allow the service to fallback to it's default resolution
50+
return aws.Endpoint{}, &aws.EndpointNotFoundError{}
51+
})
52+
awsCfg, err := awsConfig.LoadDefaultConfig(ctx,
53+
awsConfig.WithEndpointResolverWithOptions(customResolver),
54+
awsConfig.WithCredentialsProvider(credentials.StaticCredentialsProvider{
55+
Value: aws.Credentials{
56+
AccessKeyID: localProfile.AccessKey,
57+
SecretAccessKey: localProfile.SecretAccessKey,
58+
SessionToken: localProfile.SessionToken,
59+
},
60+
}),
61+
)
62+
if err != nil {
63+
return nil, fmt.Errorf("unable to load SDK config, %w", err)
4164
}
42-
// returning EndpointNotFoundError will allow the service to fallback to it's default resolution
43-
return aws.Endpoint{}, &aws.EndpointNotFoundError{}
65+
return sqs.NewFromConfig(awsCfg), nil
4466
})
45-
awsCfg, err := awsConfig.LoadDefaultConfig(ctx,
46-
awsConfig.WithEndpointResolverWithOptions(customResolver),
47-
awsConfig.WithCredentialsProvider(credentials.StaticCredentialsProvider{
48-
Value: aws.Credentials{
49-
AccessKeyID: localProfile.AccessKey,
50-
SecretAccessKey: localProfile.SecretAccessKey,
51-
SessionToken: localProfile.SessionToken,
52-
},
53-
}),
54-
)
55-
if err != nil {
56-
return nil, fmt.Errorf("unable to load SDK config, %w", err)
57-
}
58-
return sqs.NewFromConfig(awsCfg), nil
67+
return fn()
5968
}
6069

6170
type LocalProfile struct {

0 commit comments

Comments
 (0)