diff --git a/app/Jobs/DatabaseBackupJob.php b/app/Jobs/DatabaseBackupJob.php
index a6c423cac..adb5473b5 100644
--- a/app/Jobs/DatabaseBackupJob.php
+++ b/app/Jobs/DatabaseBackupJob.php
@@ -23,6 +23,8 @@ use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Str;
+use Throwable;
+use Visus\Cuid2\Cuid2;
class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
{
@@ -60,9 +62,16 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
public ?S3Storage $s3 = null;
+ public $timeout = 3600;
+
+ public string $backup_log_uuid;
+
public function __construct(public ScheduledDatabaseBackup $backup)
{
$this->onQueue('high');
+ $this->timeout = $backup->timeout;
+
+ $this->backup_log_uuid = (string) new Cuid2;
}
public function handle(): void
@@ -219,12 +228,8 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$this->mongo_root_username = str($rootUsername)->after('MONGO_INITDB_ROOT_USERNAME=')->value();
}
}
- \Log::info('MongoDB credentials extracted from environment', [
- 'has_username' => filled($this->mongo_root_username),
- 'has_password' => filled($this->mongo_root_password),
- ]);
+
} catch (\Throwable $e) {
- \Log::warning('Failed to extract MongoDB environment variables', ['error' => $e->getMessage()]);
// Continue without env vars - will be handled in backup_standalone_mongodb method
}
}
@@ -288,6 +293,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
}
$this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([
+ 'uuid' => $this->backup_log_uuid,
'database_name' => $database,
'filename' => $this->backup_location,
'scheduled_database_backup_id' => $this->backup->id,
@@ -307,6 +313,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
$this->backup_file = "/mongo-dump-$databaseName-".Carbon::now()->timestamp.'.tar.gz';
$this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([
+ 'uuid' => $this->backup_log_uuid,
'database_name' => $databaseName,
'filename' => $this->backup_location,
'scheduled_database_backup_id' => $this->backup->id,
@@ -319,6 +326,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
}
$this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([
+ 'uuid' => $this->backup_log_uuid,
'database_name' => $database,
'filename' => $this->backup_location,
'scheduled_database_backup_id' => $this->backup->id,
@@ -331,6 +339,7 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
}
$this->backup_location = $this->backup_dir.$this->backup_file;
$this->backup_log = ScheduledDatabaseBackupExecution::create([
+ 'uuid' => $this->backup_log_uuid,
'database_name' => $database,
'filename' => $this->backup_location,
'scheduled_database_backup_id' => $this->backup->id,
@@ -574,4 +583,18 @@ class DatabaseBackupJob implements ShouldBeEncrypted, ShouldQueue
return "{$helperImage}:{$latestVersion}";
}
+
+ public function failed(?Throwable $exception): void
+ {
+ $log = ScheduledDatabaseBackupExecution::where('uuid', $this->backup_log_uuid)->first();
+
+ if ($log) {
+ $log->update([
+ 'status' => 'failed',
+ 'message' => 'Job failed: '.$exception->getMessage(),
+ 'size' => 0,
+ 'filename' => null,
+ ]);
+ }
+ }
}
diff --git a/app/Livewire/Project/Database/BackupEdit.php b/app/Livewire/Project/Database/BackupEdit.php
index 0d363e983..abc88d736 100644
--- a/app/Livewire/Project/Database/BackupEdit.php
+++ b/app/Livewire/Project/Database/BackupEdit.php
@@ -73,6 +73,9 @@ class BackupEdit extends Component
#[Validate(['required', 'boolean'])]
public bool $dumpAll = false;
+ #[Validate(['required', 'int', 'min:1', 'max:36000'])]
+ public int $timeout = 3600;
+
public function mount()
{
try {
@@ -98,6 +101,7 @@ class BackupEdit extends Component
$this->backup->s3_storage_id = $this->s3StorageId;
$this->backup->databases_to_backup = $this->databasesToBackup;
$this->backup->dump_all = $this->dumpAll;
+ $this->backup->timeout = $this->timeout;
$this->customValidate();
$this->backup->save();
} else {
@@ -114,6 +118,7 @@ class BackupEdit extends Component
$this->s3StorageId = $this->backup->s3_storage_id;
$this->databasesToBackup = $this->backup->databases_to_backup;
$this->dumpAll = $this->backup->dump_all;
+ $this->timeout = $this->backup->timeout;
}
}
diff --git a/database/migrations/2025_07_16_202201_add_timeout_to_scheduled_database_backups_table.php b/database/migrations/2025_07_16_202201_add_timeout_to_scheduled_database_backups_table.php
new file mode 100644
index 000000000..f8f8cb8ad
--- /dev/null
+++ b/database/migrations/2025_07_16_202201_add_timeout_to_scheduled_database_backups_table.php
@@ -0,0 +1,18 @@
+integer('timeout')->default(3600);
+ });
+ }
+};
diff --git a/resources/views/livewire/project/database/backup-edit.blade.php b/resources/views/livewire/project/database/backup-edit.blade.php
index f83af91a0..c070edba2 100644
--- a/resources/views/livewire/project/database/backup-edit.blade.php
+++ b/resources/views/livewire/project/database/backup-edit.blade.php
@@ -77,6 +77,7 @@