Force remove a Docker container with retry logic. Uses 'docker rm -f' to forcefully remove a container, retrying with exponential backoff if it fails due to timing issues. Args: container_id: Container ID to remove max_retries: Maximum number of retry attempts (default:
(
container_id: str, max_retries: int = 3
)
| 442 | |
| 443 | |
| 444 | def docker_force_remove_container( |
| 445 | container_id: str, max_retries: int = 3 |
| 446 | ) -> tuple[bool, str]: |
| 447 | """Force remove a Docker container with retry logic. |
| 448 | |
| 449 | Uses 'docker rm -f' to forcefully remove a container, retrying with |
| 450 | exponential backoff if it fails due to timing issues. |
| 451 | |
| 452 | Args: |
| 453 | container_id: Container ID to remove |
| 454 | max_retries: Maximum number of retry attempts (default: 3) |
| 455 | |
| 456 | Returns: |
| 457 | Tuple of (success: bool, error_message: str) |
| 458 | """ |
| 459 | import time |
| 460 | |
| 461 | for attempt in range(max_retries): |
| 462 | try: |
| 463 | result = subprocess.run( |
| 464 | [get_docker_command(), "rm", "-f", container_id], |
| 465 | capture_output=True, |
| 466 | text=True, |
| 467 | timeout=30, |
| 468 | ) |
| 469 | if result.returncode == 0: |
| 470 | return True, "" |
| 471 | |
| 472 | # Failed - capture error message |
| 473 | error_msg = ( |
| 474 | result.stderr.strip() if result.stderr else result.stdout.strip() |
| 475 | ) |
| 476 | |
| 477 | # If this is the last attempt, return the error |
| 478 | if attempt == max_retries - 1: |
| 479 | return False, error_msg |
| 480 | |
| 481 | # Retry with exponential backoff: 0.5s, 1s, 2s |
| 482 | wait_time = 0.5 * (2**attempt) |
| 483 | time.sleep(wait_time) |
| 484 | |
| 485 | except FileNotFoundError: |
| 486 | return False, "Docker command not found" |
| 487 | except subprocess.TimeoutExpired: |
| 488 | if attempt == max_retries - 1: |
| 489 | return False, "Docker command timed out after 30 seconds" |
| 490 | # Retry on timeout |
| 491 | time.sleep(0.5 * (2**attempt)) |
| 492 | |
| 493 | return False, "Max retries exceeded" |
| 494 | |
| 495 | |
| 496 | def prepare_container( |
no test coverage detected