Skip to content

Commit 4d062d9

Browse files
committed
updating the code with exponential backoff for when it tries to retrieve a user
1 parent 9fbb527 commit 4d062d9

File tree

1 file changed

+88
-45
lines changed

1 file changed

+88
-45
lines changed

wall_e/extensions/leveling.py

Lines changed: 88 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,15 @@
77
import discord
88
import pytz
99
from discord import NotFound, app_commands, Guild
10-
from discord.errors import DiscordServerError, HTTPException
10+
from discord.errors import DiscordException
1111
from discord.ext import commands, tasks
1212

13-
from utilities.global_vars import bot, wall_e_config
14-
15-
from wall_e_models.models import Level, UserPoint, UpdatedUser, ProfileBucketInProgress
16-
1713
from utilities.embed import embed, COLOUR_MAPPING, WallEColour
1814
from utilities.file_uploading import start_file_uploading
15+
from utilities.global_vars import bot, wall_e_config
1916
from utilities.paginate import paginate_embed
2017
from utilities.setup_logger import Loggers
21-
22-
BUGGY_USER = [234501345749630976]
18+
from wall_e_models.models import Level, UserPoint, UpdatedUser, ProfileBucketInProgress
2319

2420

2521
class Leveling(commands.Cog):
@@ -53,9 +49,10 @@ def __init__(self):
5349
self.council_channel = None
5450
self.levelling_website_avatar_channel = None
5551
self.bucket_update_in_progress = False
52+
self.NUMBER_OF_RETRIEVAL_ATTEMPTS_PER_USER = 15
5653
self.ensure_xp_roles_exist_and_have_right_users.start()
5754
self.process_leveling_profile_data_for_lurkers.start()
58-
self.process_outdated_profile_pics.start()
55+
# self.process_outdated_profile_pics.start()
5956
self.process_leveling_profile_data_for_active_users.start()
6057

6158
@commands.Cog.listener(name="on_ready")
@@ -67,7 +64,8 @@ async def upload_debug_logs(self):
6764
while self.guild is None:
6865
await asyncio.sleep(2)
6966
await start_file_uploading(
70-
self.logger, self.guild, bot, wall_e_config, self.debug_log_file_absolute_path, "leveling_debug"
67+
self.logger, self.guild, bot, wall_e_config, self.debug_log_file_absolute_path,
68+
"leveling_debug"
7169
)
7270

7371
@commands.Cog.listener(name="on_ready")
@@ -84,7 +82,8 @@ async def upload_error_logs(self):
8482
while self.guild is None:
8583
await asyncio.sleep(2)
8684
await start_file_uploading(
87-
self.logger, self.guild, bot, wall_e_config, self.error_log_file_absolute_path, "leveling_error"
85+
self.logger, self.guild, bot, wall_e_config, self.error_log_file_absolute_path,
86+
"leveling_error"
8887
)
8988

9089
@commands.Cog.listener(name="on_ready")
@@ -558,7 +557,7 @@ async def process_leveling_profile_data_for_lurkers(self):
558557
f"[Leveling process_leveling_profile_data_for_lurkers()] {user_ids_to_update} "
559558
f"potential updates retrieved for bucket {entry.bucket_number_completed}"
560559
)
561-
await self._update_users(self.process_lurkers_logger, user_ids_to_update)
560+
await self._update_users_with_given_ids(self.process_lurkers_logger, user_ids_to_update)
562561
await ProfileBucketInProgress.async_save(entry)
563562

564563
async def _set_bucket_numbers(self, logger):
@@ -671,37 +670,40 @@ async def _get_current_bucket_number(self) -> ProfileBucketInProgress:
671670
entry.bucket_number_completed = 1
672671
return entry
673672

