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

feat: Add idempotency feature to detect duplicate requests due to network conditions #1190

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

DrMimik
Copy link

@DrMimik DrMimik commented Mar 16, 2023

New Pull Request Checklist

Issue Description

Requests are duplicated on slow internet connections and during network interruptions.

Closes: #764

Approach

Add idempotency requestId header for client requests to enforce server side idempotency middleware on selected routes..

TODOs before merging

  • Add tests
  • Add changes to documentation (guides, repository pages, in-code descriptions)

@parse-github-assistant
Copy link

parse-github-assistant bot commented Mar 16, 2023

Thanks for opening this pull request!

  • 🎉 We are excited about your hands-on contribution!

@DrMimik DrMimik changed the title Idempotent Requests Implementation fix: duplicate requests Mar 16, 2023
@parse-github-assistant
Copy link

I will reformat the title to use the proper commit message syntax.

@parse-github-assistant parse-github-assistant bot changed the title fix: duplicate requests fix: Duplicate requests Mar 16, 2023
@DrMimik DrMimik changed the title fix: Duplicate requests fix: Duplicate Requests Mar 16, 2023
if (masterKey != null)
jsonObject.put(HEADER_MASTER_KEY, masterKey);
requestBuilder.addHeader(HEADER_REQUEST_ID, ParseDigestUtils.md5(toDeterministicString(jsonObject)));
} catch (JSONException e) {
Copy link
Member

Choose a reason for hiding this comment

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

The OS should provide a UUID API that takes care of seeding. Could you use the same logic for generating the UUID as we use in the other SDKs? For example the iOS SDK and JS SDK?

Copy link
Author

Choose a reason for hiding this comment

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

I have rewritten the logic to use a UUID, as this is uniformed between SDKs.

But imo why isn't the UUID data based?, like this if the SDK calls ParseObject.save() it changes the ParseRequest which creates a new UUID, while using a data based UUID calling save won't change the UUID header.

Currently if I want the SDK to create an idempotent request I'd still set the HttpClient to use a longer timeout and increase the default max retries of requests.

Copy link
Author

@DrMimik DrMimik Mar 17, 2023

Choose a reason for hiding this comment

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

I am not very good at JS, but could you direct me to where the iOS SDK implements the logic.

Copy link
Member

Choose a reason for hiding this comment

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

But imo why isn't the UUID data based?

It doesn't need to be based on object data. A UUID is a Universally Unique IDentifier, which ensures that every generated UUID is unique.

The part you'd have to take care about in the PR is that for a ParseObject.save that UUID is only generated one time and then reused if the request fails and the SDK auto-retries the request. Obviously, if you generated a new UUID with ever retry of the same request, then this wouldn't work.

Copy link
Author

@DrMimik DrMimik Mar 18, 2023

Choose a reason for hiding this comment

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

The current approach works as follows if all requests were unsuccessfull:

ParseObject object = new ParseObject("GameScore");
// calls a request and retries according to the max retries (default is 4), with the same requestId header. (5 calls with the same header)
object.save();

// this second method call... calls a request and retries according to the max retries set, with the same requestId header but different than the first save() method call.
object.save();

Copy link
Member

@mtrezza mtrezza Mar 18, 2023

Choose a reason for hiding this comment

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

with the same requestId header but different than the first save() method call.

Not sure what how to read that. The second save call should use a different UUID for the request ID than the first call. In fact, every save call should use its own UUID. Only auto-retries of each save call should re-use their initial UUID.

Copy link
Author

Choose a reason for hiding this comment

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

Yes, It is using exactly that. My explanation was kind of confusing.

I'll add a second test using the code in my previous comment.

@mtrezza mtrezza changed the title fix: Duplicate Requests feat: Add indempotency feature to detect duplicate requests due to network conditions Mar 16, 2023
@mtrezza mtrezza changed the title feat: Add indempotency feature to detect duplicate requests due to network conditions feat: Add idempotency feature to detect duplicate requests due to network conditions Mar 16, 2023
@DrMimik
Copy link
Author

DrMimik commented Mar 17, 2023

Should I force push the first commit? or use a new commit?.

@codecov
Copy link

codecov bot commented Mar 19, 2023

Codecov Report

Patch and project coverage have no change.

Comparison is base (5ebd443) 0.00% compared to head (039d197) 0.00%.

Additional details and impacted files
@@          Coverage Diff           @@
##           master   #1190   +/-   ##
======================================
  Coverage    0.00%   0.00%           
======================================
  Files         122     122           
  Lines        9971    9973    +2     
  Branches     1345    1345           
======================================
- Misses       9971    9973    +2     
Impacted Files Coverage Δ
parse/src/main/java/com/parse/ParseException.java 0.00% <ø> (ø)
...arse/src/main/java/com/parse/ParseRESTCommand.java 0.00% <0.00%> (ø)

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@azlekov
Copy link
Contributor

azlekov commented May 16, 2023

Should I force push the first commit? or use a new commit?.

New commit is preferable to track changes and reviewing it easily.
Hoping to get this merged.

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.

ParseObject saved multiple times on slow internet connection
3 participants