resolve roles with at most one fetch_roles call per update

Previously every role missing from the cache triggered its own fetch_roles
call, for every user in the membership check.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
leanderandClaude Opus 5.5 committed 2026-10-23 02:44:44 +02:00
1 parent 3e4561367c
commit aef7753751
2 files changed
+18 -22

No files matched your search

+5 -10
View File
@@ -465,16 +465,11 @@ class Galtinn(commands.Cog):
requested_roles_to_add = roles_to_add requested_roles_to_add = roles_to_add
requested_roles_to_remove = roles_to_remove requested_roles_to_remove = roles_to_remove
roles_to_add = { guild_roles = await discord_utils.get_guild_roles(
role self.bot, guild, requested_roles_to_add | requested_roles_to_remove
for role_id in requested_roles_to_add )
if (role := await discord_utils.get_guild_role(self.bot, guild, role_id)) roles_to_add = {guild_roles[role_id] for role_id in requested_roles_to_add if role_id in guild_roles}
} roles_to_remove = {guild_roles[role_id] for role_id in requested_roles_to_remove if role_id in guild_roles}
roles_to_remove = {
role
for role_id in requested_roles_to_remove
if (role := await discord_utils.get_guild_role(self.bot, guild, role_id))
}
# Problematic roles are skipped rather than aborting, so that one misconfigured role # Problematic roles are skipped rather than aborting, so that one misconfigured role
# doesn't stop every other role from being updated # doesn't stop every other role from being updated
+13 -12
View File
@@ -93,32 +93,33 @@ async def get_guild_member(bot: commands.Bot, guild: discord.Guild, user_id: int
return user return user
async def get_guild_role(bot: commands.Bot, guild: discord.Guild, role_id: int) -> discord.Role | None: async def get_guild_roles(bot: commands.Bot, guild: discord.Guild, role_ids: set[int]) -> dict[int, discord.Role]:
""" """
Helper function that tries fetching a discord object from the cache. If not found, fetches from the API Helper function that tries fetching discord roles from the cache.
If any are not found, all roles are fetched from the API in a single call
Parameters Parameters
---------- ----------
bot (commands.Bot): Bot instance bot (commands.Bot): Bot instance
guild (discord.Guild): The discord guild to fetch the role from guild (discord.Guild): The discord guild to fetch the roles from
role_id (int): ID of the role role_ids (set[int]): IDs of the roles
Returns Returns
---------- ----------
(discord.Role | None): Discord object. None if not found or failed to fetch from API (dict[int, discord.Role]): Discord objects by ID. Roles that were not found or failed to fetch are left out
""" """
role = guild.get_role(role_id) roles = {role_id: role for role_id in role_ids if (role := guild.get_role(role_id))}
if not role: if missing_role_ids := role_ids - roles.keys():
bot.logger.info(f"failed to fetch role {role_id} from cache. Making API call...") bot.logger.info(f"failed to fetch roles {missing_role_ids} from cache. Making API call...")
try: try:
roles = await guild.fetch_roles() fetched_roles = await guild.fetch_roles()
except discord.errors.HTTPException: except discord.errors.HTTPException:
bot.logger.warning(f"Failed to fetch role with ID {role_id}. HTTPException") bot.logger.warning(f"Failed to fetch roles with IDs {missing_role_ids}. HTTPException")
else: else:
role = discord.utils.get(roles, id=role_id) roles.update({role.id: role for role in fetched_roles if role.id in missing_role_ids})
return role return roles
class ScrollerButton(discord.ui.Button): class ScrollerButton(discord.ui.Button):