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

refactor: reduce DB updates by traits update requests without real changes in the data #4451

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

devapro
Copy link

@devapro devapro commented Aug 5, 2024

Thanks for submitting a PR! Please check the boxes below:

  • I have added information to docs/ if required so people know about the feature!
  • I have filled in the "Changes" section below?
  • I have filled in the "How did you test this code" section below?
  • I have used a Conventional Commit title for this Pull Request

Changes

It is common case for mobile app to set traits on the app start, because some properties can be changed offline or by request from another device with the same account etc. However in this case db is update even if no changes in the data. This change should reduce updates by getting list of traits from db than compares the existing and incoming data, and only add/update when the data actually changes. This strategy drastically reduces unnecessary UPDATE operations in case when the clients send requests with the same data.

How did you test this code?

manually

Please describe.

@devapro devapro requested a review from a team as a code owner August 5, 2024 19:16
@devapro devapro requested review from zachaysan and removed request for a team August 5, 2024 19:16
Copy link

vercel bot commented Aug 5, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

1 Skipped Deployment
Name Status Preview Comments Updated (UTC)
docs ⬜️ Ignored (Inspect) Visit Preview Aug 9, 2024 1:48pm

Copy link

vercel bot commented Aug 5, 2024

@devapro is attempting to deploy a commit to the Flagsmith Team on Vercel.

A member of the Team first needs to authorize it.

Copy link

sentry-io bot commented Aug 5, 2024

🔍 Existing Issues For Review

Your pull request is modifying functions with the following pre-existing issues:

📄 File: api/environments/identities/traits/views.py

Function Unhandled Issue
bulk_create KeyError: 'identifier' /api/v1/traits/bulk/
Event Count: 1

Did you find this useful? React with a 👍 or 👎

@github-actions github-actions bot added the api Issue related to the REST API label Aug 5, 2024
Copy link
Contributor

github-actions bot commented Aug 6, 2024

Uffizzi Ephemeral Environment deployment-56255

☁️ https://app.uffizzi.com/github.com/Flagsmith/flagsmith/pull/4451

📄 View Application Logs etc.

What is Uffizzi? Learn more!

Copy link

codecov bot commented Aug 6, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 97.18%. Comparing base (5cbdd7f) to head (39d82cd).
Report is 121 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4451      +/-   ##
==========================================
+ Coverage   96.85%   97.18%   +0.32%     
==========================================
  Files        1170     1163       -7     
  Lines       38812    40289    +1477     
==========================================
+ Hits        37592    39153    +1561     
+ Misses       1220     1136      -84     

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

zachaysan
zachaysan previously approved these changes Aug 6, 2024
Copy link
Contributor

@zachaysan zachaysan left a comment

Choose a reason for hiding this comment

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

Looks good. Though it seems like CI has failed for this test, perhaps try re-running the test suite with an empty commit?

Copy link
Contributor

@matthewelwell matthewelwell left a comment

Choose a reason for hiding this comment

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

Though it seems like CI has failed for this test, perhaps try re-running the test suite with an empty commit?

This is actually an issue in our CI workflows that don't work correctly for external contributors. We are working to resolve this.

I've added a comment to a specific part of the diff but, in general, I'd also like to see a test / some tests written for this logic.

Comment on lines 304 to 306
return Response(serializer.data if traits else [], status=200)

return Response(traits, status=200)
Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm... this actually looks like it changes the behaviour of the endpoint which could have an effect on clients. Previously, we are always returning the traits that were sent (assuming they were valid). Now we're sending an empty list if none of the traits are actually updated / created.

Perhaps we could do something like the following:

all_traits = [*traits, *SDKCreateUpdateTraitSerializer(instance=existing_traits, many=True).data]
return Response(all_traits)

Copy link
Author

Choose a reason for hiding this comment

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

Thank you for review.
I made changes, now traits always added to the response.
Moved all logic of updating traits to new method, I think it will be a bit easy to read an understand in this case.

Copy link
Contributor

@matthewelwell matthewelwell 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 changes @devapro . I've added a couple more comments.

As per my previous review though, it's still missing any sort of testing coverage.

api/environments/identities/traits/views.py Outdated Show resolved Hide resolved
api/environments/identities/traits/views.py Outdated Show resolved Hide resolved
@matthewelwell
Copy link
Contributor

@devapro just checking in to see if you had time to look at my recent review comments and whether you might have time to update the PR?

@devapro
Copy link
Author

devapro commented Aug 22, 2024

Sorry for long response, will check your comments next week.

@devapro
Copy link
Author

devapro commented Aug 26, 2024

Thanks for the changes @devapro . I've added a couple more comments.

As per my previous review though, it's still missing any sort of testing coverage.

I checked existing unit tests and looks like it is covered all logic that I refactored.
I think will be good to add test that checks case when db is not called, but my knowledge in python very limited, I didn't find an example of how to do it in current code.

Copy link
Contributor

@matthewelwell matthewelwell left a comment

Choose a reason for hiding this comment

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

This is looking better. I've left 2 fairly minor additional comments, but I think it's pretty close.

try:
if not request.environment.trait_persistence_allowed(request):
raise BadRequest("Unable to set traits with client key.")
def _update_traits(self, request):
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
def _update_traits(self, request):
def _update_traits(self, request: Request) -> None:

Copy link
Author

Choose a reason for hiding this comment

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

✔️

api/environments/identities/traits/views.py Show resolved Hide resolved
@matthewelwell
Copy link
Contributor

I think will be good to add test that checks case when db is not called, but my knowledge in python very limited, I didn't find an example of how to do it in current code.

You can just copy one of the existing tests, manipulate the data to be what you want and then use the django_assert_num_queries fixture to do something like:

with django_assert_num_queries(0):
    ... 

You'll find plenty of usages of this fixture throughout the code base.

@devapro
Copy link
Author

devapro commented Sep 20, 2024

I think will be good to add test that checks case when db is not called, but my knowledge in python very limited, I didn't find an example of how to do it in current code.

You can just copy one of the existing tests, manipulate the data to be what you want and then use the django_assert_num_queries fixture to do something like:

with django_assert_num_queries(0):
    ... 

You'll find plenty of usages of this fixture throughout the code base.

I can't find existing test for method that I changed. It is not simple for me to understand how to write new test for specific method.

Didn't manage to run tests locally, for running project I am using docker + mounting specific files with changes, because can't install all required dependencies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api Issue related to the REST API
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants