From 334728e16e822adb6735df2bb9b2a426358845c4 Mon Sep 17 00:00:00 2001 From: Dwi Swandhana Date: Sun, 2 Aug 2026 05:31:32 +0700 Subject: [PATCH] update --- htdocs/.env.example | 2 +- htdocs/README.md | 14 +++- .../Commands/BackupUploadFileCommand.php | 68 ++++++++++++++++--- 3 files changed, 72 insertions(+), 12 deletions(-) diff --git a/htdocs/.env.example b/htdocs/.env.example index f668f89e..935e4799 100644 --- a/htdocs/.env.example +++ b/htdocs/.env.example @@ -68,7 +68,7 @@ BPJS_SERVICE_NAME="new-vclaim-rest" CLOUD_BACKUP_API_URL=https://duidev.com CLOUD_BACKUP_API_TOKEN= CLOUD_BACKUP_NAME=lismikro -CLOUD_BACKUP_CHUNK_SIZE=5242880 +CLOUD_BACKUP_CHUNK_SIZE=1048576 CLOUD_BACKUP_DOWNLOAD_PATH= CLOUD_BACKUP_PG_RESTORE=pg_restore CLOUD_BACKUP_DB_HOST=10.10.123.193 diff --git a/htdocs/README.md b/htdocs/README.md index 3d39d30a..1aa4aa18 100644 --- a/htdocs/README.md +++ b/htdocs/README.md @@ -71,7 +71,7 @@ Tambahkan konfigurasi berikut di file `.env` server production `10.10.123.218`: CLOUD_BACKUP_API_URL=https://duidev.com CLOUD_BACKUP_API_TOKEN=isi_token_rahasia_yang_sama_dengan_duidev CLOUD_BACKUP_NAME=lismikro -CLOUD_BACKUP_CHUNK_SIZE=5242880 +CLOUD_BACKUP_CHUNK_SIZE=1048576 CLOUD_BACKUP_DB_HOST=10.10.123.193 CLOUD_BACKUP_DB_PORT=5002 CLOUD_BACKUP_DB_DATABASE=lismikro @@ -123,7 +123,7 @@ if [ $STATUS -eq 0 ]; then echo "Backup berhasil: $FILE" cd /home/mikro/project/htdocs - php artisan backup:upload-file "$FILE" + php artisan backup:upload-file "$FILE" --retries=10 --retry-delay=15 --timeout=300 UPLOAD_STATUS=$? if [ $UPLOAD_STATUS -eq 0 ]; then @@ -170,6 +170,16 @@ cd /home/mikro/project/htdocs php artisan backup:upload-file /home/mikro/project/backups/lismikro_YYYY-MM-DD_HH-MM-SS.backup ``` +Jika upload pernah gagal dengan HTTP `524`, gunakan chunk lebih kecil dan retry lebih banyak: + +```bash +php artisan backup:upload-file /home/mikro/project/backups/lismikro_YYYY-MM-DD_HH-MM-SS.backup \ + --chunk-size=1048576 \ + --retries=10 \ + --retry-delay=15 \ + --timeout=300 +``` + ### Download Backup Terbaru Untuk download saja tanpa restore: diff --git a/htdocs/app/Console/Commands/BackupUploadFileCommand.php b/htdocs/app/Console/Commands/BackupUploadFileCommand.php index dee8872c..de439beb 100644 --- a/htdocs/app/Console/Commands/BackupUploadFileCommand.php +++ b/htdocs/app/Console/Commands/BackupUploadFileCommand.php @@ -3,6 +3,7 @@ namespace App\Console\Commands; use Illuminate\Console\Command; +use Illuminate\Http\Client\Response; use Illuminate\Support\Facades\Http; use Illuminate\Support\Str; @@ -13,7 +14,10 @@ class BackupUploadFileCommand extends Command {--url= : Base URL server cloud backup} {--token= : Token API cloud backup} {--name= : Nama backup} - {--chunk-size= : Ukuran chunk dalam byte}'; + {--chunk-size= : Ukuran chunk dalam byte} + {--retries=5 : Jumlah percobaan ulang setiap chunk} + {--retry-delay=10 : Jeda percobaan ulang dalam detik} + {--timeout=300 : Timeout request upload dalam detik}'; protected $description = 'Upload file backup ke duidev.com secara bertahap/chunked.'; @@ -29,6 +33,9 @@ class BackupUploadFileCommand extends Command $token = (string) ($this->option('token') ?: config('cloud_backup.api_token')); $backupName = (string) ($this->option('name') ?: config('cloud_backup.backup_name', 'lismikro')); $chunkSize = (int) ($this->option('chunk-size') ?: config('cloud_backup.chunk_size', 5 * 1024 * 1024)); + $retries = max(1, (int) $this->option('retries')); + $retryDelay = max(0, (int) $this->option('retry-delay')); + $timeout = max(30, (int) $this->option('timeout')); if ($baseUrl === '' || $token === '') { $this->error('CLOUD_BACKUP_API_URL dan CLOUD_BACKUP_API_TOKEN wajib diisi.'); @@ -47,6 +54,7 @@ class BackupUploadFileCommand extends Command $endpoint = $baseUrl . '/api/backups/chunk'; $this->info('Upload backup: ' . basename($file)); + $this->info('Upload ID: ' . $uploadId); $this->info('Total chunk: ' . $totalChunks); $handle = fopen($file, 'rb'); @@ -63,10 +71,12 @@ class BackupUploadFileCommand extends Command return Command::FAILURE; } - $response = Http::withToken($token) - ->timeout(300) - ->attach('chunk', $chunk, 'chunk_' . $index . '.part') - ->post($endpoint, [ + $response = $this->uploadChunk( + endpoint: $endpoint, + token: $token, + chunk: $chunk, + chunkIndex: $index, + payload: [ 'backup_name' => $backupName, 'upload_id' => $uploadId, 'filename' => basename($file), @@ -74,11 +84,15 @@ class BackupUploadFileCommand extends Command 'total_chunks' => $totalChunks, 'total_size' => $size, 'checksum' => $checksum, - ]); + ], + retries: $retries, + retryDelay: $retryDelay, + timeout: $timeout + ); - if (!$response->successful()) { - $this->error('Upload chunk ke-' . $index . ' gagal. HTTP ' . $response->status()); - $this->line($response->body()); + if (!$response || !$response->successful()) { + $this->error('Upload chunk ke-' . $index . ' gagal. HTTP ' . ($response?->status() ?: '-')); + $this->line($response?->body() ?: 'Tidak ada response dari server.'); return Command::FAILURE; } @@ -92,4 +106,40 @@ class BackupUploadFileCommand extends Command return Command::SUCCESS; } + + private function uploadChunk( + string $endpoint, + string $token, + string $chunk, + int $chunkIndex, + array $payload, + int $retries, + int $retryDelay, + int $timeout + ): ?Response { + $response = null; + + for ($attempt = 1; $attempt <= $retries; $attempt++) { + try { + $response = Http::withToken($token) + ->timeout($timeout) + ->attach('chunk', $chunk, 'chunk_' . $chunkIndex . '.part') + ->post($endpoint, $payload); + + if ($response->successful()) { + return $response; + } + + $this->warn('Chunk ' . ($chunkIndex + 1) . ' gagal percobaan ' . $attempt . '/' . $retries . '. HTTP ' . $response->status()); + } catch (\Throwable $e) { + $this->warn('Chunk ' . ($chunkIndex + 1) . ' gagal percobaan ' . $attempt . '/' . $retries . ': ' . $e->getMessage()); + } + + if ($attempt < $retries && $retryDelay > 0) { + sleep($retryDelay); + } + } + + return $response; + } }