From 091b1f305e9c5e5884a62bbcf6e0e92521f2146f Mon Sep 17 00:00:00 2001 From: arifal Date: Tue, 25 Mar 2025 15:54:02 +0700 Subject: [PATCH] fix handle retry button --- .../Controllers/Api/ScrapingController.php | 47 +++++------- .../Resources/ImportDatasourceResource.php | 1 + app/Jobs/RetrySyncronizeJob.php | 76 +++++++++++++++++++ app/Jobs/ScrapingDataJob.php | 15 +++- app/Services/ServicePbgTask.php | 2 - app/Services/ServiceTabPbgTask.php | 34 +++++++-- ..._add_failed_uuid_on_import_datasources.php | 28 +++++++ resources/js/bigdata-resumes/index.js | 2 + .../js/settings/syncronize/syncronize.js | 65 ++++++++++++++++ routes/api.php | 6 +- 10 files changed, 234 insertions(+), 42 deletions(-) create mode 100644 app/Jobs/RetrySyncronizeJob.php create mode 100644 database/migrations/2025_03_25_085656_add_failed_uuid_on_import_datasources.php diff --git a/app/Http/Controllers/Api/ScrapingController.php b/app/Http/Controllers/Api/ScrapingController.php index 148265d..cc800e7 100644 --- a/app/Http/Controllers/Api/ScrapingController.php +++ b/app/Http/Controllers/Api/ScrapingController.php @@ -4,6 +4,7 @@ namespace App\Http\Controllers\Api; use App\Enums\ImportDatasourceStatus; use App\Http\Controllers\Controller; +use App\Jobs\RetrySyncronizeJob; use App\Jobs\ScrapingDataJob; use App\Jobs\SyncronizeSIMBG; use App\Models\ImportDatasource; @@ -37,35 +38,25 @@ class ScrapingController extends Controller return $this->resSuccess(["message" => "Success execute scraping service on background, check status for more"]); } - /** - * Store a newly created resource in storage. - */ - public function store(Request $request) - { - // - } + public function retry_syncjob(string $import_datasource_id){ + try{ - /** - * Display the specified resource. - */ - public function show(string $id) - { - // - } + $import_datasource = ImportDatasource::find($import_datasource_id); + if(!$import_datasource){ + return $this->resError("Invalid import datasource id", null, 404); + } - /** - * Update the specified resource in storage. - */ - public function update(Request $request, string $id) - { - // - } - - /** - * Remove the specified resource from storage. - */ - public function destroy(string $id) - { - // + dispatch(new RetrySyncronizeJob($import_datasource->id)); + return response()->json([ + "success" => true, + "message" => "Retrying scrape job on background, check status for more" + ]); + }catch(\Exception $e){ + return response()->json([ + "success" => false, + "message" => "Failed to retry sync job", + "error" => $e->getMessage() + ]); + } } } diff --git a/app/Http/Resources/ImportDatasourceResource.php b/app/Http/Resources/ImportDatasourceResource.php index bd8c7bc..840e6de 100644 --- a/app/Http/Resources/ImportDatasourceResource.php +++ b/app/Http/Resources/ImportDatasourceResource.php @@ -29,6 +29,7 @@ class ImportDatasourceResource extends JsonResource "finish_time" => $finishTime ? $finishTime->toDateTimeString() : null, "created_at" => $this->created_at->toDateTimeString(), "updated_at" => $this->updated_at->toDateTimeString(), + "failed_uuid" => $this->failed_uuid ]; } } diff --git a/app/Jobs/RetrySyncronizeJob.php b/app/Jobs/RetrySyncronizeJob.php new file mode 100644 index 0000000..c9c5352 --- /dev/null +++ b/app/Jobs/RetrySyncronizeJob.php @@ -0,0 +1,76 @@ +import_datasource_id = $import_datasource_id; + } + + /** + * Execute the job. + */ + public function handle(): void + { + try{ + $service_tab_pbg_task = app(ServiceTabPbgTask::class); + $service_google_sheet = app(ServiceGoogleSheet::class); + + $failed_import = ImportDatasource::find($this->import_datasource_id); + + $failed_import->update([ + 'message' => "Retrying from UUID: ". $failed_import->failed_uuid, + 'status' => ImportDatasourceStatus::Processing->value, + 'start_time' => now() + ]); + + $current_failed_uuid = null; + try{ + $service_tab_pbg_task->run_service($failed_import->failed_uuid); + }catch(\Exception $e){ + $current_failed_uuid = $service_tab_pbg_task->getFailedUUID(); + throw $e; + } + + $data_setting_result = $service_google_sheet->get_big_resume_data(); + + BigdataResume::generateResumeData($failed_import->id, "all", $data_setting_result); + BigdataResume::generateResumeData($failed_import->id, now()->year, $data_setting_result); + + $failed_import->update([ + 'status' => ImportDatasourceStatus::Success->value, + 'message' => "Retry completed successfully from UUID: ". $failed_import->failed_uuid, + 'finish_time' => now(), + 'failed_uuid' => null + ]); + }catch(\Exception $e){ + \Log::error("RetrySyncronizeJob Failed: ". $e->getMessage(), [ + 'exception' => $e, + ]); + if(isset($failed_import)){ + $failed_import->update([ + 'status' => ImportDatasourceStatus::Failed->value, + 'message' => "Retry failed from UUID: ". $failed_import->failed_uuid, + 'finish_time' => now(), + 'failed_uuid' => $current_failed_uuid + ]); + } + + $this->fail($e); + } + } +} diff --git a/app/Jobs/ScrapingDataJob.php b/app/Jobs/ScrapingDataJob.php index 42b338c..7ed9416 100644 --- a/app/Jobs/ScrapingDataJob.php +++ b/app/Jobs/ScrapingDataJob.php @@ -44,13 +44,21 @@ class ScrapingDataJob implements ShouldQueue 'message' => 'Initiating scraping...', 'response_body' => null, 'status' => 'processing', - 'start_time' => now() + 'start_time' => now(), + 'failed_uuid' => null ]); + $failed_uuid = null; + // Run the scraping services $service_google_sheet->run_service(); $service_pbg_task->run_service(); - $service_tab_pbg_task->run_service(); + try{ + $service_tab_pbg_task->run_service(); + }catch(\Exception $e){ + $failed_uuid = $service_tab_pbg_task->getFailedUUID(); + throw $e; + } $data_setting_result = $service_google_sheet->get_big_resume_data(); @@ -72,7 +80,8 @@ class ScrapingDataJob implements ShouldQueue $import_datasource->update([ 'status' => 'failed', 'response_body' => 'Error: ' . $e->getMessage(), - 'finish_time' => now() + 'finish_time' => now(), + 'failed_uuid' => $failed_uuid, ]); } diff --git a/app/Services/ServicePbgTask.php b/app/Services/ServicePbgTask.php index 08e5be5..d96a7e5 100644 --- a/app/Services/ServicePbgTask.php +++ b/app/Services/ServicePbgTask.php @@ -158,8 +158,6 @@ class ServicePbgTask ]); } - Log::info("Page {$currentPage} fetched & saved", ['records' => count($saved_data)]); - $currentPage++; } while ($currentPage <= $totalPage); diff --git a/app/Services/ServiceTabPbgTask.php b/app/Services/ServiceTabPbgTask.php index 79229b7..4421112 100644 --- a/app/Services/ServiceTabPbgTask.php +++ b/app/Services/ServiceTabPbgTask.php @@ -19,6 +19,7 @@ class ServiceTabPbgTask private $service_token; private $user_token; private $user_refresh_token; + protected $current_uuid = null; public function __construct(Client $client, ServiceTokenSIMBG $service_token) { @@ -34,25 +35,42 @@ class ServiceTabPbgTask $this->user_refresh_token = $auth_data['refresh']; } - public function run_service() + public function run_service($retry_uuid = null) { try { - $pbg_tasks = PbgTask::all(); + $pbg_tasks = PbgTask::orderBy('id')->get(); + $start = false; foreach ($pbg_tasks as $pbg_task) { - $this->scraping_task_assignments($pbg_task->uuid); - $this->scraping_task_retributions($pbg_task->uuid); - $this->scraping_task_integrations($pbg_task->uuid); + if($retry_uuid){ + if($pbg_task->uuid === $retry_uuid){ + $start = true; + } - // Process task assignments here if needed - Log::info("Successfully fetched for UUID: {$pbg_task->uuid}"); + if(!$start){ + continue; + } + } + try{ + $this->current_uuid = $pbg_task->uuid; + $this->scraping_task_assignments($pbg_task->uuid); + $this->scraping_task_retributions($pbg_task->uuid); + $this->scraping_task_integrations($pbg_task->uuid); + }catch(\Exception $e){ + Log::error("Failed on UUID: {$this->current_uuid}, Error: " . $e->getMessage()); + throw $e; + } } } catch (\Exception $e) { - Log::error("Failed to scrape task assignments: " . $e->getMessage()); + Log::error("Failed to syncronize: " . $e->getMessage()); throw $e; } } + public function getFailedUUID(){ + return $this->current_uuid; + } + private function scraping_task_assignments($uuid) { $url = "{$this->simbg_host}/api/pbg/v1/list-tim-penilai/{$uuid}/?page=1&size=10"; diff --git a/database/migrations/2025_03_25_085656_add_failed_uuid_on_import_datasources.php b/database/migrations/2025_03_25_085656_add_failed_uuid_on_import_datasources.php new file mode 100644 index 0000000..3d8ebd7 --- /dev/null +++ b/database/migrations/2025_03_25_085656_add_failed_uuid_on_import_datasources.php @@ -0,0 +1,28 @@ +string('failed_uuid')->nullable()->after('status'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('import_datasources', function (Blueprint $table) { + $table->dropColumn('failed_uuid'); + }); + } +}; diff --git a/resources/js/bigdata-resumes/index.js b/resources/js/bigdata-resumes/index.js index 12a2374..356aee2 100644 --- a/resources/js/bigdata-resumes/index.js +++ b/resources/js/bigdata-resumes/index.js @@ -27,6 +27,7 @@ class BigdataResume { this.table = new Grid({ columns: [ { name: "ID" }, + { name: "Year" }, { name: "Jumlah Potensi" }, { name: "Total Potensi" }, { name: "Jumlah Berkas Belum Terverifikasi" }, @@ -79,6 +80,7 @@ class BigdataResume { then: (data) => { return data.data.map((item) => [ item.id, + item.year, item.potention_count, addThousandSeparators(item.potention_sum), item.non_verified_count, diff --git a/resources/js/settings/syncronize/syncronize.js b/resources/js/settings/syncronize/syncronize.js index d86f067..ee99714 100644 --- a/resources/js/settings/syncronize/syncronize.js +++ b/resources/js/settings/syncronize/syncronize.js @@ -28,6 +28,19 @@ class SyncronizeTask { "Duration", "Finished", "Created", + { + name: "Action", + formatter: (cell) => { + if (cell.status === "failed") { + return gridjs.html(` + + `); + } + }, + }, ], search: { server: { @@ -62,10 +75,20 @@ class SyncronizeTask { item.duration, item.finish_time, item.created_at, + item, ]), total: (data) => data.meta.total, }, }).render(tableContainer); + + tableContainer.addEventListener("click", (event) => { + let btn = event.target.closest(".btn-retry"); + if (btn) { + const id = btn.getAttribute("data-id"); + btn.disabled = true; + this.handleRetrySync(id, btn); + } + }); } handleSubmitSync() { const button = document.getElementById("btn-sync-submit"); @@ -117,6 +140,48 @@ class SyncronizeTask { }); } + handleRetrySync(id, btn) { + const apiToken = document + .querySelector('meta[name="api-token"]') + .getAttribute("content"); + + fetch(`${GlobalConfig.apiHost}/api/retry-scraping/${id}`, { + method: "GET", + headers: { + Authorization: `Bearer ${apiToken}`, + "Content-Type": "application/json", + }, + }) + .then(async (response) => { + if (!response.ok) { + throw new Error(`HTTP error! Status: ${response.status}`); + } + return response.json(); + }) + .then((data) => { + console.log("API Response:", data); // Debugging + + // Show success message + const message = + data?.data?.message || + data?.message || + "Synchronization successful!"; + this.toastMessage.innerText = message; + this.toast.show(); + }) + .catch((err) => { + console.error("Fetch error:", err); + + // Show error message + this.toastMessage.innerText = + err.message || + "Failed to synchronize, something went wrong!"; + this.toast.show(); + + // Re-enable button on failure + btn.disabled = false; + }); + } handleSyncClick() { const button = document.getElementById("btn-sync-submit"); const spinner = document.getElementById("spinner"); diff --git a/routes/api.php b/routes/api.php index 196f419..bba0633 100644 --- a/routes/api.php +++ b/routes/api.php @@ -72,7 +72,11 @@ Route::group(['middleware' => 'auth:sanctum'], function (){ }); // scraping - Route::apiResource('/scraping', ScrapingController::class); + Route::controller(ScrapingController::class)->group(function (){ + Route::get('/scraping','index')->name('scraping'); + Route::get('/retry-scraping/{id}','retry_syncjob')->name('retry-scraping'); + }); + // Route::apiResource('/scraping', ScrapingController::class); // reklame Route::apiResource('advertisements', AdvertisementController::class);