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

Only Retry POST Receipt Paths for 429 #4107

Merged
merged 8 commits into from
Jul 25, 2024
Merged

Conversation

fire-at-will
Copy link
Contributor

@fire-at-will fire-at-will commented Jul 24, 2024

Description

This PR modifies the HTTPClient's retry logic to only perform retries on requests to the /v1/receipts URL path that result in a 429 status code.

Testing

  • Updated existing tests to set the isRetryable field correctly
  • Added unit tests to HTTPClient.Request to ensure that the isRetryable field is being set properly
  • Wrote new unit & integration tests to ensure that we don't retry requests to unsupported endpoints (like /v1/subscribers/identify)

isRetryable = Bool(isRetryableString.lowercased()) ?? true
} else {
isRetryable = true
let doesServerAllowRetryString = urlResponse.value(forHTTPHeaderField: ResponseHeader.isRetryable.rawValue)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

No change in the logic, just renaming isRetryable to doesServerAllowRetry to be more clear

@fire-at-will
Copy link
Contributor Author

@RCGitBot please test

@fire-at-will fire-at-will requested review from aboedo, MarkVillacampa and a team July 24, 2024 17:34
@fire-at-will
Copy link
Contributor Author

Some of the test checks look a little funny right now because it took me a moment to figure out how to run all of the tests, I'll make sure they're all good to go before merging 💪

@@ -173,7 +175,7 @@ class OtherIntegrationTests: BaseBackendIntegrationTests {
try AvailabilityChecks.iOS15APIAvailableOrSkipTest()

let result = try await self.purchases.productEntitlementMapping().entitlementsByProduct
expect(result).to(haveCount(18))
expect(result).to(haveCount(21))
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not sure when (the audit logs aren't loading for me), but we now have 21 iOS products in the StoreKit Integration Tests app instead of 18

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm looking into this a little more to confirm why this has changed

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The most recently added product to the project was on June 25, so this isn't an issue with a new product being present. Continuing to dig 👀

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The test is currently failing in main with the value 18, but passed during yesterday's release pipeline 🧐

https://app.circleci.com/pipelines/github/RevenueCat/purchases-ios/20914/workflows/68cd311d-9aec-47a8-8f55-889bef8bdabc

Copy link
Member

Choose a reason for hiding this comment

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

@RevenueCat/coresdk thoughts?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Josh and I took a look at some network logs and found that the backend was returning 18 mappings on Tuesday when the test passed, but is now returning 21 in the network calls to /v1/product_entitlement_mapping. This is happening on this branch, main, and the 4.32.2 release. We now believe that 21 is the correct number and are following up with the backend team to investigate what caused the change to take so long to appear.

Copy link
Member

@aboedo aboedo left a comment

Choose a reason for hiding this comment

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

looking good so far

Comment on lines 674 to 676
var doesServerAllowRetry: Bool = true
if let doesServerAllowRetryString = doesServerAllowRetryString {
doesServerAllowRetry = Bool(doesServerAllowRetryString.lowercased()) ?? true
Copy link
Member

Choose a reason for hiding this comment

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

I'm sure this version is more clever, but it was kinda clearer before the ternary IMO

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm okay reverting it! I'll keep the name doesServerAllowRetry over isRetryable though 😅


init(method: Method, path: HTTPRequest.Path, nonce: Data? = nil) {
self.init(method: method, requestPath: path, nonce: nonce)
/// Whether or not this reqeust should be retried by the HTTPClient for certain status codes.
Copy link
Member

Choose a reason for hiding this comment

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

typo request

@@ -173,7 +175,7 @@ class OtherIntegrationTests: BaseBackendIntegrationTests {
try AvailabilityChecks.iOS15APIAvailableOrSkipTest()

let result = try await self.purchases.productEntitlementMapping().entitlementsByProduct
expect(result).to(haveCount(18))
expect(result).to(haveCount(21))
Copy link
Member

Choose a reason for hiding this comment

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

@RevenueCat/coresdk thoughts?

@@ -935,6 +935,7 @@ class StoreKit1IntegrationTests: BaseStoreKitIntegrationTests {
}

func testVerifyPurchaseGrantsEntitlementsThroughOnRetryAfter429() async throws {
defer { HTTPStubs.removeAllStubs() }
Copy link
Member

Choose a reason for hiding this comment

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

should this just be a setup or teardown?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Moved it to the tearDown functions 😎

@fire-at-will
Copy link
Contributor Author

fire-at-will commented Jul 25, 2024

Hey @aboedo! Since your last review, I've made the following changes:

Code Changes

  • Reverted the syntax when computing doesServerAllowRetry
  • Fixed the "request" typo in HTTPRequest.swift
  • Moved the HTTPStubs.removeAllStubs() calls in the tests from a defer statements to the tearDown functions

Test Fixes/Clarifications

  • Fixed the configuration issues that were causing the CustomEntitlementsComputationIntegrationTests to fail
  • Dug into why OtherIntegrationTests.testProductEntitlementMapping was returning 21 mappings instead of 18. Josh and I took a look at some network logs and found that the backend was returning 18 mappings on Tuesday when the test passed, but is now returning 21 in the network calls to /v1/product_entitlement_mapping. This is happening on this branch, main, and the 4.32.2 release. We now believe that 21 is the correct number and are following up with the backend team to investigate what caused the change to take so long to appear.

This should be ready for another look!

@fire-at-will fire-at-will requested a review from aboedo July 25, 2024 12:22
@fire-at-will fire-at-will merged commit 348258a into main Jul 25, 2024
32 checks passed
@fire-at-will fire-at-will deleted the only-retry-post-receipt branch July 25, 2024 21:46
@fire-at-will fire-at-will mentioned this pull request Jul 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants