local()->toDateString(); foreach ($health->components() as $component) { $state = $component['state']; // One statement, so two schedulers racing on the same minute cannot // read-modify-write over each other. The counters are increments, // never assignments — a sample is a thing that happened, and a // later run must not be able to undo it. DB::table('status_days')->upsert( [[ 'day' => $day, 'component' => $component['key'], 'samples' => 1, 'operational' => $state === 'operational' ? 1 : 0, 'degraded' => $state === 'degraded' ? 1 : 0, 'down' => $state === 'down' ? 1 : 0, 'unknown' => $state === 'unknown' ? 1 : 0, 'created_at' => now(), 'updated_at' => now(), ]], ['day', 'component'], [ 'samples' => DB::raw('samples + 1'), 'operational' => DB::raw('operational + '.($state === 'operational' ? 1 : 0)), 'degraded' => DB::raw('degraded + '.($state === 'degraded' ? 1 : 0)), 'down' => DB::raw('down + '.($state === 'down' ? 1 : 0)), 'unknown' => DB::raw('unknown + '.($state === 'unknown' ? 1 : 0)), 'updated_at' => DB::raw('CURRENT_TIMESTAMP'), ], ); } // Beyond the window the page can draw, the rows are only weight. Kept a // fortnight longer than the ninety days shown so a change of window // does not immediately hit an empty table. StatusDay::query() ->where('day', '<', Carbon::now()->local()->subDays(104)->toDateString()) ->delete(); return self::SUCCESS; } }