From 9881d975fdb48982241eb7808137ed55e08d409d Mon Sep 17 00:00:00 2001 From: Norman Huth Date: Sun, 25 Jan 2026 13:25:29 +0100 Subject: [PATCH] feat(job): optimize menu sync by disabling recipe fetch and adding unique job constraints - Disable missing recipe fetch during menu sync to reduce API calls, with a note to monitor data quality - Update `FetchMenuJob` to sync menus with existing recipes only - Make `FetchRecipeJob` implement `ShouldBeUnique` to prevent duplicate processing - Add unique constraints and timeout to `FetchRecipeJob` for better queue management - Adjust `SyncMenusJob` scheduling to run at 6 AM and 6 PM --- app/Jobs/Menu/FetchMenusJob.php | 49 ++++++++++++++++++------------ app/Jobs/Recipe/FetchRecipeJob.php | 16 +++++++++- routes/console.php | 2 +- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/app/Jobs/Menu/FetchMenusJob.php b/app/Jobs/Menu/FetchMenusJob.php index 1bab4bf1..ee599ec3 100644 --- a/app/Jobs/Menu/FetchMenusJob.php +++ b/app/Jobs/Menu/FetchMenusJob.php @@ -5,7 +5,6 @@ use App\Enums\QueueEnum; use App\Http\Clients\HelloFresh\HelloFreshClient; use App\Jobs\Concerns\HandlesApiFailuresTrait; -use App\Jobs\Recipe\FetchRecipeJob; use App\Models\Country; use App\Models\Menu; use App\Models\Recipe; @@ -14,7 +13,6 @@ use Illuminate\Foundation\Queue\Queueable; use Illuminate\Http\Client\ConnectionException; use Illuminate\Http\Client\RequestException; -use Illuminate\Support\Facades\Bus; use Illuminate\Support\Facades\Context; use Throwable; @@ -131,25 +129,36 @@ protected function importMenu(array $menuData): void return; } + // TODO: Disabled to reduce API calls. Monitor NZ data quality. // Dispatch batch to fetch missing recipes, then sync menu - $jobs = []; - foreach ($missingHellofreshIds as $missingHellofreshId) { - $jobs[] = new FetchRecipeJob( - country: $this->country, - locale: $this->locale, - hellofreshId: $missingHellofreshId, - ); - } - - // Extract primitive values for serializable closure - $menuId = $menu->id; - $countryId = $this->country->id; - $recipeIds = $menuData['recipe_ids']; + // $jobs = []; + // foreach ($missingHellofreshIds as $missingHellofreshId) { + // $jobs[] = new FetchRecipeJob( + // country: $this->country, + // locale: $this->locale, + // hellofreshId: $missingHellofreshId, + // ); + // } + // + // // Extract primitive values for serializable closure + // $menuId = $menu->id; + // $countryId = $this->country->id; + // $recipeIds = $menuData['recipe_ids']; + // + // Bus::batch($jobs) + // ->name(sprintf('Fetch missing recipes for menu %d', $menu->year_week)) + // ->onQueue(QueueEnum::HelloFresh->value) + // ->then(fn () => SyncMenuRecipesJob::dispatch($menuId, $countryId, $recipeIds)) + // ->dispatch(); + + // Sync menu with existing recipes only + $recipeIds = Recipe::where('country_id', $this->country->id) + ->whereIn('hellofresh_id', $menuData['recipe_ids']) + ->pluck('id') + ->toArray(); - Bus::batch($jobs) - ->name(sprintf('Fetch missing recipes for menu %d', $menu->year_week)) - ->onQueue(QueueEnum::HelloFresh->value) - ->then(fn () => SyncMenuRecipesJob::dispatch($menuId, $countryId, $recipeIds)) - ->dispatch(); + if ($recipeIds !== []) { + $menu->recipes()->sync($recipeIds); + } } } diff --git a/app/Jobs/Recipe/FetchRecipeJob.php b/app/Jobs/Recipe/FetchRecipeJob.php index 3599c212..3fdd7dbd 100644 --- a/app/Jobs/Recipe/FetchRecipeJob.php +++ b/app/Jobs/Recipe/FetchRecipeJob.php @@ -7,12 +7,13 @@ use App\Jobs\Concerns\HandlesApiFailuresTrait; use App\Models\Country; use Illuminate\Bus\Batchable; +use Illuminate\Contracts\Queue\ShouldBeUnique; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Queue\Queueable; use Illuminate\Http\Client\ConnectionException; use Illuminate\Http\Client\RequestException; -class FetchRecipeJob implements ShouldQueue +class FetchRecipeJob implements ShouldBeUnique, ShouldQueue { use Batchable; use HandlesApiFailuresTrait; @@ -23,6 +24,19 @@ class FetchRecipeJob implements ShouldQueue */ public int $tries = 3; + /** + * The number of seconds after which the job's unique lock will be released. + */ + public int $uniqueFor = 300; + + /** + * The unique ID of the job. + */ + public function uniqueId(): string + { + return $this->country->id . '-' . $this->hellofreshId; + } + /** * Create a new job instance. */ diff --git a/routes/console.php b/routes/console.php index 8948a246..d8e60614 100644 --- a/routes/console.php +++ b/routes/console.php @@ -29,7 +29,7 @@ ]); Schedule::job(new SyncMenusJob()) - ->twiceDaily(); + ->twiceDailyAt(6, 18); Schedule::job(new CountryResourcesOrchestrationJob()) ->twiceDaily();