enterprise/server/maintenance_task_processor/README.md
This package contains the maintenance task system for running background maintenance operations in the OpenHands deployment wrapper.
The maintenance task system provides a framework for running background tasks that perform maintenance operations such as upgrading user settings, cleaning up data, or other periodic maintenance work. Tasks are designed to be short-running (typically under a minute) and handle background state upgrades. The runner is triggered as part of every deploy, though does not block it.
The system consists of several key components:
MaintenanceTask)Located in storage/maintenance_task.py, this model stores maintenance tasks with the following fields:
id: Primary keystatus: Task status (INACTIVE, PENDING, WORKING, COMPLETED, ERROR)processor_type: Fully qualified class name of the processorprocessor_json: JSON serialized processor configurationdelay: Delay before starting taskinfo: JSON field containing structured information about the task outcomecreated_at: When the task was createdupdated_at: When the task was last updatedMaintenanceTaskProcessor)Abstract base class for all maintenance task processors. Processors must implement the __call__ method to perform the actual work.
from storage.maintenance_task import MaintenanceTaskProcessor, MaintenanceTask
class MyProcessor(MaintenanceTaskProcessor):
# Define your processor fields here
some_config: str
async def __call__(self, task: MaintenanceTask) -> dict:
# Implement your maintenance logic here
return {"status": "completed", "processed_items": 42}
Located in user_version_upgrade_processor.py, this processor:
user_version < ORG_SETTINGS_VERSIONSaasSettingsStore.create_default_settings() for upgradesUsage:
from server.maintenance_task_processor.user_version_upgrade_processor import UserVersionUpgradeProcessor
processor = UserVersionUpgradeProcessor(user_ids=["user1", "user2", "user3"])
To create a new maintenance task processor:
MaintenanceTaskProcessor:from storage.maintenance_task import MaintenanceTaskProcessor, MaintenanceTask
from typing import List
class MyMaintenanceProcessor(MaintenanceTaskProcessor):
"""Description of what this processor does."""
# Define configuration fields
target_ids: List[str]
batch_size: int = 50
async def __call__(self, task: MaintenanceTask) -> dict:
"""
Implement your maintenance logic here.
Args:
task: The maintenance task being processed
Returns:
dict: Information about the task execution
"""
try:
# Your maintenance logic here
processed_count = 0
for target_id in self.target_ids:
# Process each target
processed_count += 1
return {
"status": "completed",
"processed_count": processed_count,
"message": f"Successfully processed {processed_count} items"
}
except Exception as e:
return {
"status": "error",
"error": str(e),
"processed_count": processed_count
}
Add the processor to the package by importing it in __init__.py if needed.
Create tasks using the utility functions in server/utils/maintenance_task_utils.py:
from server.utils.maintenance_task_utils import create_maintenance_task
from server.maintenance_task_processor.my_processor import MyMaintenanceProcessor
# Create a task
processor = MyMaintenanceProcessor(target_ids=["id1", "id2"], batch_size=25)
task = create_maintenance_task(processor, start_at=datetime.utcnow())
from datetime import datetime, timedelta
from server.utils.maintenance_task_utils import create_maintenance_task
from server.maintenance_task_processor.user_version_upgrade_processor import UserVersionUpgradeProcessor
# Create a user upgrade task
processor = UserVersionUpgradeProcessor(user_ids=["user1", "user2"])
task = create_maintenance_task(
processor=processor,
start_at=datetime.utcnow() + timedelta(minutes=5) # Start in 5 minutes
)
The maintenance task system follows the repository's established patterns:
session_maker() for database operationscall_sync_from_async for async routesUserSettings modelORG_SETTINGS_VERSION)admin = True in their UserSettingsTasks stuck in WORKING state: Usually indicates the runner crashed while processing. These can be manually reset to PENDING.
Serialization errors: Ensure all processor fields are JSON serializable.
Database connection issues: Check that the processor properly handles database sessions.
Potential improvements that could be added: