mirror of
https://github.com/tiennm99/coolify.git
synced 2026-10-14 06:17:36 +00:00
feat(backups): add scheduled persistent volume backups
This commit is contained in:
1 parent
05dc2c65f6
commit
63961e0799
36 files changed
+3506
-31
No files matched your search
@@ -4,6 +4,8 @@ namespace App\Jobs;
|
||||
|
||||
use App\Models\ScheduledDatabaseBackup;
|
||||
use App\Models\ScheduledTask;
|
||||
use App\Models\ScheduledVolumeBackup;
|
||||
use App\Models\ScheduledVolumeBackupExecution;
|
||||
use App\Models\Server;
|
||||
use App\Models\Team;
|
||||
use Cron\CronExpression;
|
||||
@@ -109,6 +111,16 @@ class ScheduledJobManager implements ShouldQueue
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
$this->recoverPausedVolumeBackupContainers();
|
||||
$this->processScheduledVolumeBackups();
|
||||
} catch (\Exception $e) {
|
||||
Log::channel('scheduled-errors')->error('Failed to process scheduled volume backups', [
|
||||
'error' => $e->getMessage(),
|
||||
'trace' => $e->getTraceAsString(),
|
||||
]);
|
||||
}
|
||||
|
||||
// Process Docker cleanups - don't let failures stop the job manager
|
||||
try {
|
||||
$this->processDockerCleanups();
|
||||
@@ -341,6 +353,101 @@ class ScheduledJobManager implements ShouldQueue
|
||||
}
|
||||
}
|
||||
|
||||
private function processScheduledVolumeBackups(): void
|
||||
{
|
||||
ScheduledVolumeBackup::query()
|
||||
->with(['volume', 'team.subscription'])
|
||||
->where('enabled', true)
|
||||
->chunkById(self::CHUNK_SIZE, function ($backups): void {
|
||||
foreach ($backups as $backup) {
|
||||
$this->processScheduledVolumeBackup($backup);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function recoverPausedVolumeBackupContainers(): void
|
||||
{
|
||||
ScheduledVolumeBackupExecution::query()
|
||||
->where(fn (Builder $query) => $query
|
||||
->where('pause_recovery_pending', true)
|
||||
->orWhere('s3_cleanup_pending', true))
|
||||
->chunkById(self::CHUNK_SIZE, function ($executions): void {
|
||||
foreach ($executions as $execution) {
|
||||
VolumeBackupRecoveryJob::dispatch($execution);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private function processScheduledVolumeBackup(ScheduledVolumeBackup $backup): void
|
||||
{
|
||||
try {
|
||||
$server = $backup->server();
|
||||
|
||||
if ($backup->executions()
|
||||
->where(fn (Builder $query) => $query
|
||||
->where('pause_recovery_pending', true)
|
||||
->orWhere('s3_cleanup_pending', true))
|
||||
->exists()) {
|
||||
$this->skippedCount++;
|
||||
$this->logSkip('volume_backup', 'container_recovery_pending', [
|
||||
'backup_id' => $backup->id,
|
||||
'team_id' => $backup->team_id,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $backup->volume || ! $server) {
|
||||
$backup->delete();
|
||||
$this->skippedCount++;
|
||||
$this->logSkip('volume_backup', 'resource_deleted', [
|
||||
'backup_id' => $backup->id,
|
||||
'team_id' => $backup->team_id,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $server->isFunctional()) {
|
||||
$this->skippedCount++;
|
||||
$this->logSkip('volume_backup', 'server_not_functional', [
|
||||
'backup_id' => $backup->id,
|
||||
'team_id' => $backup->team_id,
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (isCloud() && $backup->team_id !== 0 && ! data_get($backup, 'team.subscription.stripe_invoice_paid', false)) {
|
||||
$this->skippedCount++;
|
||||
$this->logSkip('volume_backup', 'subscription_unpaid', [
|
||||
'backup_id' => $backup->id,
|
||||
'team_id' => $backup->team_id,
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->shouldDispatch($backup->frequency, $server, "scheduled-volume-backup:{$backup->id}")) {
|
||||
VolumeBackupJob::dispatch($backup);
|
||||
$this->dispatchedCount++;
|
||||
Log::channel('scheduled')->info('Volume backup dispatched', [
|
||||
'backup_id' => $backup->id,
|
||||
'volume_id' => $backup->local_persistent_volume_id,
|
||||
'team_id' => $backup->team_id,
|
||||
'server_id' => $server->id,
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
Log::channel('scheduled-errors')->error('Error processing volume backup', [
|
||||
'backup_id' => $backup->id,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function getBackupSkipReason(ScheduledDatabaseBackup $backup, ?Server $server): ?string
|
||||
{
|
||||
if (blank(data_get($backup, 'database'))) {
|
||||
|
||||
Reference in new issue
Block a user