fix(retry): retry transient edge answers centrally, fix stale task test (#57)
Release Please / Release Please (push) Skipped
Release / GoReleaser (push) Skipped
Tests / Secret scan (gitleaks) (push) Skipped
Tests / Test (Go 1.25) (push) Skipped
Tests / Test (Go stable) (push) Skipped
Tests / Secret scan (gitleaks) (pull_request) Successful in 4s
Tests / Test (Go 1.25) (pull_request) Successful in 21s
Tests / Test (Go stable) (pull_request) Successful in 21s

- Route HTTP helpers (getJSON/formRequest/deleteReq/postJSON/putJSON/
  multipart upload), Query and AuthenticateContext/ensureToken through the
  deterministic 429/502/503/504 retry (retryRaw), so the integration suite
  no longer fails on the shared openresty rate limit under parallel runs.
- Fix stale cmd/office/fetch integration test: loader.TaskFields was
  replaced by loader.DetailForm (broke go vet -tags=integration).
- Add unit tests for Transient/DoRetry.
This commit is contained in:
2026-09-16 21:32:14 +00:00
parent 8a17a32269
commit d6b8eb7777
7 changed files with 169 additions and 18 deletions
+32 -2
View File
@@ -144,8 +144,13 @@ func unmarshalResponseObject(raw json.RawMessage) (map[string]any, error) {
}
}
// getJSON issues an authenticated GET and returns the raw response body.
// getJSON issues an authenticated GET and returns the raw response body,
// retrying transient answers (see retryRaw).
func (c *Client) getJSON(ctx context.Context, path string) (json.RawMessage, error) {
return retryRaw(ctx, func() (json.RawMessage, error) { return c.getJSONOnce(ctx, path) })
}
func (c *Client) getJSONOnce(ctx context.Context, path string) (json.RawMessage, error) {
auth, err := c.authHeader()
if err != nil {
return nil, err
@@ -187,6 +192,12 @@ func (c *Client) deleteForm(ctx context.Context, path string, fields url.Values)
}
func (c *Client) formRequest(ctx context.Context, method, path string, fields url.Values) (json.RawMessage, error) {
return retryRaw(ctx, func() (json.RawMessage, error) {
return c.formRequestOnce(ctx, method, path, fields)
})
}
func (c *Client) formRequestOnce(ctx context.Context, method, path string, fields url.Values) (json.RawMessage, error) {
auth, err := c.authHeader()
if err != nil {
return nil, err
@@ -215,6 +226,10 @@ func (c *Client) formRequest(ctx context.Context, method, path string, fields ur
// deleteReq issues an authenticated DELETE.
func (c *Client) deleteReq(ctx context.Context, path string) (json.RawMessage, error) {
return retryRaw(ctx, func() (json.RawMessage, error) { return c.deleteReqOnce(ctx, path) })
}
func (c *Client) deleteReqOnce(ctx context.Context, path string) (json.RawMessage, error) {
auth, err := c.authHeader()
if err != nil {
return nil, err
@@ -260,6 +275,10 @@ func (c *Client) postJSONObject(ctx context.Context, path string, body any) (map
// postJSON issues an authenticated POST with application/json body.
func (c *Client) postJSON(ctx context.Context, path string, body any) (json.RawMessage, error) {
return retryRaw(ctx, func() (json.RawMessage, error) { return c.postJSONOnce(ctx, path, body) })
}
func (c *Client) postJSONOnce(ctx context.Context, path string, body any) (json.RawMessage, error) {
auth, err := c.authHeader()
if err != nil {
return nil, err
@@ -303,6 +322,10 @@ func (c *Client) postJSON(ctx context.Context, path string, body any) (json.RawM
// putJSON issues an authenticated PUT with application/json body.
func (c *Client) putJSON(ctx context.Context, path string, body any) (json.RawMessage, error) {
return retryRaw(ctx, func() (json.RawMessage, error) { return c.putJSONOnce(ctx, path, body) })
}
func (c *Client) putJSONOnce(ctx context.Context, path string, body any) (json.RawMessage, error) {
auth, err := c.authHeader()
if err != nil {
return nil, err
@@ -352,8 +375,15 @@ func (c *Client) uploadMultipart(ctx context.Context, path, fieldName, filePath
// uploadMultipartMethod sends a single-file multipart request with the given
// HTTP method. The OnlyOffice Documents API needs PUT for /update (a new
// version) and POST for /upload (a new file); sending POST to /update answers
// 500 on current servers.
// 500 on current servers. The file is re-opened per attempt, so transient
// answers are retried like every other request.
func (c *Client) uploadMultipartMethod(ctx context.Context, method, path, fieldName, filePath string) (json.RawMessage, error) {
return retryRaw(ctx, func() (json.RawMessage, error) {
return c.uploadMultipartOnce(ctx, method, path, fieldName, filePath)
})
}
func (c *Client) uploadMultipartOnce(ctx context.Context, method, path, fieldName, filePath string) (json.RawMessage, error) {
auth, err := c.authHeader()
if err != nil {
return nil, err