Prepare a container for use, ensuring clean state. This function implements the pre-run phase: 1. Checks if container name already exists in DB 2. If owner process is alive, raises error (container in use) 3. If owner process is dead, cleans up orphaned container 4. Removes any
(
container_name: str,
image_name: str,
create_container_fn: Callable[[], str],
db: Optional[ContainerDatabase] = None,
config_hash: str = "",
platform_type: str = "",
)
| 494 | |
| 495 | |
| 496 | def prepare_container( |
| 497 | container_name: str, |
| 498 | image_name: str, |
| 499 | create_container_fn: Callable[[], str], |
| 500 | db: Optional[ContainerDatabase] = None, |
| 501 | config_hash: str = "", |
| 502 | platform_type: str = "", |
| 503 | ) -> tuple[str, bool]: |
| 504 | """Prepare a container for use, ensuring clean state. |
| 505 | |
| 506 | This function implements the pre-run phase: |
| 507 | 1. Checks if container name already exists in DB |
| 508 | 2. If owner process is alive, raises error (container in use) |
| 509 | 3. If owner process is dead, cleans up orphaned container |
| 510 | 4. Removes any untracked Docker containers with same name |
| 511 | 5. Creates fresh container using provided function |
| 512 | 6. Registers container in database |
| 513 | |
| 514 | Args: |
| 515 | container_name: Name for the container |
| 516 | image_name: Docker image name to use |
| 517 | create_container_fn: Callable that creates and starts container, returns container ID |
| 518 | db: Database instance (creates new if None) |
| 519 | |
| 520 | Returns: |
| 521 | Tuple of (container_id, was_cleaned) where was_cleaned indicates if cleanup occurred |
| 522 | |
| 523 | Raises: |
| 524 | RuntimeError: If container is already in use by another process |
| 525 | """ |
| 526 | if db is None: |
| 527 | db = ContainerDatabase() |
| 528 | |
| 529 | current_pid = os.getpid() |
| 530 | was_cleaned = False |
| 531 | |
| 532 | # Check if container name already exists in DB |
| 533 | existing = db.get_by_name(container_name) |
| 534 | |
| 535 | if existing: |
| 536 | # Check if owner process is still alive |
| 537 | if process_exists(existing.owner_pid): |
| 538 | # Owner is alive - cannot proceed |
| 539 | raise RuntimeError( |
| 540 | f"Container '{container_name}' is already in use by PID {existing.owner_pid}. " |
| 541 | f"Stop that process first or wait for it to complete.\n\n" |
| 542 | f"To force cleanup:\n" |
| 543 | f" kill {existing.owner_pid}\n" |
| 544 | f" OR\n" |
| 545 | f" uv run python -m ci.docker.cleanup_orphans" |
| 546 | ) |
| 547 | else: |
| 548 | # Owner is dead - orphaned container, clean it up |
| 549 | print( |
| 550 | f"Cleaning up orphaned container from dead process {existing.owner_pid}" |
| 551 | ) |
| 552 | success, error_msg = docker_force_remove_container(existing.container_id) |
| 553 | if not success: |
nothing calls this directly
no test coverage detected