674-
async def _update_users(self, logger, updated_user_ids):
673+
async def _update_users_with_given_ids(self, logger, updated_user_ids):
675674
"""
676675
iterates through the given list of user_ids and updates them
677676
:param updated_user_ids:
678677
:return:
679678
"""
680679
total_number_of_updates_needed = len(updated_user_ids)
681680
for index, user_id in enumerate(updated_user_ids):
681+
successful = False
682682
logger.debug(
683-
f"[Leveling _update_users()] attempting to get updated user_point profile data for member {user_id} "
684-
f"{index + 1}/{total_number_of_updates_needed} "
683+
f"[Leveling _update_users_with_given_ids()] attempt "
684+
f"{self.user_points[user_id].leveling_update_attempt} to get updated user_point profile data for "
685+
f"member {user_id} {index + 1}/{total_number_of_updates_needed} "
685686
)
686-
member = None
687-
try:
688-
member = await self.guild.fetch_member(user_id)
689-
except (NotFound, DiscordServerError) as e:
690-
try:
691-
logger.info(
692-
f"[Leveling _update_users()] got following error when fetching guild member {user_id}\n{e}"
693-
)
694-
member = await bot.fetch_user(user_id)
695-
except DiscordServerError as e:
696-
logger.error(
697-
f"[Leveling _update_users()] got the following error when fetching member {user_id}\n{e}."
698-
)
699-
except HTTPException as e:
700-
logger.warn(
701-
f"[Leveling _update_users()] got the following error when fetching member {user_id}\n{e}."
687+
while (
688+
not successful and
689+
self.user_points[user_id].leveling_update_attempt < self.NUMBER_OF_RETRIEVAL_ATTEMPTS_PER_USER
690+
):
691+
self.user_points[user_id].leveling_update_attempt += 1
692+
random_number_milliseconds = random.randint(0, 1000) / 1000
693+
sleep_seconds = math.pow(
694+
2, self.user_points[user_id].leveling_update_attempt + random_number_milliseconds
695+
)
696+
logger.debug(
697+
f"[Leveling _update_users_with_given_ids()] Sleeping for {sleep_seconds} before attempt "
698+
f"{self.user_points[user_id].leveling_update_attempt} when trying to update user_point profile "
699+
f"data for member {user_id}."
702700
)
703-
if member:
704-
await self._update_member_profile_data(logger, member, user_id, index, total_number_of_updates_needed)
701+
await asyncio.sleep(sleep_seconds)
702+
member = await self.get_user(logger, user_id)
703+
if member:
704+
successful = await self._update_member_profile_data(
705+
logger, member, user_id, index, total_number_of_updates_needed
706+
)
705707

706708
@tasks.loop(seconds=2)
707709
async def process_leveling_profile_data_for_active_users(self):
@@ -717,19 +719,59 @@ async def process_leveling_profile_data_for_active_users(self):
717719
for index, update_user in enumerate(updated_user_logs):
718720
updated_user_log_id = update_user[0] # noqa: F841
719721
updated_user_id = update_user[1]
722+
successful = False
720723
self.logger.debug(
721-
f"[Leveling process_leveling_profile_data_for_active_users()] attempting to get updated "
722-
f"user_point profile data for member {updated_user_id} "
723-
f"{index + 1}/{total_number_of_updates_needed} "
724+
f"[Leveling process_leveling_profile_data_for_active_users()] attempt "
725+
f"{self.user_points[updated_user_id].leveling_update_attempt} to get data for user in UpdatedUser"
726+
f" with id {updated_user_id} {index + 1}/{total_number_of_updates_needed} "
724727
)
728+
while (
729+
not successful and
730+
self.user_points[updated_user_id].leveling_update_attempt <
731+
self.NUMBER_OF_RETRIEVAL_ATTEMPTS_PER_USER
732+
):
733+
self.user_points[updated_user_id].leveling_update_attempt += 1
734+
random_number_milliseconds = random.randint(0, 1000) / 1000
735+
sleep_seconds = math.pow(
736+
2, self.user_points[updated_user_id].leveling_update_attempt + random_number_milliseconds
737+
)
738+
self.logger.debug(
739+
f"[Leveling process_leveling_profile_data_for_active_users()] Sleeping for {sleep_seconds} before"
740+
f" attempt {self.user_points[updated_user_id].leveling_update_attempt} when trying to get data"
741+
f" for user in UpdatedUser with id {updated_user_id}."
742+
)
743+
await asyncio.sleep(sleep_seconds)
744+
member = await self.get_user(self.logger, updated_user_id)
745+
if member:
746+
# cannot call _update_users_with_given_ids like process_outdated_profile_pics and
747+
# process_leveling_profile_data_for_lurkers because this task needs to be able to specify a
748+
# updated_user_log_id that will be deleted update_leveling_profile_info when the user is processed
749+
successful = await self._update_member_profile_data(
750+
self.logger, member, updated_user_id, index, total_number_of_updates_needed,
751+
updated_user_log_id=updated_user_log_id
752+
)
753+
754+
async def get_user(self, logger, user_id):
755+
user = None
756+
try:
757+
user = await self.guild.fetch_member(user_id)
758+
except NotFound as e:
725759
try:
726-
member = await self.guild.fetch_member(updated_user_id)
727-
except NotFound:
728-
member = await bot.fetch_user(updated_user_id)
729-
await self._update_member_profile_data(
730-
self.logger, member, updated_user_id, index, total_number_of_updates_needed,
731-
updated_user_log_id=updated_user_log_id
760+
logger.info(
761+
f"[Leveling get_user()] unable to find guild member {user_id}\n{e}"
762+
)
763+
user = await bot.fetch_user(user_id)
764+
except DiscordException as e:
765+
logger.error(
766+
f"[Leveling get_user()] got the following error when fetching discord user "
767+
f"{user_id}\n{e}."
768+
)
769+
except DiscordException as e:
770+
logger.error(
771+
f"[Leveling get_user()] got the following error when fetching guild member "
772+
f"{user_id}\n{e}."
732773
)
774+
return user
733775

734776
@tasks.loop(seconds=5)
735777
async def process_outdated_profile_pics(self):
@@ -747,7 +789,7 @@ async def process_outdated_profile_pics(self):
747789
f"[Leveling process_outdated_profile_pics()] {number_of_users_to_update} users with outdated CDN links"
748790
f" to update"
749791
)
750-
await self._update_users(self.update_outdated_profile_pics_logger, user_ids_to_update)
792+
await self._update_users_with_given_ids(self.update_outdated_profile_pics_logger, user_ids_to_update)
751793
self.process_outdated_profile_pics_in_progress = False
752794

753795
async def _update_member_profile_data(self, logger, member, updated_user_id, index,
@@ -763,11 +805,10 @@ async def _update_member_profile_data(self, logger, member, updated_user_id, ind
763805
current loop
764806
:param updated_user_log_id: the ID of the UpdatedUser record to delete if this function was called as a
765807
result of member_update_listener's recording any detected changed in UpdatedUser
766-
:return:
808+
:return: True if member was successfully processed
767809
"""
810+
user_updated = False
768811
if member:
769-
if member.id in BUGGY_USER:
770-
return
771812
try:
772813
if self.user_points[member.id].leveling_update_attempt >= 5:
773814
log_level = logger.error if updated_user_log_id is None else logger.debug
@@ -812,13 +853,15 @@ async def _update_member_profile_data(self, logger, member, updated_user_id, ind
812853
f" data in the database for member {member} with id [{updated_user_id}]"
813854
f" {index + 1}/{total_number_of_updates_needed} due to error:\n{e}"
814855
)
856+
return user_updated
815857
else:
816858
logger.warn(
817859
f"[Leveling _update_member_profile_data()] attempt "
818860
f"{self.user_points[member.id].leveling_update_attempt}: unable to update the member profile data"
819861
f" in the database for member {updated_user_id} {index + 1}/{total_number_of_updates_needed}"
820862
)
821863
await self.user_points[member.id].async_save()
864+
return user_updated
822865

823866
@app_commands.command(name="reset_attempts")
824867
@app_commands.checks.has_any_role("Bot_manager")

0 commit comments

Comments
 (0)