diff --git a/services/custom_commands_service.py b/services/custom_commands_service.py index 03445bc..ad2635b 100644 --- a/services/custom_commands_service.py +++ b/services/custom_commands_service.py @@ -4,6 +4,7 @@ Custom Commands Service for Discord Bot v2.0 Modern async service layer for managing custom commands with full type safety. """ +import asyncio import math from datetime import UTC, datetime, timedelta from typing import Optional, List, Any, Tuple @@ -466,21 +467,28 @@ class CustomCommandsService(BaseService[CustomCommand]): commands_data = await self.get_items_with_params(params) + creators = await asyncio.gather( + *[ + self.get_creator_by_id(cmd_data.creator_id) + for cmd_data in commands_data + ], + return_exceptions=True, + ) + commands = [] - for cmd_data in commands_data: - try: - creator = await self.get_creator_by_id(cmd_data.creator_id) - commands.append(CustomCommand(**cmd_data.model_dump(), creator=creator)) - except BotException as e: - # Handle missing creator gracefully + for cmd_data, creator in zip(commands_data, creators): + if isinstance(creator, BotException): self.logger.warning( "Skipping popular command with missing creator", command_id=cmd_data.id, command_name=cmd_data.name, creator_id=cmd_data.creator_id, - error=str(e), + error=str(creator), ) continue + if isinstance(creator, BaseException): + raise creator + commands.append(CustomCommand(**cmd_data.model_dump(), creator=creator)) return commands @@ -662,21 +670,28 @@ class CustomCommandsService(BaseService[CustomCommand]): commands_data = await self.get_items_with_params(params) + creators = await asyncio.gather( + *[ + self.get_creator_by_id(cmd_data.creator_id) + for cmd_data in commands_data + ], + return_exceptions=True, + ) + commands = [] - for cmd_data in commands_data: - try: - creator = await self.get_creator_by_id(cmd_data.creator_id) - commands.append(CustomCommand(**cmd_data.model_dump(), creator=creator)) - except BotException as e: - # Handle missing creator gracefully + for cmd_data, creator in zip(commands_data, creators): + if isinstance(creator, BotException): self.logger.warning( "Skipping command with missing creator", command_id=cmd_data.id, command_name=cmd_data.name, creator_id=cmd_data.creator_id, - error=str(e), + error=str(creator), ) continue + if isinstance(creator, BaseException): + raise creator + commands.append(CustomCommand(**cmd_data.model_dump(), creator=creator)) return commands @@ -688,21 +703,28 @@ class CustomCommandsService(BaseService[CustomCommand]): commands_data = await self.get_items_with_params(params) + creators = await asyncio.gather( + *[ + self.get_creator_by_id(cmd_data.creator_id) + for cmd_data in commands_data + ], + return_exceptions=True, + ) + commands = [] - for cmd_data in commands_data: - try: - creator = await self.get_creator_by_id(cmd_data.creator_id) - commands.append(CustomCommand(**cmd_data.model_dump(), creator=creator)) - except BotException as e: - # Handle missing creator gracefully + for cmd_data, creator in zip(commands_data, creators): + if isinstance(creator, BotException): self.logger.warning( "Skipping command with missing creator", command_id=cmd_data.id, command_name=cmd_data.name, creator_id=cmd_data.creator_id, - error=str(e), + error=str(creator), ) continue + if isinstance(creator, BaseException): + raise creator + commands.append(CustomCommand(**cmd_data.model_dump(), creator=creator)) return commands diff --git a/services/decision_service.py b/services/decision_service.py index 11a36b5..a688b9e 100644 --- a/services/decision_service.py +++ b/services/decision_service.py @@ -4,6 +4,7 @@ Decision Service Manages pitching decision operations for game submission. """ +import asyncio from typing import List, Dict, Any, Optional, Tuple from utils.logging import get_contextual_logger @@ -124,22 +125,19 @@ class DecisionService: if int(decision.get("b_save", 0)) == 1: bsv_ids.append(pitcher_id) - # Second pass: Fetch Player objects - wp = await player_service.get_player(wp_id) if wp_id else None - lp = await player_service.get_player(lp_id) if lp_id else None - sv = await player_service.get_player(sv_id) if sv_id else None + # Second pass: Fetch all Player objects in parallel + # Order: [wp_id, lp_id, sv_id, *hold_ids, *bsv_ids]; None IDs resolve immediately + ordered_ids = [wp_id, lp_id, sv_id] + hold_ids + bsv_ids + results = await asyncio.gather( + *[ + player_service.get_player(pid) if pid else asyncio.sleep(0, result=None) + for pid in ordered_ids + ] + ) - holders = [] - for hold_id in hold_ids: - holder = await player_service.get_player(hold_id) - if holder: - holders.append(holder) - - blown_saves = [] - for bsv_id in bsv_ids: - bsv = await player_service.get_player(bsv_id) - if bsv: - blown_saves.append(bsv) + wp, lp, sv = results[0], results[1], results[2] + holders = [p for p in results[3 : 3 + len(hold_ids)] if p] + blown_saves = [p for p in results[3 + len(hold_ids) :] if p] return wp, lp, sv, holders, blown_saves