Skip to content

Commit 4acad84

Browse files
authored
add clean container task (alibaba#621)
* Add file cleanup task (alibaba#584) * add release note 120 * Revert "add release note 120" This reverts commit 65a11fd. * add file clean task * add file cleanup task * add container cleanup task
1 parent 8fb2831 commit 4acad84

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# rock/admin/scheduler/tasks/__init__.py
2+
from rock.admin.scheduler.tasks.container_cleanup_task import ContainerCleanupTask
23
from rock.admin.scheduler.tasks.file_cleanup_task import FileCleanupTask
34
from rock.admin.scheduler.tasks.image_cleanup_task import ImageCleanupTask
45

5-
__all__ = ["FileCleanupTask", "ImageCleanupTask"]
6+
__all__ = ["ContainerCleanupTask", "FileCleanupTask", "ImageCleanupTask"]
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# rock/admin/scheduler/tasks/container_cleanup_task.py
2+
from rock import env_vars
3+
from rock.admin.proto.request import SandboxCommand as Command
4+
from rock.admin.scheduler.task_base import BaseTask, IdempotencyType, TaskStatusEnum
5+
from rock.common.constants import PID_PREFIX, PID_SUFFIX, SCHEDULER_LOG_NAME
6+
from rock.logger import init_logger
7+
from rock.sandbox.remote_sandbox import RemoteSandboxRuntime
8+
from rock.utils.system import extract_nohup_pid
9+
10+
logger = init_logger(name="container_cleanup", file_name=SCHEDULER_LOG_NAME)
11+
12+
13+
class ContainerCleanupTask(BaseTask):
14+
"""Scheduled task for cleaning up stopped Docker containers older than a specified age."""
15+
16+
def __init__(
17+
self,
18+
interval_seconds: int = 86400,
19+
max_age_hours: int = 24,
20+
):
21+
"""
22+
Initialize container cleanup task.
23+
24+
Args:
25+
interval_seconds: Execution interval in seconds, default 24 hours (86400s)
26+
max_age_hours: Max container age in hours since it stopped, default 24 hours
27+
"""
28+
super().__init__(
29+
type="container_cleanup",
30+
interval_seconds=interval_seconds,
31+
idempotency=IdempotencyType.IDEMPOTENT,
32+
)
33+
self.max_age_hours = max_age_hours
34+
35+
@classmethod
36+
def from_config(cls, task_config) -> "ContainerCleanupTask":
37+
"""Create task instance from config."""
38+
max_age_hours = task_config.params.get("max_age_hours", 24)
39+
return cls(
40+
interval_seconds=task_config.interval_seconds,
41+
max_age_hours=max_age_hours,
42+
)
43+
44+
async def run_action(self, runtime: RemoteSandboxRuntime) -> dict:
45+
"""Run container cleanup action.
46+
47+
Removes exited Docker containers whose finish time exceeds max_age_hours.
48+
"""
49+
log_dir = env_vars.ROCK_LOGGING_PATH if env_vars.ROCK_LOGGING_PATH else "/tmp"
50+
command = (
51+
f"nohup bash -c '"
52+
f"docker ps -aq --filter status=created | xargs -r docker rm; "
53+
f'cutoff=$(date -d "{self.max_age_hours} hours ago" +%s); '
54+
f"docker ps -aq --filter status=exited | "
55+
f'xargs -r docker inspect --format "{{{{.Id}}}} {{{{.State.FinishedAt}}}}" | '
56+
f"while read -r id finished; do "
57+
f'[ "$finished" = "0001-01-01T00:00:00Z" ] && continue; '
58+
f'finished_ts=$(date -d "$finished" +%s 2>/dev/null) || continue; '
59+
f'[ "$finished_ts" -lt "$cutoff" ] && docker rm "$id"; '
60+
f"done"
61+
f"' > {log_dir}/container_cleanup.log 2>&1 & echo {PID_PREFIX}${{!}}{PID_SUFFIX}"
62+
)
63+
64+
result = await runtime.execute(Command(command=command, shell=True))
65+
66+
pid = extract_nohup_pid(result.stdout)
67+
logger.info(
68+
f"container cleanup task [{pid}] run successfully on worker[{runtime._config.host}], "
69+
f"max_age_hours={self.max_age_hours}"
70+
)
71+
72+
return {
73+
"pid": pid,
74+
"max_age_hours": self.max_age_hours,
75+
"status": TaskStatusEnum.RUNNING,
76+
}

0 commit comments

Comments
 (0)