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

Closed
wants to merge 3 commits into from

Conversation

ghost
Copy link

@ghost ghost 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!

@ghost ghost 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
@ghost ghost 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

@ghost ghost 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

@ghost ghost 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
@ghost
Copy link
Author

ghost 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

Attention: Patch coverage is 0% with 2 lines in your changes missing coverage. Please review.

Project coverage is 0.00%. Comparing base (83aec68) to head (039d197).
Report is 1 commits behind head on master.

Current head 039d197 differs from pull request most recent head 76673eb

Please upload reports for the commit 76673eb to get more accurate results.

Files Patch % Lines
...arse/src/main/java/com/parse/ParseRESTCommand.java 0.00% 2 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##           master   #1190    +/-   ##
=======================================
  Coverage    0.00%   0.00%            
=======================================
  Files         124     122     -2     
  Lines       10076    9973   -103     
  Branches     1359    1345    -14     
=======================================
+ Misses      10076    9973   -103     

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

@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.

@dplewis
Copy link
Member

dplewis commented Jun 7, 2024

@mtrezza Looks like this is ready for review

Copy link
Member

@mtrezza mtrezza left a comment

Choose a reason for hiding this comment

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

Lint failed

@ghost ghost closed this Aug 3, 2024
@ghost ghost deleted the idempotent-requests branch August 3, 2024 19:15
@mtrezza
Copy link
Member

mtrezza commented Aug 5, 2024

@parse-community/android-sdk anyone wants to pick this up and submit a new PR? It seems this was almost ready for merge, except for lint issues.

@abubkr-hago
Copy link

Hi, I am a new contributor, I would love to continue on this PR

@rommansabbir
Copy link
Member

Hi, I am a new contributor, I would love to continue on this PR

That would be great!.

@mtrezza
Copy link
Member

mtrezza commented Aug 14, 2024

Sure, please go ahead.

This pull request was closed.
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
5 participants