diff --git a/gso/migrations/versions/2024-08-13_844aa61c09ce_add_new_cleanup_task.py b/gso/migrations/versions/2024-08-13_844aa61c09ce_add_new_cleanup_task.py new file mode 100644 index 0000000000000000000000000000000000000000..037c092e05a740b230b11f490aa0730829c0499b --- /dev/null +++ b/gso/migrations/versions/2024-08-13_844aa61c09ce_add_new_cleanup_task.py @@ -0,0 +1,44 @@ +"""Add new cleanup task. + +Revision ID: 844aa61c09ce +Revises: 88dd5a44150d +Create Date: 2024-08-13 12:23:11.043293 + +""" + +from uuid import uuid4 + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision = '844aa61c09ce' +down_revision = '88dd5a44150d' +branch_labels = None +depends_on = None + +workflows = [ + { + "name": "task_clean_old_tasks", + "target": "SYSTEM", + "description": "Remove old cleanup tasks", + "workflow_id": uuid4(), + } +] + + +def upgrade() -> None: + conn = op.get_bind() + for workflow in workflows: + conn.execute( + sa.text( + "INSERT INTO workflows VALUES (:workflow_id, :name, :target, :description, now())" + ), + workflow, + ) + + +def downgrade() -> None: + conn = op.get_bind() + for workflow in workflows: + conn.execute(sa.text("DELETE FROM workflows WHERE name = :name"), {"name": workflow["name"]}) diff --git a/gso/schedules/clean_old_tasks.py b/gso/schedules/clean_old_tasks.py new file mode 100644 index 0000000000000000000000000000000000000000..c37d44450209a90033f66b36094e91b6f5403442 --- /dev/null +++ b/gso/schedules/clean_old_tasks.py @@ -0,0 +1,13 @@ +"""Metatask that cleans up old cleanup tasks.""" + +from orchestrator.services.processes import start_process + +from gso.schedules.scheduling import CronScheduleConfig, scheduler +from gso.worker import celery + + +@celery.task +@scheduler(CronScheduleConfig(name="Clean up tasks", hour="3")) +def clean_old_tasks() -> None: + """Run all cleanup tasks every 3 AM UTC.""" + start_process("task_clean_old_tasks") diff --git a/gso/translations/en-GB.json b/gso/translations/en-GB.json index 64843bf05296cd1ce7fc862e22bab6bcfe7af68c..b00f91ebc513bdbe1dc07b125df3d8f0af1dfc5b 100644 --- a/gso/translations/en-GB.json +++ b/gso/translations/en-GB.json @@ -72,6 +72,7 @@ "task_create_partners": "Create partner task", "task_modify_partners": "Modify partner task", "task_delete_partners": "Delete partner task", + "task_clean_old_tasks": "Remove old cleanup tasks", "promote_p_to_pe": "Promote P to PE" } } diff --git a/gso/worker.py b/gso/worker.py index 807c1edb9f41d15e1e099b03e9c0a2ae4845839e..300eb5908457aead3fbbaa7425e8c05bf71d0de5 100644 --- a/gso/worker.py +++ b/gso/worker.py @@ -25,6 +25,7 @@ celery = OrchestratorCelery( "gso.schedules.validate_products", "gso.schedules.validate_subscriptions", "gso.schedules.send_email_notifications", + "gso.schedules.clean_old_tasks", ], ) diff --git a/gso/workflows/__init__.py b/gso/workflows/__init__.py index 82f876bb5a10291e6d648dff90f16b8d6fba6de3..291a9e250e729dfb61554eea3e38fe4d8cab6cd6 100644 --- a/gso/workflows/__init__.py +++ b/gso/workflows/__init__.py @@ -74,3 +74,4 @@ LazyWorkflowInstance("gso.workflows.tasks.validate_geant_products", "task_valida LazyWorkflowInstance("gso.workflows.tasks.create_partners", "task_create_partners") LazyWorkflowInstance("gso.workflows.tasks.modify_partners", "task_modify_partners") LazyWorkflowInstance("gso.workflows.tasks.delete_partners", "task_delete_partners") +LazyWorkflowInstance("gso.workflows.tasks.clean_old_tasks", "task_clean_old_tasks") diff --git a/gso/workflows/tasks/clean_old_tasks.py b/gso/workflows/tasks/clean_old_tasks.py new file mode 100644 index 0000000000000000000000000000000000000000..963e108f7c959bb273a772d9d37e50be1b239d2d --- /dev/null +++ b/gso/workflows/tasks/clean_old_tasks.py @@ -0,0 +1,41 @@ +"""A cleanup task for removing past runs.""" + +from orchestrator.db import ProcessTable, WorkflowTable, db +from orchestrator.targets import Target +from orchestrator.workflow import ProcessStatus, StepList, begin, done, step, workflow +from sqlalchemy import or_, select + + +@step("Clean up all cleanup tasks") +def remove_meta_tasks() -> None: + """Find and remove runs of old cleanup tasks.""" + cleanup_tasks = WorkflowTable.query.filter( + or_(WorkflowTable.name == "task_clean_up_tasks", WorkflowTable.name == "task_clean_old_tasks") + ).all() + + for cleanup_task in cleanup_tasks: + tasks = db.session.scalars( + select(ProcessTable) + .filter(ProcessTable.is_task.is_(True)) + .filter(ProcessTable.workflow_id == cleanup_task.workflow_id) + .filter( + or_( + ProcessTable.last_status == ProcessStatus.COMPLETED.value, + ProcessTable.last_status == ProcessStatus.CREATED.value, + ) + ) + ) + + for task in tasks: + db.session.delete(task) + + +@workflow("Remove old cleanup tasks", target=Target.SYSTEM) +def task_clean_old_tasks() -> StepList: + """Remove all runs of old cleanup tasks. + + This will look for all past executions of the ``orchestrator-core`` built-in cleanup task, and this current cleanup + task. Once they have run to completion, or are stuck in a "created" state, they serve no purpose in the database and + can therefore be removed. + """ + return begin >> remove_meta_tasks >> done diff --git a/test-docs.sh b/test-docs.sh index cdc50473e43e7e6c7356e89a5c994bac86f141c2..2adbe6b0680a8ee99fcb245ae1fec3713f191f4f 100755 --- a/test-docs.sh +++ b/test-docs.sh @@ -1,8 +1,4 @@ #!/bin/bash -if [ ! -d ./docs/vale/styles/proselint ] || [ ! -d ./docs/vale/styles/Microsoft ]; then - docker run -it --rm -v "$(pwd)"/docs:/docs jdkato/vale:latest --config="/docs/vale/.vale.ini" sync -fi - -docker run -it --rm -v "$(pwd)":/gso jdkato/vale:latest --glob='!*/migrations/*' \ ---config="/gso/docs/vale/.vale.ini" /gso/docs/source /gso/gso +vale --config=docs/vale/.vale.ini sync +vale --glob='!*/migrations/*' --config=docs/vale/.vale.ini docs/source gso