Ctrl K
ComunidadGuías…

rex/retention.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""Scheduled retention cleanup jobs for dashboard and inbound SMS stores.

Wire-up functions register cleanup jobs in the global scheduler so that
old notifications and inbound SMS records are pruned on a configurable
schedule.

Design rules:
- Dashboard cleanup is scheduled when ``notifications.dashboard.store.cleanup_schedule``
  is non-null (default ``"interval:86400"`` — daily).
- Inbound SMS cleanup is scheduled only when ``messaging.inbound.enabled`` is
  ``true`` AND ``messaging.inbound.cleanup_schedule`` is non-null.
- All failures are caught and logged as warnings so that missing config or
  unavailable stores never crash startup.
- Registering jobs twice is idempotent: a second call is a no-op when the
  job already exists in the scheduler.
"""

from __future__ import annotations

import logging
from typing import Any

logger = logging.getLogger(__name__)


def setup_dashboard_cleanup_job(
    raw_config: dict[str, Any] | None = None,
    scheduler: Any | None = None,
) -> bool:
    """No-op stub — dashboard cleanup is deferred to OpenClaw.

    The legacy dashboard notification store is scheduled for retirement as
    part of the OpenClaw migration.  Dashboard notification retention is no
    longer registered as a scheduled job; OpenClaw will manage its own state
    retention once the legacy store is retired.

    Args:
        raw_config: Ignored (retained for API compatibility).
        scheduler: Ignored (retained for API compatibility).

    Returns:
        Always ``False`` — no job is registered.
    """
    # OPENCLAW-REPLACE: remove this function when the dashboard store is retired.
    logger.debug(
        "Dashboard cleanup job skipped — dashboard store is pending retirement "
        "(OpenClaw migration in progress)"
    )
    return False


def setup_inbound_sms_cleanup_job(
    raw_config: dict[str, Any] | None = None,
    scheduler: Any | None = None,
) -> bool:
    """No-op stub — inbound SMS cleanup is deferred to OpenClaw.

    The legacy ``rex.messaging_backends`` inbound store has been retired as
    part of the OpenClaw migration.  Inbound SMS retention is no longer
    registered as a scheduled job; OpenClaw will manage its own messaging
    state once the migration is complete.

    Args:
        raw_config: Ignored (retained for API compatibility).
        scheduler: Ignored (retained for API compatibility).

    Returns:
        Always ``False`` — no job is registered.
    """
    # OPENCLAW-REPLACE: messaging_backends retired in iter 91.
    logger.debug(
        "Inbound SMS cleanup job skipped — messaging backend retired "
        "(OpenClaw migration in progress)"
    )
    return False


def setup_retention_jobs(
    raw_config: dict[str, Any] | None = None,
    scheduler: Any | None = None,
) -> dict[str, bool]:
    """Register all retention cleanup jobs.

    Calls both :func:`setup_dashboard_cleanup_job` and
    :func:`setup_inbound_sms_cleanup_job`.  Failures in either are caught and
    logged as warnings so that the other job can still be registered.

    Args:
        raw_config: Full runtime config dict.  Pass ``None`` to load from disk.
        scheduler: Scheduler instance.  Uses the global scheduler if ``None``.

    Returns:
        A dict with keys ``"dashboard"`` and ``"inbound_sms"`` whose values are
        ``True`` when the corresponding job was registered and ``False``
        otherwise.
    """
    if raw_config is None:
        try:
            from rex.config_manager import load_config

            raw_config = load_config()
        except Exception as exc:
            logger.warning("Could not load config for retention cleanup setup: %s", exc)
            raw_config = {}

    results: dict[str, bool] = {
        "dashboard": False,
        "inbound_sms": False,
    }

    try:
        results["dashboard"] = setup_dashboard_cleanup_job(raw_config, scheduler)
    except Exception as exc:
        logger.warning("Failed to set up dashboard retention cleanup: %s", exc)

    try:
        results["inbound_sms"] = setup_inbound_sms_cleanup_job(raw_config, scheduler)
    except Exception as exc:
        logger.warning("Failed to set up inbound SMS retention cleanup: %s", exc)

    return results


def wire_retention_cleanup(raw_config: dict[str, Any] | None = None) -> bool:
    """Wire retention cleanup jobs and ensure the scheduler background loop runs.

    Suitable for calling from application entry points such as
    ``flask_proxy.py``.  Loading config from disk when *raw_config* is not
    provided.

    Args:
        raw_config: Full runtime config dict, or ``None`` to load from disk.

    Returns:
        ``True`` if at least one retention job was registered.
    """
    results = setup_retention_jobs(raw_config)

    if any(results.values()):
        # Ensure the scheduler background loop is running so jobs actually execute.
        try:
            from rex.scheduler import get_scheduler

            get_scheduler().start()
        except Exception as exc:
            logger.warning("Could not start scheduler background loop: %s", exc)

    return any(results.values())


__all__ = [
    "setup_dashboard_cleanup_job",
    "setup_inbound_sms_cleanup_job",
    "setup_retention_jobs",
    "wire_retention_cleanup",
]