parent
48638e76f8
commit
dc5a033e63
@ -0,0 +1,10 @@ |
||||
from django.core.management.base import BaseCommand |
||||
from tournaments.tasks import check_confirmation_deadlines |
||||
|
||||
class Command(BaseCommand): |
||||
help = 'Run confirmation deadline check immediately' |
||||
|
||||
def handle(self, *args, **options): |
||||
# Run the function directly (not through the task queue) |
||||
check_confirmation_deadlines(schedule=0) |
||||
self.stdout.write(self.style.SUCCESS('Successfully checked confirmation deadlines')) |
||||
@ -0,0 +1,63 @@ |
||||
from django.core.management.base import BaseCommand |
||||
from tournaments.tasks import check_confirmation_deadlines |
||||
from django.utils import timezone |
||||
import datetime |
||||
import pytz |
||||
|
||||
class Command(BaseCommand): |
||||
help = 'Schedule background tasks to run at :00 and :30 of every hour' |
||||
|
||||
def handle(self, *args, **options): |
||||
# Clear existing tasks first to avoid duplicates |
||||
from background_task.models import Task |
||||
Task.objects.filter(task_name='tournaments.tasks.check_confirmation_deadlines').delete() |
||||
|
||||
# Get the current timezone-aware time |
||||
now = timezone.now() |
||||
|
||||
# Get local timezone for display purposes |
||||
local_timezone = timezone.get_current_timezone() |
||||
local_now = now.astimezone(local_timezone) |
||||
|
||||
# Calculate time until next half-hour mark (either :00 or :30) |
||||
current_minute = local_now.minute |
||||
|
||||
if current_minute < 30: |
||||
# Next run at XX:30:00 |
||||
next_minute = 30 |
||||
next_hour = local_now.hour |
||||
else: |
||||
# Next run at (XX+1):00:00 |
||||
next_minute = 0 |
||||
next_hour = local_now.hour + 1 |
||||
|
||||
# Create a datetime with exactly XX:30:00 or XX:00:00 in local time |
||||
first_run_local = local_now.replace( |
||||
hour=next_hour, |
||||
minute=next_minute + 1, #let the expiration time be off first |
||||
second=0, |
||||
microsecond=0 |
||||
) |
||||
|
||||
# Handle day rollover if needed |
||||
if first_run_local < local_now: # This would happen if we crossed midnight |
||||
first_run_local += datetime.timedelta(days=1) |
||||
|
||||
# Calculate seconds from now until the first run |
||||
seconds_until_first_run = (first_run_local - local_now).total_seconds() |
||||
if seconds_until_first_run < 0: |
||||
seconds_until_first_run = 0 # If somehow negative, run immediately |
||||
|
||||
# Schedule with seconds delay instead of a specific datetime |
||||
check_confirmation_deadlines( |
||||
schedule=int(seconds_until_first_run), # Delay in seconds before first run |
||||
repeat=1800 # 30 minutes in seconds |
||||
) |
||||
|
||||
# Show the message with proper timezone info |
||||
local_timezone_name = local_timezone.tzname(local_now) |
||||
self.stdout.write(self.style.SUCCESS( |
||||
f'Task scheduled to first run at {first_run_local.strftime("%H:%M:%S")} {local_timezone_name} ' |
||||
f'(in {int(seconds_until_first_run)} seconds) ' |
||||
f'and then every 30 minutes' |
||||
)) |
||||
@ -0,0 +1,89 @@ |
||||
from background_task import background |
||||
from django.utils import timezone |
||||
from django.db import transaction |
||||
|
||||
from .models import PlayerRegistration |
||||
from .models.player_registration import RegistrationStatus |
||||
from .services.email_service import TournamentEmailService, TeamEmailType |
||||
|
||||
@background(schedule=1) # Run every 30 minutes (30*60 seconds) |
||||
def check_confirmation_deadlines(): |
||||
""" |
||||
Periodic task to check for expired confirmation deadlines |
||||
and notify the next team in the waiting list. |
||||
""" |
||||
now = timezone.now() |
||||
print(f"[{now}] Running confirmation deadline check...") |
||||
|
||||
# Find players with expired confirmation deadlines |
||||
expired_confirmations = PlayerRegistration.objects.filter( |
||||
registration_status=RegistrationStatus.PENDING, |
||||
registered_online=True, |
||||
team_registration__isnull=False |
||||
).select_related('team_registration', 'team_registration__tournament') |
||||
|
||||
print(f"Found {expired_confirmations.count()} expired confirmations") |
||||
|
||||
# Process each expired confirmation |
||||
processed_teams = set() # To avoid processing the same team multiple times |
||||
|
||||
for player in expired_confirmations: |
||||
team_registration = player.team_registration |
||||
|
||||
# Skip if we've already processed this team |
||||
if team_registration.id in processed_teams: |
||||
continue |
||||
|
||||
processed_teams.add(team_registration.id) |
||||
tournament = team_registration.tournament |
||||
|
||||
if not tournament or not tournament.enable_online_registration: |
||||
continue |
||||
|
||||
teams = tournament.teams(True) |
||||
waiting_list_teams = tournament.waiting_list_teams(teams) |
||||
if waiting_list_teams is not None: |
||||
ttc = tournament.calculate_time_to_confirm(len(waiting_list_teams)) |
||||
else: |
||||
ttc = None |
||||
first_waiting_list_team = tournament.first_waiting_list_team(teams) |
||||
|
||||
# Process in a transaction to ensure atomic operations |
||||
with transaction.atomic(): |
||||
# Get all players in this team and mark them as expired |
||||
team_players = PlayerRegistration.objects.filter( |
||||
team_registration=team_registration, |
||||
registered_online=True |
||||
) |
||||
|
||||
should_update_team = False |
||||
should_send_mail = False |
||||
for team_player in team_players: |
||||
if team_player.time_to_confirm is None and first_waiting_list_team is not None: |
||||
team_registration.set_time_to_confirm(ttc) |
||||
team_player.save() |
||||
should_send_mail = True |
||||
print(team_player, "team_player.time_to_confirm is None and", ttc) |
||||
elif team_player.time_to_confirm is not None and now > team_player.time_to_confirm: |
||||
team_player.registration_status = RegistrationStatus.CANCELED |
||||
team_player.time_to_confirm = None |
||||
team_player.save() |
||||
team_registration.registration_date = now |
||||
print(team_player, "time_to_confirm = ", team_player.time_to_confirm) |
||||
should_update_team = True |
||||
# elif team_player.time_to_confirm is not None and team_player.time_to_confirm > ttc: |
||||
# team_player.registration_status = RegistrationStatus.PENDING |
||||
# team_player.time_to_confirm = ttc |
||||
# team_player.save() |
||||
# should_update_team = True |
||||
|
||||
if should_send_mail: |
||||
TournamentEmailService.notify_team( |
||||
team_registration, |
||||
tournament, |
||||
TeamEmailType.OUT_OF_WAITING_LIST |
||||
) |
||||
|
||||
if should_update_team: |
||||
team_registration.save() |
||||
print(f"Team {team_registration} confirmation expired in tournament {tournament.id}") |
||||
Loading…
Reference in new issue