Skip to content

Commit ec0fa02

Browse files
authored
Merge pull request #43 from seymourtang/retry
chore:Improve the retry mechanism at the application layer
2 parents b9a0476 + ee9390c commit ec0fa02

28 files changed

+409
-490
lines changed

services/cloudrecording/api/acquire.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,23 @@ import (
99

1010
"github.com/AgoraIO-Community/agora-rest-client-go/agora"
1111
"github.com/AgoraIO-Community/agora-rest-client-go/agora/client"
12+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/log"
1213
)
1314

1415
type Acquire struct {
15-
client client.Client
16-
prefixPath string // /v1/apps/{appid}/cloud_recording/
16+
baseHandler
1717
}
1818

19-
func NewAcquire(client client.Client, prefixPath string) *Acquire {
20-
return &Acquire{client: client, prefixPath: prefixPath}
19+
func NewAcquire(module string, logger log.Logger, retryCount int, client client.Client, prefixPath string) *Acquire {
20+
return &Acquire{
21+
baseHandler: baseHandler{
22+
module: module,
23+
logger: logger,
24+
retryCount: retryCount,
25+
client: client,
26+
prefixPath: prefixPath,
27+
},
28+
}
2129
}
2230

2331
// buildPath returns the request path.
@@ -62,7 +70,7 @@ type AcquireSuccessResp struct {
6270
func (a *Acquire) Do(ctx context.Context, payload *AcquireReqBody) (*AcquireResp, error) {
6371
path := a.buildPath()
6472

65-
responseData, err := a.client.DoREST(ctx, path, http.MethodPost, payload)
73+
responseData, err := doRESTWithRetry(ctx, a.module, a.logger, a.retryCount, a.client, path, http.MethodPost, payload)
6674
if err != nil {
6775
var internalErr *agora.InternalErr
6876
if !errors.As(err, &internalErr) {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package api
2+
3+
import (
4+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/client"
5+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/log"
6+
)
7+
8+
type baseHandler struct {
9+
module string
10+
logger log.Logger
11+
client client.Client
12+
retryCount int
13+
prefixPath string // /v1/apps/{appid}/cloud_recording
14+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package api
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"time"
7+
8+
"github.com/AgoraIO-Community/agora-rest-client-go/agora"
9+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/client"
10+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/log"
11+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/retry"
12+
)
13+
14+
func doRESTWithRetry(ctx context.Context, module string, logger log.Logger, handleRetryCount int, client client.Client, path string, method string, requestBody any) (*agora.BaseResponse, error) {
15+
var (
16+
resp *agora.BaseResponse
17+
err error
18+
retryCount int
19+
)
20+
21+
err = retry.Do(func(retryCount int) error {
22+
var doErr error
23+
24+
resp, doErr = client.DoREST(ctx, path, method, requestBody)
25+
if doErr != nil {
26+
return agora.NewRetryErr(false, doErr)
27+
}
28+
29+
statusCode := resp.HttpStatusCode
30+
switch {
31+
case statusCode == 200 || statusCode == 201:
32+
return nil
33+
case statusCode >= 400 && statusCode < 499:
34+
logger.Debugf(ctx, module, "http status code is %d, no retry,http response:%s", statusCode, resp.RawBody)
35+
return agora.NewRetryErr(
36+
false,
37+
agora.NewInternalErr(fmt.Sprintf("http status code is %d, no retry,http response:%s", statusCode, resp.RawBody)),
38+
)
39+
default:
40+
logger.Debugf(ctx, module, "http status code is %d, retry,http response:%s", statusCode, resp.RawBody)
41+
return fmt.Errorf("http status code is %d, retry", resp.RawBody)
42+
}
43+
}, func() bool {
44+
select {
45+
case <-ctx.Done():
46+
return true
47+
default:
48+
}
49+
return retryCount >= handleRetryCount
50+
}, func(i int) time.Duration {
51+
return time.Second * time.Duration(i+1)
52+
}, func(err error) {
53+
logger.Debugf(ctx, module, "http request err:%s", err)
54+
retryCount++
55+
})
56+
57+
return resp, err
58+
}

services/cloudrecording/api/query.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,23 @@ import (
1010

1111
"github.com/AgoraIO-Community/agora-rest-client-go/agora"
1212
"github.com/AgoraIO-Community/agora-rest-client-go/agora/client"
13+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/log"
1314
)
1415

1516
type Query struct {
16-
client client.Client
17-
prefixPath string // /v1/apps/{appid}/cloud_recording
17+
baseHandler
1818
}
1919

20-
func NewQuery(client client.Client, prefixPath string) *Query {
21-
return &Query{client: client, prefixPath: prefixPath}
20+
func NewQuery(module string, logger log.Logger, retryCount int, client client.Client, prefixPath string) *Query {
21+
return &Query{
22+
baseHandler: baseHandler{
23+
module: module,
24+
logger: logger,
25+
retryCount: retryCount,
26+
client: client,
27+
prefixPath: prefixPath,
28+
},
29+
}
2230
}
2331

2432
// buildPath returns the request path.
@@ -537,7 +545,7 @@ func (q *QuerySuccessResp) setServerResponse(rawBody []byte, mode string) error
537545
func (q *Query) Do(ctx context.Context, resourceID string, sid string, mode string) (*QueryResp, error) {
538546
path := q.buildPath(resourceID, sid, mode)
539547

540-
responseData, err := q.client.DoREST(ctx, path, http.MethodGet, nil)
548+
responseData, err := doRESTWithRetry(ctx, q.module, q.logger, q.retryCount, q.client, path, http.MethodGet, nil)
541549
if err != nil {
542550
var internalErr *agora.InternalErr
543551
if !errors.As(err, &internalErr) {

services/cloudrecording/api/start.go

Lines changed: 12 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,29 @@ package api
33
import (
44
"context"
55
"errors"
6-
"fmt"
76
"net/http"
8-
"time"
97

108
"github.com/tidwall/gjson"
119

1210
"github.com/AgoraIO-Community/agora-rest-client-go/agora"
1311
"github.com/AgoraIO-Community/agora-rest-client-go/agora/client"
1412
"github.com/AgoraIO-Community/agora-rest-client-go/agora/log"
15-
"github.com/AgoraIO-Community/agora-rest-client-go/agora/retry"
1613
)
1714

1815
type Start struct {
19-
module string
20-
logger log.Logger
21-
client client.Client
22-
prefixPath string // /v1/apps/{appid}/cloud_recording
16+
baseHandler
2317
}
2418

25-
func NewStart(module string, logger log.Logger, client client.Client, prefixPath string) *Start {
26-
return &Start{module: module, logger: logger, client: client, prefixPath: prefixPath}
19+
func NewStart(module string, logger log.Logger, retryCount int, client client.Client, prefixPath string) *Start {
20+
return &Start{
21+
baseHandler: baseHandler{
22+
module: module,
23+
logger: logger,
24+
retryCount: retryCount,
25+
client: client,
26+
prefixPath: prefixPath,
27+
},
28+
}
2729
}
2830

2931
const (
@@ -570,7 +572,7 @@ type StartSuccessResp struct {
570572
func (s *Start) Do(ctx context.Context, resourceID string, mode string, payload *StartReqBody) (*StartResp, error) {
571573
path := s.buildPath(resourceID, mode)
572574

573-
responseData, err := s.doRESTWithRetry(ctx, path, http.MethodPost, payload)
575+
responseData, err := doRESTWithRetry(ctx, s.module, s.logger, s.retryCount, s.client, path, http.MethodPost, payload)
574576
if err != nil {
575577
var internalErr *agora.InternalErr
576578
if !errors.As(err, &internalErr) {
@@ -600,51 +602,3 @@ func (s *Start) Do(ctx context.Context, resourceID string, mode string, payload
600602
resp.BaseResponse = responseData
601603
return &resp, nil
602604
}
603-
604-
const startRetryCount = 3
605-
606-
func (s *Start) doRESTWithRetry(ctx context.Context, path string, method string, requestBody interface{}) (*agora.BaseResponse, error) {
607-
var (
608-
resp *agora.BaseResponse
609-
err error
610-
retryCount int
611-
)
612-
613-
err = retry.Do(func(retryCount int) error {
614-
var doErr error
615-
616-
resp, doErr = s.client.DoREST(ctx, path, method, requestBody)
617-
if doErr != nil {
618-
return agora.NewRetryErr(false, doErr)
619-
}
620-
621-
statusCode := resp.HttpStatusCode
622-
switch {
623-
case statusCode == 200 || statusCode == 201:
624-
return nil
625-
case statusCode >= 400 && statusCode < 499:
626-
s.logger.Debugf(ctx, s.module, "http status code is %d, no retry,http response:%s", statusCode, resp.RawBody)
627-
return agora.NewRetryErr(
628-
false,
629-
agora.NewInternalErr(fmt.Sprintf("http status code is %d, no retry,http response:%s", statusCode, resp.RawBody)),
630-
)
631-
default:
632-
s.logger.Debugf(ctx, s.module, "http status code is %d, retry,http response:%s", statusCode, resp.RawBody)
633-
return fmt.Errorf("http status code is %d, retry", resp.RawBody)
634-
}
635-
}, func() bool {
636-
select {
637-
case <-ctx.Done():
638-
return true
639-
default:
640-
}
641-
return retryCount >= startRetryCount
642-
}, func(i int) time.Duration {
643-
return time.Second * time.Duration(i+1)
644-
}, func(err error) {
645-
s.logger.Debugf(ctx, s.module, "http request err:%s", err)
646-
retryCount++
647-
})
648-
649-
return resp, err
650-
}

services/cloudrecording/api/stop.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,23 @@ import (
99

1010
"github.com/AgoraIO-Community/agora-rest-client-go/agora"
1111
"github.com/AgoraIO-Community/agora-rest-client-go/agora/client"
12+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/log"
1213
)
1314

1415
type Stop struct {
15-
client client.Client
16-
prefixPath string // /v1/apps/{appid}/cloud_recording
16+
baseHandler
1717
}
1818

19-
func NewStop(client client.Client, prefixPath string) *Stop {
20-
return &Stop{client: client, prefixPath: prefixPath}
19+
func NewStop(module string, logger log.Logger, retryCount int, client client.Client, prefixPath string) *Stop {
20+
return &Stop{
21+
baseHandler: baseHandler{
22+
module: module,
23+
logger: logger,
24+
retryCount: retryCount,
25+
client: client,
26+
prefixPath: prefixPath,
27+
},
28+
}
2129
}
2230

2331
// buildPath returns the request path.
@@ -75,7 +83,7 @@ type StopSuccessResp struct {
7583
func (s *Stop) Do(ctx context.Context, resourceId string, sid string, mode string, payload *StopReqBody) (*StopResp, error) {
7684
path := s.buildPath(resourceId, sid, mode)
7785

78-
responseData, err := s.client.DoREST(ctx, path, http.MethodPost, payload)
86+
responseData, err := doRESTWithRetry(ctx, s.module, s.logger, s.retryCount, s.client, path, http.MethodPost, payload)
7987
if err != nil {
8088
var internalErr *agora.InternalErr
8189
if !errors.As(err, &internalErr) {

services/cloudrecording/api/update.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,23 @@ import (
99

1010
"github.com/AgoraIO-Community/agora-rest-client-go/agora"
1111
"github.com/AgoraIO-Community/agora-rest-client-go/agora/client"
12+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/log"
1213
)
1314

1415
type Update struct {
15-
client client.Client
16-
prefixPath string // /v1/apps/{appid}/cloud_recording
16+
baseHandler
1717
}
1818

19-
func NewUpdate(client client.Client, prefixPath string) *Update {
20-
return &Update{client: client, prefixPath: prefixPath}
19+
func NewUpdate(module string, logger log.Logger, retryCount int, client client.Client, prefixPath string) *Update {
20+
return &Update{
21+
baseHandler: baseHandler{
22+
module: module,
23+
logger: logger,
24+
retryCount: retryCount,
25+
client: client,
26+
prefixPath: prefixPath,
27+
},
28+
}
2129
}
2230

2331
// buildPath returns the request path.
@@ -133,7 +141,7 @@ type UpdateSuccessResp struct {
133141
func (u *Update) Do(ctx context.Context, resourceID string, sid string, mode string, payload *UpdateReqBody) (*UpdateResp, error) {
134142
path := u.buildPath(resourceID, sid, mode)
135143

136-
responseData, err := u.client.DoREST(ctx, path, http.MethodPost, payload)
144+
responseData, err := doRESTWithRetry(ctx, u.module, u.logger, u.retryCount, u.client, path, http.MethodPost, payload)
137145
if err != nil {
138146
var internalErr *agora.InternalErr
139147
if !errors.As(err, &internalErr) {

services/cloudrecording/api/updatelayout.go

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,23 @@ import (
99

1010
"github.com/AgoraIO-Community/agora-rest-client-go/agora"
1111
"github.com/AgoraIO-Community/agora-rest-client-go/agora/client"
12+
"github.com/AgoraIO-Community/agora-rest-client-go/agora/log"
1213
)
1314

1415
type UpdateLayout struct {
15-
client client.Client
16-
prefixPath string // /apps/{appid}/cloud_recording
16+
baseHandler
1717
}
1818

19-
func NewUpdateLayout(client client.Client, prefixPath string) *UpdateLayout {
20-
return &UpdateLayout{client: client, prefixPath: prefixPath}
19+
func NewUpdateLayout(module string, logger log.Logger, retryCount int, client client.Client, prefixPath string) *UpdateLayout {
20+
return &UpdateLayout{
21+
baseHandler: baseHandler{
22+
module: module,
23+
logger: logger,
24+
retryCount: retryCount,
25+
client: client,
26+
prefixPath: prefixPath,
27+
},
28+
}
2129
}
2230

2331
// buildPath returns the request path.
@@ -167,7 +175,7 @@ type UpdateLayoutResp struct {
167175
func (u *UpdateLayout) Do(ctx context.Context, resourceID string, sid string, mode string, payload *UpdateLayoutReqBody) (*UpdateLayoutResp, error) {
168176
path := u.buildPath(resourceID, sid, mode)
169177

170-
responseData, err := u.client.DoREST(ctx, path, http.MethodPost, payload)
178+
responseData, err := doRESTWithRetry(ctx, u.module, u.logger, u.retryCount, u.client, path, http.MethodPost, payload)
171179
if err != nil {
172180
var internalErr *agora.InternalErr
173181
if !errors.As(err, &internalErr) {

services/cloudrecording/client.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ type Config struct {
5454
Logger log.Logger
5555
}
5656

57+
var RetryCount = 3
58+
5759
// NewClient
5860
//
5961
// @brief Creates a Cloud Recording client with the specified configuration
@@ -79,12 +81,12 @@ func NewClient(config *Config) (*Client, error) {
7981
}
8082

8183
c := &Client{
82-
acquireAPI: api.NewAcquire(agoraClient, prefixPath),
83-
startAPI: api.NewStart("cloudRecording:start", config.Logger, agoraClient, prefixPath),
84-
stopAPI: api.NewStop(agoraClient, prefixPath),
85-
queryAPI: api.NewQuery(agoraClient, prefixPath),
86-
updateLayoutAPI: api.NewUpdateLayout(agoraClient, prefixPath),
87-
updateAPI: api.NewUpdate(agoraClient, prefixPath),
84+
acquireAPI: api.NewAcquire("cloudRecording:acquire", config.Logger, RetryCount, agoraClient, prefixPath),
85+
startAPI: api.NewStart("cloudRecording:start", config.Logger, RetryCount, agoraClient, prefixPath),
86+
stopAPI: api.NewStop("cloudRecording:stop", config.Logger, RetryCount, agoraClient, prefixPath),
87+
queryAPI: api.NewQuery("cloudRecording:query", config.Logger, RetryCount, agoraClient, prefixPath),
88+
updateLayoutAPI: api.NewUpdateLayout("cloudRecording:updateLayout", config.Logger, RetryCount, agoraClient, prefixPath),
89+
updateAPI: api.NewUpdate("cloudRecording:update", config.Logger, RetryCount, agoraClient, prefixPath),
8890
}
8991

9092
c.individualRecordingScenario = scenario.NewIndividualRecording(c.acquireAPI, c.startAPI, c.stopAPI, c.queryAPI, c.updateAPI)

0 commit comments

Comments
 (0)