Skip to content

Conversation

@andrasbacsai
Copy link
Member

Changes

  • Add conditional handling in stop_running_container() catch block to detect when deployment has already succeeded
  • Log cleanup warnings with hidden: true to avoid cluttering deployment logs
  • Only re-throw exceptions if the deployment hasn't succeeded yet

Issues

Description

Successful deployments were being marked as FAILED due to exceptions during old container cleanup. When old containers are already removed (a common scenario), the "No such container" error was propagating and failing the entire deployment.

The fix checks if the new version is healthy before re-throwing cleanup exceptions, allowing the deployment to succeed while still logging the cleanup issues for debugging.

…s failed

Fixes #7439 where successful deployments were being marked as FAILED due to exceptions during old container cleanup.

Root cause: Commit 97550f4 wrapped stop_running_container() in try-catch that re-throws ALL exceptions as DeploymentException. When old containers are already removed (a common scenario), the "No such container" error propagates and marks successful deployments as failed.

Solution: Check if deployment has already succeeded (newVersionIsHealthy || force) before re-throwing exceptions from cleanup operations. Cleanup failures are logged but don't fail the deployment.

- Add conditional handling in stop_running_container() catch block
- Log cleanup warnings with hidden: true to avoid UI clutter
- Only re-throw exceptions if deployment hasn't succeeded yet
- Preserves backward compatibility and expected behavior

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@andrasbacsai andrasbacsai changed the base branch from v4.x to next December 2, 2025 20:21
@andrasbacsai andrasbacsai added the 🐰 Release The Rabbit Run CodeRabbitAI review label Dec 2, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 2, 2025

Walkthrough

The change updates error handling in ApplicationDeploymentJob::stop_running_container. In the catch block, if the newly deployed version is healthy or a force flag is set, the code logs a warning and returns without rethrowing; otherwise it preserves the prior behavior of throwing a DeploymentException. No public signatures were changed.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-deployment-cleanup-exceptions

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cfea11f and a18e920.

