1+ import asyncio
12import logging
23import nextcord
34from nextcord import Interaction , SlashOption
1213from config .messages import cached_messages , stored_messages
1314from core import log_manager
1415from core .api_connections_manager import start_all_api_connections
16+ from core .emoji_manager import cache_application_emojis
1517from core .log_manager import LogIfFailure
18+ from core .shard_manager import log_and_store_shard_distribution
1619from core .server_join_and_leave_manager import handle_server_join , handle_server_remove
1720from core .scheduling import start_scheduler , stop_scheduler
1821from core .shard_manager import calculate_shard_count
4447
4548from features .options_menu import entrypoint_ui
4649
50+ startup_time = None
51+
4752# INIT BOT ==============================================================================================================================================================
4853intents = nextcord .Intents .default ()
4954intents .message_content = True
6469
6570def get_bot () -> commands .AutoShardedBot : return bot
6671
72+ async def all_shards_loaded ():
73+ """
74+ Called once all shards are started (not necessarily ready with all info cached)
75+
76+ :return: None
77+ :rtype: None
78+ """
79+
80+ # Wait a second
81+ await asyncio .sleep (1 )
82+
83+ # Update bot ID
84+ global_settings .update_bot_id (bot )
85+
86+ # Initialize the bot's emoji cache
87+ await cache_application_emojis (bot )
88+
89+ # Initialize the bot's view cache
90+ init_views (bot )
91+
92+ # Start API connections
93+ start_all_api_connections ()
94+
95+ # Update shard distribution
96+ log_and_store_shard_distribution (bot )
97+
6798@bot .event
6899async def on_ready () -> None : # Bot load
69100 """
@@ -74,82 +105,18 @@ async def on_ready() -> None: # Bot load
74105 :return: None
75106 :rtype: None
76107 """
77- startup_start = time . time ()
108+ global startup_time
78109
79110 await bot .wait_until_ready ()
80111 logging .info (f"============================== Logged in as: { bot .user .name } with all shards ready. ==============================" )
81112 logging .info (f"Bot is running with { bot .shard_count } shards across { len (bot .guilds )} guilds." )
82113
83114 # Initialize core systems
84115 init_start = time .time ()
85- init_views (bot )
86116 global_settings .set_bot_load_status (True )
87- global_settings .update_bot_id (bot )
88117 start_scheduler ()
89- start_all_api_connections ()
90118 logging .info (f"Core systems initialized in { time .time () - init_start :.2f} s" )
91119
92- # Log shard distribution and save data for next startup (optimized)
93- shard_start = time .time ()
94- total_guilds = len (bot .guilds )
95- shard_guild_counts = {}
96-
97- # Single iteration through guilds to count by shard
98- for guild in bot .guilds :
99- shard_id = guild .shard_id
100- shard_guild_counts [shard_id ] = shard_guild_counts .get (shard_id , 0 ) + 1
101-
102- logging .info (f"Shard distribution calculated in { time .time () - shard_start :.2f} s" )
103-
104- # Save guild count data for next startup (async file operations)
105- try :
106- shard_config_path = os .path .join ("generated" , "configure" , "shard_config.json" )
107- os .makedirs (os .path .dirname (shard_config_path ), exist_ok = True )
108-
109- # Cache config value to avoid multiple calls
110- sharding_config = global_settings .get_configs ()["sharding" ]
111-
112- shard_data = {
113- "last_guild_count" : total_guilds ,
114- "last_shard_count" : bot .shard_count ,
115- "last_updated" : "2025-06-24" ,
116- "guilds_per_shard_config" : sharding_config ["guilds-per-shard" ]
117- }
118-
119- with open (shard_config_path , 'w' ) as f :
120- json .dump (shard_data , f , indent = 2 )
121-
122- logging .info (f"Saved guild count data: { total_guilds } guilds across { bot .shard_count } shards" )
123-
124- except Exception as e :
125- logging .warning (f"Could not save shard data: { e } " )
126-
127- # Display shard distribution (optimized)
128- if shard_guild_counts :
129- logging .info ("Shard distribution:" )
130- max_guilds_per_shard = max (shard_guild_counts .values ())
131- for shard_id in sorted (shard_guild_counts .keys ()):
132- guild_count = shard_guild_counts [shard_id ]
133- logging .info (f" Shard { shard_id } : { guild_count } guilds" )
134-
135- # Intelligent recommendations (cached config)
136- if sharding_config ["enabled" ]:
137- guilds_per_shard = sharding_config ["guilds-per-shard" ]
138- optimal_shards = max (1 , (total_guilds // guilds_per_shard ) + 1 )
139-
140- if max_guilds_per_shard > guilds_per_shard * 1.5 : # 50% over target
141- logging .warning (f"⚠️ HIGH SHARD LOAD: Some shards have { max_guilds_per_shard } guilds (target: { guilds_per_shard } ). Consider restarting - next startup will use { optimal_shards } shards." )
142- elif bot .shard_count < optimal_shards :
143- logging .info (f"💡 SCALING SUGGESTION: Current: { bot .shard_count } shards, Optimal: { optimal_shards } shards. Restart to apply." )
144- elif bot .shard_count > optimal_shards * 1.5 : # Over-sharded
145- logging .info (f"💡 OPTIMIZATION: You might be over-sharded. Current: { bot .shard_count } , Optimal: { optimal_shards } . Restart to optimize." )
146- else :
147- logging .info (f"✅ SHARD COUNT: Optimal ({ bot .shard_count } shards for { total_guilds } guilds)" )
148- else :
149- logging .info (f"ℹ️ AUTO-SHARDING: Disabled in config. Using Discord's recommendation ({ bot .shard_count } shards)" )
150- else :
151- logging .info ("No guilds found on any shards." )
152-
153120 # Print detailed guild info only in debug mode
154121 if logging .getLevelName (logging .getLogger ().getEffectiveLevel ()) == "DEBUG" :
155122 for guild in bot .guilds :
@@ -186,8 +153,8 @@ async def on_ready() -> None: # Bot load
186153 logging .info ("Bot startup notification is disabled. Skipping notification." )
187154
188155 # Log total startup time
189- total_startup_time = time .time () - startup_start
190- logging .info (f"🚀 STARTUP COMPLETE: Total time { total_startup_time :.2f} s for { total_guilds } guilds ({ total_guilds / total_startup_time :.1f} guilds/sec)" )
156+ total_startup_time = time .time () - startup_time
157+ logging .info (f"🚀 STARTUP COMPLETE: Total time { total_startup_time :.2f} s for { len ( bot . guilds ) } guilds ({ len ( bot . guilds ) / total_startup_time :.1f} guilds/sec)" )
191158
192159
193160@bot .event
@@ -206,6 +173,11 @@ async def on_shard_ready(shard_id: int) -> None:
206173 with global_settings .ShardLoadedStatus () as shards_loaded :
207174 shards_loaded .append (shard_id )
208175
176+ # Check if all shards are loaded
177+ if len (shards_loaded ) == bot .shard_count :
178+ logging .info (f"All { bot .shard_count } shards are loaded. Running post-shard initialization code..." )
179+ await all_shards_loaded ()
180+
209181@bot .event
210182async def on_close () -> None :
211183 """
@@ -792,12 +764,14 @@ def run() -> None:
792764 :return: None
793765 :rtype: None
794766 """
767+ global startup_time
795768
796769 # Get token
797770 token = os .environ ['DISCORD_AUTH_TOKEN' ]
798771 logging .info (f"Running bot with token: { token [:5 ]} *******..." )
799772
800773 logging .info (f"Running in { global_settings .get_environment_type ()} mode." )
774+ startup_time = time .time ()
801775
802776 try :
803777 bot .run (token )
0 commit comments