diff --git a/src/core/management/commands/housekeeping.py b/src/core/management/commands/housekeeping.py index 93f96244985b2f829ba2ab7be6b457d1b22ba425..fddcc4e42b9e5473806335c82e3dd0c78fca25a6 100644 --- a/src/core/management/commands/housekeeping.py +++ b/src/core/management/commands/housekeeping.py @@ -1,16 +1,80 @@ +import time + from django.core.management.base import BaseCommand from django.utils import timezone from ...models.messages import DirectMessage +from ...models.schedules import ScheduleSource, ScheduleSourceImport from ...models.voucher import Voucher class Command(BaseCommand): - def handle(self, *args, **options): + def add_arguments(self, parser): + parser.add_argument('--forever', action='store_true', help='repeat the housekeeping forever (until Ctrl+C is pressed)') + parser.add_argument('--forever-delay', type=int, default=300, help='seconds to wait between housekeeping runs') + + def _do_housekeeping(self): # clear all direct messages which are after their expiry date + print('Deleting messages ... ', end='', flush=True) deleted_msgs_count, _ = DirectMessage.objects.filter(autodelete_after__isnull=False, autodelete_after__lte=timezone.now()).delete() - print(f'Deleted {deleted_msgs_count} messages.') + print(deleted_msgs_count) # do auto-assignments + print('Auto-assigning vouchers ... ', end='', flush=True) vouchers_assigned = Voucher.do_auto_assignments() - print(f'Auto-assigned {vouchers_assigned} vouchers.') + print(vouchers_assigned) + + # schedules + print('Schedule imports ... ', end='', flush=True) + schedule_results = {} + schedule_failure, schedule_success, schedule_skipped = 0, 0, 0 + for schedule in ScheduleSource.objects.all(): + # skip schedules which aren't due yet + if not schedule.is_due: + continue + + # skip schedules where an import is already running + if schedule.has_running_import: + schedule_results[str(schedule)] = None + schedule_skipped += 1 + continue + + # create import job + job = ScheduleSourceImport(schedule_source=schedule, state=ScheduleSourceImport.State.PREPARED) + job.save() + + # execute job + try: + result = job.do_import() + schedule_results[str(schedule)] = job.summary + if result: + schedule_success += 1 + else: + schedule_failure += 1 + except Exception as err: + schedule_results[str(schedule)] = 'EXCEPTION: ' + str(err) + schedule_failure += 1 + + # print schedule import results + print(schedule_success, '/', len(schedule_results), ' (', schedule_skipped, ' skipped)', sep='') + for k, v in schedule_results.items(): + print(' ', k, ' => ', v, sep='') + + def handle(self, *args, **options): + # call _do_housekeeping repeatedly (unless --forever is not set) + forever = options.get('forever') + while True: + if forever: + print(timezone.now().isoformat()) + + self._do_housekeeping() + + if forever: + print() # empty line + try: + time.sleep(options.get('forever_delay')) + except KeyboardInterrupt: + print('Aborted.') + break + else: + break