Menambahkan exponential backoff (60, 120, 300 detik), timeout 5 menit, dan logging rinci untuk audit cleanup data inspeksi tanpa dokument_id
- Implementasi job queue dengan retry otomatis menggunakan exponential backoff strategy
- Tambahkan timeout 5 menit untuk mencegah hanging jobs
- Gunakan database transaction untuk memastikan atomicity operasi soft delete
- Logging komprehensif untuk audit trail proses cleanup
- Validasi data lengkap (dengan dokument_id) sebelum proses cleanup
- Soft delete data lama tanpa dokument_id hanya jika data baru tersedia
- Pencegahan penghapusan data yang baru saja ditemukan dengan kondisi where('id', '!=', $newInspeksi->id)
- Error handling dengan rollback transaction dan re-throw exception untuk retry mechanism
- Dokumentasi kode yang jelas dengan PHPDoc untuk setiap method
- Menggunakan Laravel best practices dengan ShouldQueue, Dispatchable, InteractsWithQueue, Queueable, SerializesModels traits
156 lines
5.2 KiB
PHP
156 lines
5.2 KiB
PHP
<?php
|
|
|
|
namespace Modules\Lpj\Jobs;
|
|
|
|
use Illuminate\Bus\Queueable;
|
|
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
use Illuminate\Foundation\Bus\Dispatchable;
|
|
use Illuminate\Queue\InteractsWithQueue;
|
|
use Illuminate\Queue\SerializesModels;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Modules\Lpj\Models\Inspeksi;
|
|
|
|
/**
|
|
* Job untuk membersihkan data inspeksi yang tidak memiliki dokument_id
|
|
*
|
|
* Case: Jika ada data inspeksi yang masuk dengan permohonan_id yang sama
|
|
* tetapi memiliki dokument_id dan user created_by yang sama, maka
|
|
* data lama (tanpa dokument_id) akan di-soft delete
|
|
*/
|
|
class CleanupInspeksiDataJob implements ShouldQueue
|
|
{
|
|
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
|
|
|
public $timeout = 300; // 5 menit
|
|
public $tries = 3;
|
|
public $maxExceptions = 3;
|
|
public $backoff = [60, 120, 300]; // Exponential backoff dalam detik
|
|
|
|
protected int $permohonanId;
|
|
protected int $createdBy;
|
|
protected ?int $dokumentId;
|
|
|
|
/**
|
|
* Create a new job instance.
|
|
*
|
|
* @param int $permohonanId
|
|
* @param int $createdBy
|
|
* @param int|null $dokumentId
|
|
*/
|
|
public function __construct(int $permohonanId, int $createdBy, ?int $dokumentId = null)
|
|
{
|
|
$this->permohonanId = $permohonanId;
|
|
$this->createdBy = $createdBy;
|
|
$this->dokumentId = $dokumentId;
|
|
}
|
|
|
|
/**
|
|
* Execute the job.
|
|
*
|
|
* @return void
|
|
* @throws \Exception
|
|
*/
|
|
public function handle(): void
|
|
{
|
|
Log::info('CleanupInspeksiDataJob: Memulai proses cleanup data inspeksi', [
|
|
'permohonan_id' => $this->permohonanId,
|
|
'created_by' => $this->createdBy,
|
|
'dokument_id' => $this->dokumentId
|
|
]);
|
|
|
|
DB::beginTransaction();
|
|
|
|
try {
|
|
// Cari data inspeksi yang memiliki dokument_id (data baru)
|
|
$newInspeksi = Inspeksi::where('permohonan_id', $this->permohonanId)
|
|
->where('created_by', $this->createdBy)
|
|
->whereNotNull('dokument_id')
|
|
->whereNull('deleted_at')
|
|
->first();
|
|
|
|
if (!$newInspeksi) {
|
|
Log::warning('CleanupInspeksiDataJob: Tidak ditemukan data inspeksi baru dengan dokument_id', [
|
|
'permohonan_id' => $this->permohonanId,
|
|
'created_by' => $this->createdBy
|
|
]);
|
|
DB::rollBack();
|
|
return;
|
|
}
|
|
|
|
Log::info('CleanupInspeksiDataJob: Data inspeksi baru ditemukan', [
|
|
'inspeksi_id' => $newInspeksi->id,
|
|
'dokument_id' => $newInspeksi->dokument_id
|
|
]);
|
|
|
|
// Cari data inspeksi lama yang tidak memiliki dokument_id
|
|
$oldInspeksiList = Inspeksi::where('permohonan_id', $this->permohonanId)
|
|
->where('created_by', $this->createdBy)
|
|
->whereNull('dokument_id')
|
|
->whereNull('deleted_at')
|
|
->where('id', '!=', $newInspeksi->id) // Jangan hapus data yang baru saja ditemukan
|
|
->get();
|
|
|
|
if ($oldInspeksiList->isEmpty()) {
|
|
Log::info('CleanupInspeksiDataJob: Tidak ditemukan data inspeksi lama tanpa dokument_id', [
|
|
'permohonan_id' => $this->permohonanId,
|
|
'created_by' => $this->createdBy
|
|
]);
|
|
DB::commit();
|
|
return;
|
|
}
|
|
|
|
$deletedCount = 0;
|
|
foreach ($oldInspeksiList as $oldInspeksi) {
|
|
// Soft delete data lama
|
|
$oldInspeksi->delete(); // Menggunakan soft delete karena model menggunakan SoftDeletes trait
|
|
|
|
Log::info('CleanupInspeksiDataJob: Data inspeksi lama berhasil di-soft delete', [
|
|
'old_inspeksi_id' => $oldInspeksi->id,
|
|
'permohonan_id' => $oldInspeksi->permohonan_id,
|
|
'created_by' => $oldInspeksi->created_by,
|
|
'deleted_at' => now()->toDateTimeString()
|
|
]);
|
|
|
|
$deletedCount++;
|
|
}
|
|
|
|
DB::commit();
|
|
|
|
Log::info('CleanupInspeksiDataJob: Proses cleanup selesai', [
|
|
'permohonan_id' => $this->permohonanId,
|
|
'created_by' => $this->createdBy,
|
|
'deleted_count' => $deletedCount,
|
|
'new_inspeksi_id' => $newInspeksi->id
|
|
]);
|
|
|
|
} catch (\Exception $e) {
|
|
DB::rollBack();
|
|
|
|
Log::error('CleanupInspeksiDataJob: Terjadi error saat proses cleanup', [
|
|
'permohonan_id' => $this->permohonanId,
|
|
'created_by' => $this->createdBy,
|
|
'error' => $e->getMessage(),
|
|
'trace' => $e->getTraceAsString()
|
|
]);
|
|
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle a job failure.
|
|
*
|
|
* @param \Throwable $exception
|
|
* @return void
|
|
*/
|
|
public function failed(\Throwable $exception): void
|
|
{
|
|
Log::error('CleanupInspeksiDataJob: Job gagal dieksekusi', [
|
|
'permohonan_id' => $this->permohonanId,
|
|
'created_by' => $this->createdBy,
|
|
'error' => $exception->getMessage(),
|
|
'trace' => $exception->getTraceAsString()
|
|
]);
|
|
}
|
|
} |