Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
82.19% covered (warning)
82.19%
60 / 73
0.00% covered (danger)
0.00%
0 / 1
CRAP
0.00% covered (danger)
0.00%
0 / 1
SystemHealthService
82.19% covered (warning)
82.19%
60 / 73
0.00% covered (danger)
0.00%
0 / 1
11.68
0.00% covered (danger)
0.00%
0 / 1
 collect
82.19% covered (warning)
82.19%
60 / 73
0.00% covered (danger)
0.00%
0 / 1
11.68
1<?php
2
3namespace App\Http\Services\Admin\SystemDashboard;
4
5use Illuminate\Support\Facades\DB;
6use Illuminate\Support\Facades\Http;
7use Illuminate\Support\Facades\Redis;
8
9class SystemHealthService
10{
11    /**
12     * Collect live health status for all subsystems.
13     *
14     * HTTP status is always 200 for the admin endpoint — the UI surfaces
15     * per-component status. Field names are preserved snake_case to keep
16     * the public /health endpoint byte-identical when delegated.
17     *
18     * @return array<string, array<string, mixed>>
19     */
20    public function collect(): array
21    {
22        $statuses = [
23            'application' => [
24                'status' => 'OK',
25                'message' => 'Application is running smoothly',
26            ],
27            'mongodb' => [
28                'status' => 'OK',
29                'message' => 'MongoDB connection established',
30            ],
31            'redis' => [
32                'status' => 'OK',
33                'message' => 'Redis connection established',
34            ],
35            'queue' => [
36                'status' => 'OK',
37                'count' => 0,
38                'message' => 'Queue is operational',
39            ],
40            'environment' => [
41                'status' => 'OK',
42                'message' => config('app.env', 'unknown'),
43            ],
44        ];
45
46        try {
47            /** @var \MongoDB\Laravel\Connection $mongoConnection */
48            $mongoConnection = DB::connection('mongodb');
49            $mongoConnection->command(['ping' => 1]);
50        } catch (\Exception $e) {
51            $statuses['mongodb']['status'] = 'Fail';
52            $statuses['mongodb']['message'] = 'MongoDB connection failed';
53            $statuses['mongodb']['error'] = $e->getMessage();
54            $statuses['application']['status'] = 'Partial Fail';
55            $statuses['application']['message'] = 'One or more services failed';
56        }
57
58        try {
59            Redis::ping();
60            $statuses['queue']['count'] = (Redis::llen('queues:default') ?? 0) + (Redis::llen('queues:high') ?? 0);
61        } catch (\Exception $e) {
62            $statuses['queue']['status'] = 'Fail';
63            $statuses['queue']['message'] = 'Redis connection failed';
64            $statuses['redis']['status'] = 'Fail';
65            $statuses['redis']['message'] = 'Redis connection failed';
66            $statuses['redis']['error'] = $e->getMessage();
67            $statuses['application']['status'] = 'Partial Fail';
68            $statuses['application']['message'] = 'One or more services failed';
69        }
70
71        if ($statuses['queue']['count'] < 100) {
72            $statuses['queue']['status'] = 'OK';
73        } else {
74            $statuses['queue']['status'] = 'Fail';
75            $statuses['queue']['message'] = "Queue depth exceeds threshold ({$statuses['queue']['count']} pending jobs)";
76            $statuses['application']['status'] = 'Partial Fail';
77            $statuses['application']['message'] = 'One or more services failed';
78        }
79
80        $statuses['node_sidecar'] = [
81            'status' => 'OK',
82            'message' => 'Node sidecar is running!',
83        ];
84
85        try {
86            $sidecarUrl = config('services.node_sidecar.url', 'http://127.0.0.1:3000');
87            $response = Http::timeout(2)->get($sidecarUrl.'/api/health');
88
89            if ($response->successful()) {
90                $statuses['node_sidecar']['message'] = $response->json('status', 'healthy');
91            } else {
92                $statuses['node_sidecar']['status'] = 'Fail';
93                $statuses['node_sidecar']['message'] = 'Node sidecar returned non-OK response';
94                $statuses['application']['status'] = 'Partial Fail';
95                $statuses['application']['message'] = 'One or more services failed';
96            }
97        } catch (\Exception $e) {
98            $statuses['node_sidecar']['status'] = 'Fail';
99            $statuses['node_sidecar']['message'] = 'Node sidecar is not responding';
100            $statuses['application']['status'] = 'Partial Fail';
101            $statuses['application']['message'] = 'One or more services failed';
102        }
103
104        if ($statuses['mongodb']['status'] === 'Fail' && $statuses['redis']['status'] === 'Fail') {
105            $statuses['application']['status'] = 'Fail';
106            $statuses['application']['message'] = 'Both MongoDB and Redis connections failed';
107        } elseif (
108            $statuses['mongodb']['status'] === 'OK' &&
109            $statuses['redis']['status'] === 'OK' &&
110            $statuses['node_sidecar']['status'] === 'OK'
111        ) {
112            $statuses['application']['status'] = 'OK';
113            $statuses['application']['message'] = 'All systems operational';
114        }
115
116        return $statuses;
117    }
118}