Skip to content

Commit 000963f

Browse files
committed
handle rate-limit exceptions
1 parent f960a44 commit 000963f

File tree

2 files changed

+36
-12
lines changed

2 files changed

+36
-12
lines changed

project/slacksync/management/commands/sync_slack_users.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ class Command(BaseCommand):
99

1010
def add_arguments(self, parser):
1111
parser.add_argument('--autodeactivate', action='store_true', help='Automatically deactivate users that are no longer members')
12+
parser.add_argument('--noresend', action='store_true', help='Automatically deactivate users that are no longer members')
1213

1314
pass
1415

@@ -18,8 +19,11 @@ def handle(self, *args, **options):
1819
autoremove = False
1920
if options['autodeactivate']:
2021
autoremove = True
22+
resend = True
23+
if options['noresend']:
24+
resend = False
2125
sync = SlackMemberSync()
22-
tbd = sync.sync_members(autoremove)
26+
tbd = sync.sync_members(autoremove, )
2327
if options['verbosity'] > 1:
2428
for dm in tbd:
2529
if autoremove:

project/slacksync/membersync.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
# -*- coding: utf-8 -*-
2+
import collections
23
import logging
34
import time
45

@@ -27,7 +28,7 @@ def get_slack_users_simple(self, slack, exclude_api_user=True):
2728
emails.append((member['id'], member['name'], member['profile']['email']))
2829
return emails
2930

30-
def sync_members(self, autodeactivate=False):
31+
def sync_members(self, autodeactivate=False, resend=True):
3132
"""Sync members, NOTE: https://github.com/ErikKalkoken/slackApiDoc/blob/master/users.admin.setInactive.md says
3233
deactivation via API works only on paid tiers"""
3334
if not api_configured():
@@ -36,15 +37,25 @@ def sync_members(self, autodeactivate=False):
3637
slack = get_client(session=session)
3738
slack_users = self.get_slack_users_simple(slack)
3839
slack_emails = set([x[2] for x in slack_users])
39-
add_members = Member.objects.exclude(email__in=slack_emails)
40-
for member in add_members:
40+
add_members = collections.deque(Member.objects.exclude(email__in=slack_emails))
41+
42+
while add_members.count():
43+
member = add_members.popleft()
4144
try:
42-
resp = slack.users.admin.invite(member.email)
45+
resp = slack.users.admin.invite(member.email, resend=resend)
4346
if 'ok' not in resp.body or not resp.body['ok']:
4447
self.logger.error("Could not invite {}, response: {}".format(member.email, resp.body))
45-
time.sleep(0.1) # rate-limit
48+
time.sleep(0.25) # rate-limit
4649
except Exception as e:
47-
logger.exception("Got exception when trying to invite {}".format(member.email))
50+
if 'Retry-After' in e.response.headers:
51+
wait_s = int(e.response.headers['Retry-After'])
52+
logger.warning("Asked to wait {}s".format(wait_s))
53+
time.sleep(wait_s)
54+
add_members.appendleft(member)
55+
continue
56+
else:
57+
logger.exception("Got exception when trying to invite {}".format(member.email))
58+
raise e
4859

4960
member_emails = set(Member.objects.values_list('email', flat=True))
5061
remove_slack_emails = slack_emails - member_emails
@@ -59,14 +70,23 @@ def sync_members(self, autodeactivate=False):
5970
return remove_usernames
6071

6172
userids_by_email = {x[2]: x[0] for x in slack_users}
62-
for email in remove_slack_emails:
73+
remove_iter = collections.deque(remove_slack_emails)
74+
while remove_iter.count():
75+
email = remove_iter.popleft()
6376
try:
6477
resp = slack.users.admin.setInactive(userids_by_email[email])
6578
if 'ok' not in resp.body or not resp.body['ok']:
66-
self.logger.error(
67-
"Could not deactivate {}, response: {}".format(email, resp.body))
68-
time.sleep(0.1) # rate-limit
79+
self.logger.error("Could not deactivate {}, response: {}".format(email, resp.body))
80+
time.sleep(0.25) # rate-limit
6981
except Exception as e:
70-
logger.exception("Got exception when trying to deactivate {}".format(email))
82+
if 'Retry-After' in e.response.headers:
83+
wait_s = int(e.response.headers['Retry-After'])
84+
logger.warning("Asked to wait {}s".format(wait_s))
85+
time.sleep(wait_s)
86+
remove_iter.appendleft(email)
87+
continue
88+
else:
89+
logger.exception("Got exception when trying to deactivate {}".format(email))
90+
raise e
7191

7292
return remove_usernames

0 commit comments

Comments
 (0)