Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SyncG3WRegion
0.00% covered (danger)
0.00%
0 / 26
0.00% covered (danger)
0.00%
0 / 4
30
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 middleware
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 handle
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
6
 failed
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2
3namespace App\Jobs;
4
5use App\Services\PresupuestosService;
6use Illuminate\Bus\Queueable;
7use Illuminate\Contracts\Queue\ShouldQueue;
8use Illuminate\Foundation\Bus\Dispatchable;
9use Illuminate\Queue\InteractsWithQueue;
10use Illuminate\Queue\Middleware\RateLimited;
11use Illuminate\Queue\Middleware\WithoutOverlapping;
12use Illuminate\Queue\SerializesModels;
13use Illuminate\Support\Facades\Log;
14
15/**
16 * FIRE-1151: per-region G3W budget sync, dispatched in parallel from
17 * QuotationsSync::handle(). Pre-fix the command ran 5 regions serially
18 * for 6+ minutes wall-time; this job lets them run concurrently capped
19 * by the 'g3w' rate-limiter.
20 *
21 * Depends on FIRE-1147 (queue infrastructure) — when QUEUE_CONNECTION
22 * is 'sync' this job runs inline and there is no parallelism gain.
23 */
24class SyncG3WRegion implements ShouldQueue
25{
26    use Dispatchable;
27    use InteractsWithQueue;
28    use Queueable;
29    use SerializesModels;
30
31    public int $tries = 3;
32
33    /** @var array<int,int> backoff between retries in seconds */
34    public array $backoff = [10, 30, 60];
35
36    /** Job is killed if it runs longer than this. */
37    public int $timeout = 600;
38
39    public function __construct(
40        public readonly string $date,
41        public readonly string $name,
42        public readonly string $region,
43    ) {}
44
45    /**
46     * Queue middleware: cap G3W call rate across all parallel jobs +
47     * prevent the same region running twice simultaneously.
48     */
49    public function middleware(): array
50    {
51        return [
52            (new WithoutOverlapping("g3w:region:{$this->region}"))
53                ->expireAfter(900)   // auto-release after 15 min if the job dies
54                ->dontRelease(),     // if locked, drop the duplicate rather than retry
55            new RateLimited('g3w'),
56        ];
57    }
58
59    public function handle(PresupuestosService $service): void
60    {
61        $start = microtime(true);
62
63        try {
64            $service->syncByDate($this->date, $this->name, $this->region);
65            $status = 'ok';
66        } catch (\Throwable $e) {
67            $status = 'failed';
68            Log::channel('g3w')->error("SyncG3WRegion failed: {$this->region} — {$e->getMessage()}");
69            throw $e;   // let the queue retry per $tries / $backoff
70        } finally {
71            Log::channel('g3w')->info('SyncG3WRegion finished', [
72                'region' => $this->region,
73                'date' => $this->date,
74                'wall_ms' => (int) round((microtime(true) - $start) * 1000),
75                'status' => $status ?? 'unknown',
76                'attempt' => $this->attempts(),
77            ]);
78        }
79    }
80
81    public function failed(\Throwable $e): void
82    {
83        Log::channel('g3w')->error('SyncG3WRegion exhausted retries', [
84            'region' => $this->region,
85            'date' => $this->date,
86            'error' => $e->getMessage(),
87        ]);
88    }
89}