diff --git a/api/custom_auth/apps.py b/api/custom_auth/apps.py new file mode 100644 index 000000000000..2328a449d114 --- /dev/null +++ b/api/custom_auth/apps.py @@ -0,0 +1,8 @@ +from django.apps import AppConfig + + +class CustomAuthAppConfig(AppConfig): + name = "custom_auth" + + def ready(self) -> None: + from custom_auth import tasks # noqa F401 diff --git a/api/custom_auth/tasks.py b/api/custom_auth/tasks.py new file mode 100644 index 000000000000..670d1bc6ae0a --- /dev/null +++ b/api/custom_auth/tasks.py @@ -0,0 +1,17 @@ +from datetime import timedelta + +from django.conf import settings +from django.utils import timezone + +from custom_auth.models import UserPasswordResetRequest +from task_processor.decorators import register_recurring_task + + +@register_recurring_task( + run_every=timedelta(seconds=settings.PASSWORD_RESET_EMAIL_COOLDOWN), +) +def clean_up_user_password_reset_request(): + UserPasswordResetRequest.objects.filter( + requested_at__lt=timezone.now() + - timedelta(seconds=settings.PASSWORD_RESET_EMAIL_COOLDOWN) + ).delete() diff --git a/api/scripts/run-docker.sh b/api/scripts/run-docker.sh index ef88776d47f5..b3779157cfd7 100755 --- a/api/scripts/run-docker.sh +++ b/api/scripts/run-docker.sh @@ -33,7 +33,7 @@ function run_task_processor() { if [[ -n "$ANALYTICS_DATABASE_URL" || -n "$DJANGO_DB_NAME_ANALYTICS" ]]; then python manage.py waitfordb --waitfor 30 --migrations --database analytics fi - python manage.py runprocessor --sleepintervalms 500 + RUN_BY_PROCESSOR=1 python manage.py runprocessor --sleepintervalms 500 } function migrate_identities(){ python manage.py migrate_to_edge "$1" diff --git a/api/task_processor/management/commands/runprocessor.py b/api/task_processor/management/commands/runprocessor.py index f8e1a579f9aa..9b55abc5c273 100644 --- a/api/task_processor/management/commands/runprocessor.py +++ b/api/task_processor/management/commands/runprocessor.py @@ -1,17 +1,13 @@ import logging -import os import signal import time import typing from argparse import ArgumentParser from datetime import timedelta -from importlib import reload from django.core.management import BaseCommand from django.utils import timezone -from sse import tasks as sse_tasks -from task_processor import tasks as processor_tasks from task_processor.task_registry import registered_tasks from task_processor.thread_monitoring import ( clear_unhealthy_threads, @@ -21,30 +17,11 @@ logger = logging.getLogger(__name__) -TASKS_MODULES_TO_RELOAD = [processor_tasks, sse_tasks] - class Command(BaseCommand): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - # The `register_recurring_task` decorator is executed in the global scope, - # meaning it will run whenever the code is executed, including when running - # `manage.py` commands such as `migrate` or `showmigrations`. However, this - # decorator saves the task to the database, which is not desired unless it is - # being run by processor, and to indicate the we set this `RUN_BY_PROCESSOR` - # environment variable. - os.environ["RUN_BY_PROCESSOR"] = "True" - - # Since all the apps are loaded before the command is initialised, - # we need to reload some of those modules(that contains recurring tasks) - # to ensure the tasks are registered correctly - # e.g the tasks module is loaded by the ready method in TaskProcessorConfig - # which is run before the command is initialised - - for module in TASKS_MODULES_TO_RELOAD: - reload(module) - signal.signal(signal.SIGINT, self._exit_gracefully) signal.signal(signal.SIGTERM, self._exit_gracefully) diff --git a/api/tests/unit/custom_auth/test_tasks.py b/api/tests/unit/custom_auth/test_tasks.py new file mode 100644 index 000000000000..1013634ecbc4 --- /dev/null +++ b/api/tests/unit/custom_auth/test_tasks.py @@ -0,0 +1,35 @@ +from datetime import timedelta + +from django.utils import timezone +from pytest_django.fixtures import SettingsWrapper + +from custom_auth.models import UserPasswordResetRequest +from custom_auth.tasks import clean_up_user_password_reset_request +from users.models import FFAdminUser + + +def test_clean_up_user_password_reset_request( + settings: SettingsWrapper, test_user: FFAdminUser, freezer +): + # Given + settings.PASSWORD_RESET_EMAIL_COOLDOWN = 10 + now = timezone.now() + + # A user password reset request should be deleted + UserPasswordResetRequest.objects.create(user=test_user) + + freezer.move_to(now + timedelta(seconds=11)) + + # A user password reset request should not be deleted + new_user_password_reset_request = UserPasswordResetRequest.objects.create( + user=test_user + ) + # When + clean_up_user_password_reset_request() + + # Then + assert UserPasswordResetRequest.objects.count() == 1 + assert ( + UserPasswordResetRequest.objects.first().id + == new_user_password_reset_request.id + ) diff --git a/api/tests/unit/sse/test_tasks.py b/api/tests/unit/sse/test_tasks.py index 7510e35aa9c4..b0e1d76a541b 100644 --- a/api/tests/unit/sse/test_tasks.py +++ b/api/tests/unit/sse/test_tasks.py @@ -1,7 +1,5 @@ -import os from datetime import datetime from typing import Callable -from unittest import mock from unittest.mock import call import pytest @@ -17,10 +15,6 @@ send_environment_update_message_for_project, update_sse_usage, ) -from task_processor.management.commands.runprocessor import ( - Command as RunProcessorCommand, -) -from task_processor.models import RecurringTask def test_send_environment_update_message_for_project_make_correct_request( @@ -144,24 +138,3 @@ def test_track_sse_usage( bucket=influxdb_bucket, record=mocked_influx_point().field().tag().tag().tag().time(), ) - - -@mock.patch.dict(os.environ, {}) -@pytest.mark.django_db -def test_track_sse_usage_is_installed_correctly( - settings: SettingsWrapper, -): - # Given - settings.AWS_SSE_LOGS_BUCKET_NAME = "test_bucket" - - # When - # Initialising the command should save the task to the database - RunProcessorCommand() - - # Then - assert ( - RecurringTask.objects.filter( - task_identifier=f"tasks.{update_sse_usage.__name__}" - ).exists() - is True - )