-
Notifications
You must be signed in to change notification settings - Fork 29
Safe refresh #32
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
Closed
Closed
Safe refresh #32
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
f7dc1c3
safely refresh tokens in parallel environment
brad 7e9f9ba
fix problem queueing tasks test
brad efe782a
fix token expiration test
brad 3e23eb2
iron out issues from the refactor
brad 4c5e220
drop django 1.4 and python 2.6 support
brad 97f5b8e
remove debugging statement
brad 802d7a0
fix tests on python 3
brad 89df0b5
give the migration a human readable name
brad File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # -*- coding: utf-8 -*- | ||
| from __future__ import unicode_literals | ||
|
|
||
| from django.db import migrations, models | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('fitapp', '0005_upgrade_oauth1_tokens_to_oauth2'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AddField( | ||
| model_name='userfitbit', | ||
| name='expires_at', | ||
| field=models.FloatField(default=0), | ||
| preserve_default=False, | ||
| ), | ||
| migrations.AddField( | ||
| model_name='userfitbit', | ||
| name='timezone', | ||
| field=models.CharField(default='UTC', max_length=128), | ||
| preserve_default=False, | ||
| ), | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,22 +12,42 @@ | |
|
|
||
|
|
||
| logger = logging.getLogger(__name__) | ||
| LOCK_EXPIRE = 60 * 5 # Lock expires in 5 minutes | ||
| LOCK_EXPIRE = 60 * 5 # Lock expires in 5 minutes | ||
|
|
||
|
|
||
| def _hit_rate_limit(exc, task): | ||
| # We have hit the rate limit for the user, retry when it's reset, | ||
| # according to the reply from the failing API call | ||
| logger.debug('Rate limit reached, will try again in %s seconds' % | ||
| exc.retry_after_secs) | ||
| raise task.retry(exc=exc, countdown=exc.retry_after_secs) | ||
|
|
||
|
|
||
| def _generic_task_exception(exc, task_name): | ||
| logger.exception("Exception running task %s: %s" % (task_name, exc)) | ||
| raise Reject(exc, requeue=False) | ||
|
|
||
|
|
||
| @shared_task | ||
| def subscribe(fitbit_user, subscriber_id): | ||
| """ Subscribe to the user's fitbit data """ | ||
|
|
||
| fbusers = UserFitbit.objects.filter(fitbit_user=fitbit_user) | ||
| for fbuser in fbusers: | ||
| """ Subscribe the user and retrieve historical data for it """ | ||
| update_user_timezone.apply_async((fitbit_user,), countdown=1) | ||
| for fbuser in UserFitbit.objects.filter(fitbit_user=fitbit_user): | ||
| fb = utils.create_fitbit(**fbuser.get_user_data()) | ||
| try: | ||
| fb.subscription(fbuser.user.id, subscriber_id) | ||
| except: | ||
| exc = sys.exc_info()[1] | ||
| logger.exception("Error subscribing user: %s" % exc) | ||
| raise Reject(exc, requeue=False) | ||
| except HTTPTooManyRequests: | ||
| _hit_rate_limit(sys.exc_info()[1], subscribe) | ||
| except Exception: | ||
| _generic_task_exception(sys.exc_info()[1], 'subscribe') | ||
|
|
||
| # Create tasks for all data in all data types | ||
| for i, _type in enumerate(TimeSeriesDataType.objects.all()): | ||
| # Delay execution for a few seconds to speed up response Offset each | ||
| # call by 5 seconds so they don't bog down the server | ||
| get_time_series_data.apply_async( | ||
| (fitbit_user, _type.category, _type.resource,), | ||
| countdown=10 + (i * 5)) | ||
|
|
||
|
|
||
| @shared_task | ||
|
|
@@ -40,11 +60,10 @@ def unsubscribe(*args, **kwargs): | |
| if sub['ownerId'] == kwargs['user_id']: | ||
| fb.subscription(sub['subscriptionId'], sub['subscriberId'], | ||
| method="DELETE") | ||
| except: | ||
| exc = sys.exc_info()[1] | ||
| logger.exception("Error unsubscribing user: %s" % exc) | ||
| raise Reject(exc, requeue=False) | ||
|
|
||
| except HTTPTooManyRequests: | ||
| _hit_rate_limit(sys.exc_info()[1], unsubscribe) | ||
| except Exception: | ||
| _generic_task_exception(sys.exc_info()[1], 'unsubscribe') | ||
|
|
||
|
|
||
| @shared_task | ||
|
|
@@ -83,12 +102,7 @@ def get_time_series_data(fitbit_user, cat, resource, date=None): | |
| # Release the lock | ||
| cache.delete(lock_id) | ||
| except HTTPTooManyRequests: | ||
| # We have hit the rate limit for the user, retry when it's reset, | ||
| # according to the reply from the failing API call | ||
| e = sys.exc_info()[1] | ||
| logger.debug('Rate limit reached, will try again in %s seconds' % | ||
| e.retry_after_secs) | ||
| raise get_time_series_data.retry(exc=e, countdown=e.retry_after_secs) | ||
| _hit_rate_limit(sys.exc_info()[1], get_time_series_data) | ||
| except HTTPBadRequest: | ||
| # If the resource is elevation or floors, we are just getting this | ||
| # error because the data doesn't exist for this user, so we can ignore | ||
|
|
@@ -98,6 +112,22 @@ def get_time_series_data(fitbit_user, cat, resource, date=None): | |
| logger.exception("Exception updating data: %s" % exc) | ||
| raise Reject(exc, requeue=False) | ||
| except Exception: | ||
| exc = sys.exc_info()[1] | ||
| logger.exception("Exception updating data: %s" % exc) | ||
| raise Reject(exc, requeue=False) | ||
| _generic_task_exception(sys.exc_info()[1], 'get_time_series_data') | ||
|
|
||
|
|
||
| @shared_task | ||
| def update_user_timezone(fitbit_user): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
| """ Get the user's profile and update the timezone we have on file """ | ||
|
|
||
| fbusers = UserFitbit.objects.filter(fitbit_user=fitbit_user) | ||
| try: | ||
| for fbuser in fbusers: | ||
| fb = utils.create_fitbit(**fbuser.get_user_data()) | ||
| profile = fb.user_profile_get() | ||
| fbuser.timezone = profile['user']['timezone'] | ||
| fbuser.save() | ||
| utils.check_for_new_token(fbuser, fb.client.token) | ||
| except HTTPTooManyRequests: | ||
| _hit_rate_limit(sys.exc_info()[1], update_user_timezone) | ||
| except Exception: | ||
| _generic_task_exception(sys.exc_info()[1], 'update_user_timezone') | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brad I see that the migration file for the
timezonefield hasdefault='UTC'. Did you removedefault='UTC'here after the migration file was created? If not, howdefault='UTC'was added to the migration file?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@percyperez When I ran
makemigrationsit asked for a default and I specifieUTCThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@brad Ah Cool 👍