diff --git a/convey/cli.py b/convey/cli.py index 56d4c9009..ed696db07 100644 --- a/convey/cli.py +++ b/convey/cli.py @@ -63,8 +63,6 @@ def run_service( def main() -> None: """Main CLI entry point for convey command.""" - from pathlib import Path - from think.utils import ( get_journal, setup_cli, @@ -72,7 +70,6 @@ def main() -> None: ) from . import create_app - from .maint import run_pending_tasks parser = argparse.ArgumentParser(description="Convey web interface") parser.add_argument( @@ -89,12 +86,6 @@ def main() -> None: args = setup_cli(parser) journal = get_journal() - # Run pending maintenance tasks before starting - if not args.skip_maint: - ran, succeeded = run_pending_tasks(Path(journal)) - if ran > 0: - logger.info(f"Completed {succeeded}/{ran} maintenance task(s)") - app = create_app(journal) password = _resolve_config_password_hash() if password: diff --git a/convey/maint_cli.py b/convey/maint_cli.py index e79ace984..3becf89a7 100644 --- a/convey/maint_cli.py +++ b/convey/maint_cli.py @@ -20,7 +20,7 @@ from pathlib import Path from think.utils import get_journal, setup_cli -from .maint import ( +from think.maint import ( get_state_file, get_task_by_name, get_task_status, diff --git a/docs/APPS.md b/docs/APPS.md index b569bfc37..0ee09a9aa 100644 --- a/docs/APPS.md +++ b/docs/APPS.md @@ -455,7 +455,7 @@ apps/my_app/talent/my-skill/ ### 11. `maint/` - Maintenance Tasks -Define one-time maintenance scripts that run automatically on Convey startup. +Define one-time maintenance scripts that run automatically when supervisor starts. **Key Points:** - Create `maint/` directory with standalone Python scripts (each with a `main()` function) @@ -468,7 +468,7 @@ Define one-time maintenance scripts that run automatically on Convey startup. **Reference implementations:** - Example task: `apps/entities/maint/001_migrate_to_journal_entities.py` - real migration task demonstrating maint patterns -- Discovery logic: `convey/maint.py` - `discover_tasks()`, `run_task()` +- Discovery logic: `think/maint.py` - `discover_tasks()`, `run_task()` --- diff --git a/tests/test_maint.py b/tests/test_maint.py index 94996e3dc..dc9e4fe1c 100644 --- a/tests/test_maint.py +++ b/tests/test_maint.py @@ -8,7 +8,7 @@ from pathlib import Path import pytest -from convey.maint import ( +from think.maint import ( MaintTask, get_state_file, get_task_status, @@ -115,7 +115,7 @@ class TestListTasks: def mock_discover_tasks(): return tasks - monkeypatch.setattr("convey.maint.discover_tasks", mock_discover_tasks) + monkeypatch.setattr("think.maint.discover_tasks", mock_discover_tasks) # Success task with timestamp success_file = get_state_file(temp_journal, "chat", "done") @@ -164,7 +164,7 @@ class TestListTasks: def mock_discover_tasks(): return tasks - monkeypatch.setattr("convey.maint.discover_tasks", mock_discover_tasks) + monkeypatch.setattr("think.maint.discover_tasks", mock_discover_tasks) # Success task with line events and duration success_file = get_state_file(temp_journal, "chat", "done") @@ -199,7 +199,7 @@ class TestListTasks: def mock_discover_tasks(): return tasks - monkeypatch.setattr("convey.maint.discover_tasks", mock_discover_tasks) + monkeypatch.setattr("think.maint.discover_tasks", mock_discover_tasks) # In-progress task: exec event but no exit event state_file = get_state_file(temp_journal, "chat", "running") diff --git a/convey/maint.py b/think/maint.py similarity index 100% rename from convey/maint.py rename to think/maint.py diff --git a/think/supervisor.py b/think/supervisor.py index 1624b2bed..affa9ab75 100644 --- a/think/supervisor.py +++ b/think/supervisor.py @@ -21,6 +21,7 @@ from desktop_notifier import DesktopNotifier, Urgency from think import routines, scheduler from think.callosum import CallosumConnection, CallosumServer +from think.maint import run_pending_tasks from think.runner import DailyLogWriter from think.runner import ManagedProcess as RunnerManagedProcess from think.utils import ( @@ -1435,6 +1436,22 @@ def main() -> None: # Remote mode: run sync instead of local processing _is_remote_mode = bool(args.remote) + # Run pending journal-maintenance tasks before spawning any writer children. + # Callosum isn't up yet (emit_fn=None); migrations log through supervisor's logger only. + try: + ran, succeeded = run_pending_tasks(journal_path, emit_fn=None) + if ran > 0: + if ran == succeeded: + logging.info("Completed %d/%d maintenance task(s)", succeeded, ran) + else: + logging.error( + "Maintenance tasks completed with failures: %d/%d succeeded", + succeeded, + ran, + ) + except Exception: + logging.exception("Maintenance runner raised; continuing startup") + # Start Callosum in-process first - it's the message bus that other services depend on try: start_callosum_in_process()