Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't re-use empty body on retry #255

Merged
merged 4 commits into from
Jan 14, 2024
Merged

Don't re-use empty body on retry #255

merged 4 commits into from
Jan 14, 2024

Conversation

cristoper
Copy link

@cristoper cristoper commented Jan 5, 2024

Retries on 429 (rate limit) were not working for me (except for GET requests). I would get these errors (retries result in a 400 Bad Request every time):

[DEBUG] PUT: https://mydomain.myshopify.com/admin/api/2023-07/metafields/30029242335523.json
[DEBUG] SENT: {"metafield":{"created_at":"2023-08-30T19:55:54-06:00","description":"The SKU of the product.","id":30029242335523,"key":"sku","namespace":"ns","owner_id":8557574947107,"own er_resource":"product","updated_at":"2023-08-30T19:55:54-06:00","value":"8bp-101009","type":"single_line_text_field","admin_graphql_api_id":"gid://shopify/Metafield/30029242335523"}}
[DEBUG] Shopify X-Request-Id: 6676e531-ee1e-4efa-96b2-88682553f930
[DEBUG] RECV 429: 429 Too Many Requests
[DEBUG] RESP: {"errors":"Exceeded 2 calls per second for api client. Reduce request rates to resume uninterrupted service."}
[DEBUG] rate limited waiting 2s
[DEBUG] Shopify X-Request-Id:
[DEBUG] RECV 400: 400 Bad Request
[DEBUG] RESP: <html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>

The problem is that on retry, the same request with an already-read Body was being sent. The solution that is working for me is to copy the Body into a []byte buffer before the first request, and then set the req.Body to that buffer before every request.

Copy link
Collaborator

@oliver006 oliver006 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!
I left a couple of questions.
One request: can you add a request that triggers this behavior and confirms that the body is posted correctly on subsequent retries?
I think this could be done via httptest.NewServer() and capturing the request data.

goshopify.go Outdated Show resolved Hide resolved
goshopify.go Show resolved Hide resolved
@cristoper
Copy link
Author

Thanks for looking at this so quickly! I updated my PR to add a test to goshopify_test.go as a separate commit (895bbb6) that fails if the retried request has an empty body. The test fails before this change (72f9cd9) is applied and passes after it is applied.

Copy link

codecov bot commented Jan 13, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Comparison is base (29e95fe) 100.00% compared to head (22bf9cd) 100.00%.

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #255   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           51        51           
  Lines         2191      2203   +12     
=========================================
+ Hits          2191      2203   +12     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@oliver006
Copy link
Collaborator

Thanks for updating that! CodeCov indicates that not all new changes are covered, can you have a look plz? It might be the err != nil check for ReadAll(). Not sure how to test that but I don't want move away from the 100% test coverage so quickly.

@cristoper
Copy link
Author

Yep, it was never hitting the error path for ReadAll(). I added a test which gives it an io.Reader that always returns an error, but I had to modify logBody to check for and return early on error so that it didn't replace the test body with a fresh bytes.Buffer. Coverage should be back to 100%.

@oliver006
Copy link
Collaborator

The tests still fail with an error, not entirely sure what the issue is.

Retries on 429 (rate limit) were not working for me (except for GET
requests). I would get these errors (retries result in a 400 Bad Request
every time):

[DEBUG] PUT: https://mydomain.myshopify.com/admin/api/2023-07/metafields/30029242335523.json
[DEBUG] SENT: {"metafield":{"created_at":"2023-08-30T19:55:54-06:00","description":"The SKU of the product.","id":30029242335523,"key":"sku","namespace":"ns","owner_id":8557574947107,"own
er_resource":"product","updated_at":"2023-08-30T19:55:54-06:00","value":"8bp-101009","type":"single_line_text_field","admin_graphql_api_id":"gid://shopify/Metafield/30029242335523"}}
[DEBUG] Shopify X-Request-Id: 6676e531-ee1e-4efa-96b2-88682553f930
[DEBUG] RECV 429: 429 Too Many Requests
[DEBUG] RESP: {"errors":"Exceeded 2 calls per second for api client. Reduce request rates to resume uninterrupted service."}
[DEBUG] rate limited waiting 2s
[DEBUG] Shopify X-Request-Id:
[DEBUG] RECV 400: 400 Bad Request
[DEBUG] RESP: <html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<hr><center>cloudflare</center>
</body>
</html>

The problem is that on retry, the same request with an
already-read Body was being sent. The solution that is working for me is
to copy the Body into a []byte buffer before the first request, and then
set the req.Body to that buffer before every request.
@cristoper
Copy link
Author

Oops, that's go vet complaining that I was pointlessly checking whether an error was of type error. I've updated to actually check for the expected error. It passes go vet and make test on my computer, so hopefully it's right this time!

Copy link
Collaborator

@oliver006 oliver006 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

@oliver006 oliver006 merged commit 2b22533 into bold-commerce:master Jan 14, 2024
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants