77import discord
88import pytz
99from discord import NotFound , app_commands , Guild
10- from discord .errors import DiscordServerError , HTTPException
10+ from discord .errors import DiscordException
1111from 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-
1713from utilities .embed import embed , COLOUR_MAPPING , WallEColour
1814from utilities .file_uploading import start_file_uploading
15+ from utilities .global_vars import bot , wall_e_config
1916from utilities .paginate import paginate_embed
2017from utilities .setup_logger import Loggers
21-
22- BUGGY_USER = [234501345749630976 ]
18+ from wall_e_models .models import Level , UserPoint , UpdatedUser , ProfileBucketInProgress
2319
2420
2521class 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