Skip to content

GetCustomerInfoOperation: improve logic for caching responses#1292

Merged
NachoSoto merged 2 commits into
mainfrom
api-cache-ordering
Feb 15, 2022
Merged

GetCustomerInfoOperation: improve logic for caching responses#1292
NachoSoto merged 2 commits into
mainfrom
api-cache-ordering

Conversation

@NachoSoto

@NachoSoto NachoSoto commented Feb 13, 2022

Copy link
Copy Markdown
Contributor

Fixes [sc-12802].

Background

Before this change, the sequence illustrated by the new test testGetsUpdatedSubscriberInfoAfterPost (started in #1249, with a few modifications here) would fail:

  • GET /subscribers/
  • POST /receipts
  • GET /subscribers/

#1261 fixed the race condition in the test, making it so that operations are actually run serially.
However, when the first GET request finished, the second one shared the cache key, so it received the (soon to be) outdated CustomerInfo.

The fix

Unfortunately this fix is isolated for this specific issue, and not a generalized one. A more comprehensive rewrite of HTTPClient is needed ([sc-9521]).
I came up with several other alternatives, but what I ended up going with here involves the least amount of moving pieces.

If a GetCustomerInfoOperation request is enqueued with PostReceiptDataOperation in the queue, then a new unique cache key is created to avoid past GetCustomerInfoOperation to share outdated data.

If we simply added a random number to the GetCustomerInfoOperation cache key, the new test would have also passed. No other test verified the caching behavior, which is what the new testGetSubscriberInfoDoesNotMakeTwoRequests checks.

@NachoSoto NachoSoto requested review from a team and taquitos February 13, 2022 15:55
@shortcut-integration

Copy link
Copy Markdown

@joshdholtz joshdholtz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Fix looks good! Kind of wish it was a generalized solution but 🤷‍♂️ Just one small suggestion on tests.

Comment thread PurchasesTests/Networking/BackendTests.swift Outdated
Comment thread PurchasesTests/Networking/BackendTests.swift Outdated
@NachoSoto

NachoSoto commented Feb 14, 2022

Copy link
Copy Markdown
Contributor Author

Kind of wish it was a generalized solution but 🤷‍♂️

Me too trust me 😕 this fix isn't very satisfying. But understanding the whole issue now (that's why I documented here why it happens), I couldn't come up with something general that still avoids duplicated requests most of the time.

@NachoSoto

Copy link
Copy Markdown
Contributor Author

I'll wait for @taquitos to give this the thumbs up.

Fixes [sc-12802].

Before this change, the sequence illustrated by the new test `testGetsUpdatedSubscriberInfoAfterPost` (started in #1249, with a few modifications here) would fail:
- GET /subscribers/
- POST /receipts
- GET /subscribers/

However, when the first GET request finished, the second one shared the cache key, so it received the (soon to be) outdated `CustomerInfo`.

Unfortunately this fix is isolated for this specific issue, and not a generalized one. A more comprehensive rewrite of `HTTPClient` is needed ([sc-9521]).
I came up with several other alternatives, but what I ended up going with here involves the least amount of moving pieces.

If a `GetCustomerInfoOperation` request is enqueued with `PostReceiptDataOperation` in the queue, then a new unique cache key is created to avoid past `GetCustomerInfoOperation` to share outdata data.

If we simply added a random number to the `GetCustomerInfoOperation` cache key, the new test would have also passed. No other test verified the caching behavior, which is what the new `testGetSubscriberInfoDoesNotMakeTwoRequests` checks.
@NachoSoto

Copy link
Copy Markdown
Contributor Author

I implemented this on Android too: RevenueCat/purchases-android#486

@taquitos taquitos left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🚢 it!

@NachoSoto

Copy link
Copy Markdown
Contributor Author

@joshdholtz the changes look good to you?

@joshdholtz joshdholtz left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Love those changes! 🔥

@NachoSoto NachoSoto merged commit 9c583eb into main Feb 15, 2022
@NachoSoto NachoSoto deleted the api-cache-ordering branch February 15, 2022 23:13
NachoSoto added a commit to RevenueCat/purchases-android that referenced this pull request Feb 22, 2022
Android equivalent to RevenueCat/purchases-ios#1249 and RevenueCat/purchases-ios#1292.
Finishes [sc-12802].

## Background

Before this change, the sequence illustrated by the new test `"gets updated customer after posting receipt data"` would fail:
- GET /subscribers/
- POST /receipts
- GET /subscribers/

When the first GET request finishes, the second one shares the cache key, so it receives the (soon to be) outdated `CustomerInfo`.

## The fix

Unfortunately this fix is isolated for this specific issue, and not a generalized one.
I came up with several other alternatives, but what I ended up going with here involves the least amount of moving pieces.

If a `getCustomerInfo` request is enqueued with `postReceiptData` in the queue, then a new unique cache key is created to avoid past `getCustomerInfo` to share outdated data.

If we simply added a random number to the `getCustomerInfo` cache key,  the test `"given multiple get calls for same subscriber, only one is triggered"` fails, so that's still verifying the previous behavior works.
NachoSoto added a commit that referenced this pull request Sep 19, 2022
…iptDataOperation` in progress

Fixes [CSDK-419].

This is an improvement over the fix in #1292. In there, we avoided appending on an existing `CustomerInfoOperation` if there were any `PostReceiptDataOperation`s in progress, because those might come back with outdated entitlements.
This fix removes that cache key hack, and instead *reuses* the entire response to that `PostReceiptDataOperation` by "stealing" that request's cache key.

This is perfectly captured by the existing test `BackendPostReceiptDataTests.testGetsUpdatedSubscriberInfoAfterPost`, added in #1292. Amazingly enough, that test still passes with one minor (:panda:) change: the entire process requires one fewer API call :tada:
NachoSoto added a commit that referenced this pull request Sep 21, 2022
…iptDataOperation` in progress (#1911)

Fixes [CSDK-419].

This is an improvement over the fix in #1292. In there, we avoided
appending on an existing `CustomerInfoOperation` if there were any
`PostReceiptDataOperation`s in progress, because those might come back
with outdated entitlements.
This fix removes that cache key hack, and instead *reuses* the entire
response to that `PostReceiptDataOperation` by "stealing" that request's
cache key.

This is perfectly captured by the existing test
`BackendPostReceiptDataTests.testGetsUpdatedSubscriberInfoAfterPost`,
added in #1292. Amazingly enough, that test still passes with one minor
change: the entire process requires one fewer API call 🎉 🐼

[CSDK-419]:
https://revenuecats.atlassian.net/browse/CSDK-419?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
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.

4 participants