📒 Files selected for processing (1)
  • app/Jobs/ApplicationDeploymentJob.php (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.php: Use PHP 8.4 constructor property promotion and typed properties
Follow PSR-12 coding standards and run ./vendor/bin/pint before committing
Use Eloquent ORM for database interactions, avoid raw queries
Use Laravel's built-in mocking and Mockery for testing external services and dependencies
Use database transactions for critical operations that modify multiple related records
Leverage query scopes in Eloquent models for reusable, chainable query logic
Never log or expose sensitive data (passwords, tokens, API keys, SSH keys) in logs or error messages
Always validate user input using Form Requests, Rules, or explicit validation methods
Use handleError() helper for consistent error handling and logging
Use eager loading (with(), load()) to prevent N+1 queries when accessing related models
Use chunking for large data operations to avoid memory exhaustion
Implement caching for frequently accessed data using Laravel's cache helpers
Write descriptive variable and method names that clearly express intent
Keep methods small and focused on a single responsibility
Document complex logic with clear comments explaining the 'why' not just the 'what'

Always run code formatting with ./vendor/bin/pint before committing code

Files:

  • app/Jobs/ApplicationDeploymentJob.php
app/Jobs/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Queue heavy operations with Laravel Horizon instead of executing synchronously

Files:

  • app/Jobs/ApplicationDeploymentJob.php
🧬 Code graph analysis (1)
app/Jobs/ApplicationDeploymentJob.php (1)
app/Models/ApplicationDeploymentQueue.php (1)
  • addLogEntry (127-162)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Agent
  • GitHub Check: build-push (aarch64, linux/aarch64, ubuntu-24.04-arm)
🔇 Additional comments (1)
app/Jobs/ApplicationDeploymentJob.php (1)

3190-3202: Hasta la vista, cleanup exceptions!

Listen up, human. This conditional error handling is exactly what a T-800 would write if it understood the difference between mission success and janitor work. Your new container is healthy and serving tacos to the users? Don't let some "No such container" garbage from cleaning up old build artifacts terminate the entire deployment—that's what a serverless platform would do because it can't tell the difference between actual failure and harmless noise.

The logic is solid:

  • New version healthy OR forced cleanup? Log it with hidden: true (nice touch—no need to scare the humans with cleanup warnings) and move on.
  • Deployment actually failed? Re-throw and terminate with extreme prejudice.

This is how you handle Docker containers on real servers. Self-hosted infrastructure means you control the cleanup flow, not some VC-funded abstraction layer that pretends containers don't exist. Based on the PR objectives, this directly fixes issue #7439 where successful deployments were getting marked as failed due to cleanup noise.

I'll be back... but this code doesn't need me. It's already terminated the right exceptions.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between afb1911 and cfea11f.

📒 Files selected for processing (1)
  • app/Jobs/ApplicationDeploymentJob.php (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.php: Use PHP 8.4 constructor property promotion and typed properties
Follow PSR-12 coding standards and run ./vendor/bin/pint before committing
Use Eloquent ORM for database interactions, avoid raw queries
Use Laravel's built-in mocking and Mockery for testing external services and dependencies
Use database transactions for critical operations that modify multiple related records
Leverage query scopes in Eloquent models for reusable, chainable query logic
Never log or expose sensitive data (passwords, tokens, API keys, SSH keys) in logs or error messages
Always validate user input using Form Requests, Rules, or explicit validation methods
Use handleError() helper for consistent error handling and logging
Use eager loading (with(), load()) to prevent N+1 queries when accessing related models
Use chunking for large data operations to avoid memory exhaustion
Implement caching for frequently accessed data using Laravel's cache helpers
Write descriptive variable and method names that clearly express intent
Keep methods small and focused on a single responsibility
Document complex logic with clear comments explaining the 'why' not just the 'what'

Always run code formatting with ./vendor/bin/pint before committing code

Files:

  • app/Jobs/ApplicationDeploymentJob.php
app/Jobs/**/*.php

📄 CodeRabbit inference engine (CLAUDE.md)

Queue heavy operations with Laravel Horizon instead of executing synchronously

Files:

  • app/Jobs/ApplicationDeploymentJob.php
🧬 Code graph analysis (1)
app/Jobs/ApplicationDeploymentJob.php (1)
app/Models/ApplicationDeploymentQueue.php (1)
  • addLogEntry (127-162)
🪛 PHPMD (2.15.0)
app/Jobs/ApplicationDeploymentJob.php

3197-3197: Avoid using static access to class '\Log' in method 'stop_running_container'. (undefined)

(StaticAccess)

Copilot AI review requested due to automatic review settings December 3, 2025 08:16
@andrasbacsai andrasbacsai merged commit 9c80e15 into next Dec 3, 2025
3 checks passed
@andrasbacsai andrasbacsai deleted the fix-deployment-cleanup-exceptions branch December 3, 2025 08:18
@github-actions github-actions bot removed the 🐰 Release The Rabbit Run CodeRabbitAI review label Dec 3, 2025
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR attempts to prevent cleanup exceptions from failing deployments that have already succeeded by adding conditional exception handling in the stop_running_container() method. The fix checks if the new version is healthy or if the $force parameter is true before suppressing cleanup exceptions.

Key changes:

  • Added conditional exception handling to check $this->newVersionIsHealthy || $force before suppressing cleanup exceptions
  • Logged cleanup warnings with hidden: true to avoid cluttering deployment logs
  • Only re-throws exceptions if the deployment hasn't succeeded yet

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +3190 to 3202
// If new version is healthy, this is just cleanup - don't fail the deployment
if ($this->newVersionIsHealthy || $force) {
$this->application_deployment_queue->addLogEntry(
"Warning: Could not remove old container: {$e->getMessage()}",
'stderr',
hidden: true
);

return; // Don't re-throw - cleanup failures shouldn't fail successful deployments
}

// Only re-throw if deployment hasn't succeeded yet
throw new DeploymentException("Failed to stop running container: {$e->getMessage()}", $e->getCode(), $e);
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new exception handling logic in stop_running_container() lacks test coverage. Given the critical nature of this code (it determines whether deployments succeed or fail), tests should be added to verify:

  1. Cleanup exceptions are suppressed when the new version is healthy (rolling update scenario)
  2. Cleanup exceptions fail the deployment when called with force=true before the new container starts
  3. The logging behavior with hidden: true works correctly

Similar deployment logic has test coverage in tests/Unit/ApplicationDeploymentErrorLoggingTest.php, which could serve as a reference.

Copilot uses AI. Check for mistakes.
}
} catch (Exception $e) {
// If new version is healthy, this is just cleanup - don't fail the deployment
if ($this->newVersionIsHealthy || $force) {
Copy link

Copilot AI Dec 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logic error: The condition incorrectly suppresses cleanup exceptions when $force=true. When stop_running_container(force: true) is called at lines 723 and 1744, it happens BEFORE the new container starts, so newVersionIsHealthy is still false. If cleanup fails at that point (e.g., Docker daemon unavailable), the deployment should fail since we haven't successfully started anything yet. The correct condition should be if ($this->newVersionIsHealthy && !$force) - only suppress exceptions when the new version is confirmed healthy AND we're in the post-health-check cleanup phase (when $force=false, as at line 1751).

Suggested change
if ($this->newVersionIsHealthy || $force) {
if ($this->newVersionIsHealthy && !$force) {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Deployments Marked as Failed Even When Successful

1 participant