Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,4 @@ GW2_WVW_COOLDOWN=20
GW2_API_RETRY_MAX_ATTEMPTS=5
GW2_API_RETRY_DELAY=3.0
GW2_API_SESSION_RETRY_BG_DELAY=30.0
GW2_API_SESSION_END_DELAY=120
12 changes: 11 additions & 1 deletion src/gw2/cogs/sessions.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,18 @@ async def session(ctx):
live_stats["date"] = bot_utils.convert_datetime_to_str_short(bot_utils.get_current_date_time())
rs_end = live_stats
is_live_snapshot = True
elif gw2_utils.is_session_ending(user_id):
# Background end_session is still waiting for the API cache to refresh
remaining = gw2_utils.get_session_end_remaining_seconds(user_id)
msg = gw2_messages.SESSION_END_PROCESSING
if remaining is not None and remaining > 0:
m = remaining // 60
s = remaining % 60
time_str = f"{m}m {s}s" if m > 0 else f"{s}s"
msg += f"\n{gw2_messages.WAITING_TIME}: `{time_str}`"
return await bot_utils.send_warning_msg(ctx, msg)
else:
# End data missing and user stopped playing - finalize the session now
# End data missing, user stopped playing, no background task - finalize now
progress_msg = await gw2_utils.send_progress_embed(ctx)
await gw2_utils.end_session(ctx.bot, ctx.message.author, api_key, skip_delay=True)
rs_session = await gw2_session_dal.get_user_last_session(user_id)
Expand Down
5 changes: 5 additions & 0 deletions src/gw2/constants/gw2_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ def session_not_active(prefix: str) -> str:
"Please add another API key with permissions that are MISSING if you want to use this command."
)
SESSION_BOT_STILL_UPDATING = "Bot still updating your stats!"
SESSION_END_PROCESSING = (
"Your session is still being processed.\n"
"The bot waits a few minutes after you stop playing to ensure accurate data from the GW2 API.\n"
"Please try again shortly."
)
SESSION_USER_STILL_PLAYING = "You are playing Guild Wars 2 at the moment.\nYour stats may NOT be accurate."
WAITING_TIME = "Waiting time"
ACCOUNT_NAME = "Account Name"
Expand Down
2 changes: 1 addition & 1 deletion src/gw2/constants/gw2_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class Gw2Settings(BaseSettings):
api_retry_max_attempts: int | None = Field(default=5)
api_retry_delay: float | None = Field(default=3.0)
api_session_retry_bg_delay: float | None = Field(default=30.0)
api_session_end_delay: float | None = Field(default=300.0)
api_session_end_delay: float | None = Field(default=120.0)


@lru_cache(maxsize=1)
Expand Down
24 changes: 24 additions & 0 deletions src/gw2/tools/gw2_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,28 @@ def _is_gw2_activity_detected(before_activity, after_activity) -> bool:
)


def is_session_ending(user_id: int) -> bool:
"""Check if a session end is currently being processed for this user."""
if user_id not in _processing_sessions:
return False
state = _processing_sessions[user_id]
return state["current"] == "end" or state.get("pending") == "end"


def get_session_end_remaining_seconds(user_id: int) -> int | None:
"""Get remaining seconds until end session delay completes, or None if not waiting."""
if user_id not in _processing_sessions:
return None
state = _processing_sessions[user_id]
started_at = state.get("delay_started_at")
if started_at is None or state["current"] != "end":
return None
end_delay = _gw2_settings.api_session_end_delay or 0
elapsed = (datetime.now() - started_at).total_seconds()
remaining = max(0, int(end_delay - elapsed))
return remaining


async def _handle_gw2_activity_change(
bot: Bot,
member: discord.Member,
Expand Down Expand Up @@ -452,6 +474,8 @@ async def end_session(bot: Bot, member: discord.Member, api_key: str, *, skip_de
end_delay = _gw2_settings.api_session_end_delay
if not skip_delay and end_delay and end_delay > 0:
bot.log.debug(f"Waiting {end_delay}s for GW2 API cache to refresh before ending session for user {member.id}")
if member.id in _processing_sessions:
_processing_sessions[member.id]["delay_started_at"] = datetime.now()
await asyncio.sleep(end_delay)

session = await get_user_stats(bot, api_key)
Expand Down