perf: parallelize independent API calls (#90) #106
@ -4,6 +4,7 @@ Scorebug Commands
|
||||
Implements commands for publishing and displaying live game scorebugs from Google Sheets scorecards.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import discord
|
||||
from discord.ext import commands
|
||||
from discord import app_commands
|
||||
@ -73,12 +74,18 @@ class ScorebugCommands(commands.Cog):
|
||||
return
|
||||
|
||||
# Get team data for display
|
||||
away_team = None
|
||||
home_team = None
|
||||
if scorebug_data.away_team_id:
|
||||
away_team = await team_service.get_team(scorebug_data.away_team_id)
|
||||
if scorebug_data.home_team_id:
|
||||
home_team = await team_service.get_team(scorebug_data.home_team_id)
|
||||
away_team, home_team = await asyncio.gather(
|
||||
(
|
||||
team_service.get_team(scorebug_data.away_team_id)
|
||||
if scorebug_data.away_team_id
|
||||
else asyncio.sleep(0)
|
||||
),
|
||||
(
|
||||
team_service.get_team(scorebug_data.home_team_id)
|
||||
if scorebug_data.home_team_id
|
||||
else asyncio.sleep(0)
|
||||
),
|
||||
)
|
||||
|
||||
# Format scorecard link
|
||||
away_abbrev = away_team.abbrev if away_team else "AWAY"
|
||||
@ -86,7 +93,7 @@ class ScorebugCommands(commands.Cog):
|
||||
scorecard_link = f"[{away_abbrev} @ {home_abbrev}]({url})"
|
||||
|
||||
# Store the scorecard in the tracker
|
||||
self.scorecard_tracker.publish_scorecard(
|
||||
await self.scorecard_tracker.publish_scorecard(
|
||||
text_channel_id=interaction.channel_id, # type: ignore
|
||||
sheet_url=url,
|
||||
publisher_id=interaction.user.id,
|
||||
@ -157,7 +164,7 @@ class ScorebugCommands(commands.Cog):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
|
||||
# Check if a scorecard is published in this channel
|
||||
sheet_url = self.scorecard_tracker.get_scorecard(interaction.channel_id) # type: ignore
|
||||
sheet_url = await self.scorecard_tracker.get_scorecard(interaction.channel_id) # type: ignore
|
||||
|
||||
if not sheet_url:
|
||||
embed = EmbedTemplate.error(
|
||||
@ -179,12 +186,18 @@ class ScorebugCommands(commands.Cog):
|
||||
)
|
||||
|
||||
# Get team data
|
||||
away_team = None
|
||||
home_team = None
|
||||
if scorebug_data.away_team_id:
|
||||
away_team = await team_service.get_team(scorebug_data.away_team_id)
|
||||
if scorebug_data.home_team_id:
|
||||
home_team = await team_service.get_team(scorebug_data.home_team_id)
|
||||
away_team, home_team = await asyncio.gather(
|
||||
(
|
||||
team_service.get_team(scorebug_data.away_team_id)
|
||||
if scorebug_data.away_team_id
|
||||
else asyncio.sleep(0)
|
||||
),
|
||||
(
|
||||
team_service.get_team(scorebug_data.home_team_id)
|
||||
if scorebug_data.home_team_id
|
||||
else asyncio.sleep(0)
|
||||
),
|
||||
)
|
||||
|
||||
# Create scorebug embed using shared utility
|
||||
embed = create_scorebug_embed(
|
||||
@ -194,7 +207,7 @@ class ScorebugCommands(commands.Cog):
|
||||
await interaction.edit_original_response(content=None, embed=embed)
|
||||
|
||||
# Update timestamp in tracker
|
||||
self.scorecard_tracker.update_timestamp(interaction.channel_id) # type: ignore
|
||||
await self.scorecard_tracker.update_timestamp(interaction.channel_id) # type: ignore
|
||||
|
||||
except SheetsException as e:
|
||||
embed = EmbedTemplate.error(
|
||||
|
||||
@ -11,6 +11,7 @@ The injury rating format (#p##) encodes both games played and rating:
|
||||
- Remaining: Injury rating (p70, p65, p60, p50, p40, p30, p20)
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import math
|
||||
import random
|
||||
import discord
|
||||
@ -114,16 +115,14 @@ class InjuryGroup(app_commands.Group):
|
||||
"""Roll for injury using 3d6 dice and injury tables."""
|
||||
await interaction.response.defer()
|
||||
|
||||
# Get current season
|
||||
current = await league_service.get_current_state()
|
||||
# Get current season and search for player in parallel
|
||||
current, players = await asyncio.gather(
|
||||
league_service.get_current_state(),
|
||||
player_service.search_players(player_name, limit=10),
|
||||
)
|
||||
if not current:
|
||||
raise BotException("Failed to get current season information")
|
||||
|
||||
# Search for player using the search endpoint (more reliable than name param)
|
||||
players = await player_service.search_players(
|
||||
player_name, limit=10, season=current.season
|
||||
)
|
||||
|
||||
if not players:
|
||||
embed = EmbedTemplate.error(
|
||||
title="Player Not Found",
|
||||
@ -530,16 +529,14 @@ class InjuryGroup(app_commands.Group):
|
||||
await interaction.followup.send(embed=embed, ephemeral=True)
|
||||
return
|
||||
|
||||
# Get current season
|
||||
current = await league_service.get_current_state()
|
||||
# Get current season and search for player in parallel
|
||||
current, players = await asyncio.gather(
|
||||
league_service.get_current_state(),
|
||||
player_service.search_players(player_name, limit=10),
|
||||
)
|
||||
if not current:
|
||||
raise BotException("Failed to get current season information")
|
||||
|
||||
# Search for player using the search endpoint (more reliable than name param)
|
||||
players = await player_service.search_players(
|
||||
player_name, limit=10, season=current.season
|
||||
)
|
||||
|
||||
if not players:
|
||||
embed = EmbedTemplate.error(
|
||||
title="Player Not Found",
|
||||
@ -717,16 +714,14 @@ class InjuryGroup(app_commands.Group):
|
||||
|
||||
await interaction.response.defer()
|
||||
|
||||
# Get current season
|
||||
current = await league_service.get_current_state()
|
||||
# Get current season and search for player in parallel
|
||||
current, players = await asyncio.gather(
|
||||
league_service.get_current_state(),
|
||||
player_service.search_players(player_name, limit=10),
|
||||
)
|
||||
if not current:
|
||||
raise BotException("Failed to get current season information")
|
||||
|
||||
# Search for player using the search endpoint (more reliable than name param)
|
||||
players = await player_service.search_players(
|
||||
player_name, limit=10, season=current.season
|
||||
)
|
||||
|
||||
if not players:
|
||||
embed = EmbedTemplate.error(
|
||||
title="Player Not Found",
|
||||
|
||||
@ -5,6 +5,7 @@ Implements the /submit-scorecard command for submitting Google Sheets
|
||||
scorecards with play-by-play data, pitching decisions, and game results.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from typing import Optional, List
|
||||
|
||||
import discord
|
||||
@ -107,11 +108,13 @@ class SubmitScorecardCommands(commands.Cog):
|
||||
content="🔍 Looking up teams and managers..."
|
||||
)
|
||||
|
||||
away_team = await team_service.get_team_by_abbrev(
|
||||
setup_data["away_team_abbrev"], current.season
|
||||
)
|
||||
home_team = await team_service.get_team_by_abbrev(
|
||||
setup_data["home_team_abbrev"], current.season
|
||||
away_team, home_team = await asyncio.gather(
|
||||
team_service.get_team_by_abbrev(
|
||||
setup_data["away_team_abbrev"], current.season
|
||||
),
|
||||
team_service.get_team_by_abbrev(
|
||||
setup_data["home_team_abbrev"], current.season
|
||||
),
|
||||
)
|
||||
|
||||
if not away_team or not home_team:
|
||||
@ -235,9 +238,13 @@ class SubmitScorecardCommands(commands.Cog):
|
||||
decision["game_num"] = setup_data["game_num"]
|
||||
|
||||
# Validate WP and LP exist and fetch Player objects
|
||||
wp, lp, sv, holders, _blown_saves = (
|
||||
await decision_service.find_winning_losing_pitchers(decisions_data)
|
||||
)
|
||||
(
|
||||
wp,
|
||||
lp,
|
||||
sv,
|
||||
holders,
|
||||
_blown_saves,
|
||||
) = await decision_service.find_winning_losing_pitchers(decisions_data)
|
||||
|
||||
if wp is None or lp is None:
|
||||
await interaction.edit_original_response(
|
||||
|
||||
@ -4,6 +4,7 @@ Trade Builder Service
|
||||
Extends the TransactionBuilder to support multi-team trades and player exchanges.
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import Dict, List, Optional, Set
|
||||
from datetime import datetime, timezone
|
||||
@ -524,14 +525,22 @@ class TradeBuilder:
|
||||
|
||||
# Validate each team's roster after the trade
|
||||
for participant in self.trade.participants:
|
||||
team_id = participant.team.id
|
||||
result.team_abbrevs[team_id] = participant.team.abbrev
|
||||
if team_id in self._team_builders:
|
||||
builder = self._team_builders[team_id]
|
||||
roster_validation = await builder.validate_transaction(next_week)
|
||||
result.team_abbrevs[participant.team.id] = participant.team.abbrev
|
||||
|
||||
team_ids_to_validate = [
|
||||
participant.team.id
|
||||
for participant in self.trade.participants
|
||||
if participant.team.id in self._team_builders
|
||||
]
|
||||
if team_ids_to_validate:
|
||||
validations = await asyncio.gather(
|
||||
*[
|
||||
self._team_builders[tid].validate_transaction(next_week)
|
||||
for tid in team_ids_to_validate
|
||||
]
|
||||
)
|
||||
for team_id, roster_validation in zip(team_ids_to_validate, validations):
|
||||
result.participant_validations[team_id] = roster_validation
|
||||
|
||||
if not roster_validation.is_legal:
|
||||
result.is_legal = False
|
||||
|
||||
|
||||
@ -95,7 +95,7 @@ class LiveScorebugTracker:
|
||||
# Don't return - still update voice channels
|
||||
else:
|
||||
# Get all published scorecards
|
||||
all_scorecards = self.scorecard_tracker.get_all_scorecards()
|
||||
all_scorecards = await self.scorecard_tracker.get_all_scorecards()
|
||||
|
||||
if not all_scorecards:
|
||||
# No active scorebugs - clear the channel and hide it
|
||||
@ -119,11 +119,9 @@ class LiveScorebugTracker:
|
||||
# Only include active (non-final) games
|
||||
if scorebug_data.is_active:
|
||||
# Get team data
|
||||
away_team = await team_service.get_team(
|
||||
scorebug_data.away_team_id
|
||||
)
|
||||
home_team = await team_service.get_team(
|
||||
scorebug_data.home_team_id
|
||||
away_team, home_team = await asyncio.gather(
|
||||
team_service.get_team(scorebug_data.away_team_id),
|
||||
team_service.get_team(scorebug_data.home_team_id),
|
||||
)
|
||||
|
||||
if away_team is None or home_team is None:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user