Skip to content

feat: add requirements:health task for service health checks#20

Merged
konradmichalik merged 7 commits intomainfrom
feature/requirements-health
Feb 19, 2026
Merged

feat: add requirements:health task for service health checks#20
konradmichalik merged 7 commits intomainfrom
feature/requirements-health

Conversation

@konradmichalik
Copy link
Contributor

@konradmichalik konradmichalik commented Feb 19, 2026

Summary

  • Add new requirements:health Deployer task that checks the availability of critical services on the target host
  • Provides quick feedback during deployments to detect infrastructure issues early

Changes

  • deployer/requirements/task/health.php - New task checking four service categories:
    1. PHP-FPM - Detects version-specific FPM service via systemctl/pgrep
    2. Webserver - Checks for nginx, apache2, or httpd
    3. Database server - Pings via mysqladmin/mariadb-admin with process fallback
    4. HTTP response - Verifies the configured URL returns a non-5xx status
  • deployer/requirements/functions.php - Add isServiceActive() helper (systemctl with pgrep fallback)
  • deployer/requirements/config/set.php - Add requirements_check_health_enabled and requirements_health_url config options
  • autoload.php - Register the new task file

Summary by CodeRabbit

  • New Features

    • Added a new health-check task (requirements:health) to verify PHP-FPM, webserver, database server and HTTP endpoint status.
  • Chores

    • Added configuration options to enable/disable health checks and to set the health-check URL.
  • Documentation

    • Updated Requirements guide with health-check usage, examples and expected outcomes.

@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

Caution

Review failed

The pull request is closed.

📝 Walkthrough

Walkthrough

Adds a new health-check task to the deployer requirements module, plus configuration keys and a helper to detect active services; the task checks PHP-FPM, webserver, database server, and an HTTP endpoint and renders a requirements table.

Changes

Cohort / File(s) Summary
Bootstrap
autoload.php
Registered the new health check task in the autoload sequence by requiring the health task file.
Configuration
deployer/requirements/config/set.php
Added requirements_check_health_enabled (default true) and requirements_health_url (default URL) configuration keys.
Utilities
deployer/requirements/functions.php
Added isServiceActive(string ...$names): ?string helper that prefers systemctl is-active and falls back to pgrep to detect running services.
Health Check Task
deployer/requirements/task/health.php
New task requirements:health that, when enabled, checks PHP‑FPM (version-aware), webserver (nginx/apache2/httpd), database server (via admin tool ping with process fallback), and HTTP response via curl; records statuses and renders the requirements table.
Documentation
docs/REQUIREMENTS.md
Documented the health check task, detection methods, configuration options, examples, and expected outcomes.

Sequence Diagram

sequenceDiagram
    participant Task as Health Check Task
    participant Sys as System (systemctl/pgrep)
    participant DBAdmin as DB Admin Tool (mysqladmin/mariadb-admin)
    participant Curl as HTTP Client (curl)
    participant Table as Requirements Table

    Task->>Sys: detect phpX.Y-fpm (systemctl is-active / pgrep)
    Sys-->>Task: php-fpm status/result
    Task->>Sys: detect webserver (nginx/apache2/httpd)
    Sys-->>Task: webserver status/result
    Task->>DBAdmin: ping DB admin tool (if available)
    DBAdmin-->>Task: ping success/fail
    Task->>Sys: fallback check mysqld/mariadbd process (pgrep)
    Sys-->>Task: db process status/result
    Task->>Curl: request requirements_health_url
    Curl-->>Task: http response / error
    Task->>Table: render collected results
    Table-->>Task: display health status
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰
Hops and checks in tidy rows,
PHP, web, and DB all go,
A curl for the final cue,
I nibble bugs and count the two—
Health is green, the meadow glows.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: add requirements:health task for service health checks' clearly and specifically describes the main change: adding a new health-check task to the deployer requirements. It is concise, directly related to the primary purpose of the changeset, and uses standard conventional commit format.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/requirements-health

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@konradmichalik
Copy link
Contributor Author

konradmichalik commented Feb 19, 2026

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
deployer/requirements/config/set.php (1)

111-113: requirements_check_health_enabled is misplaced relative to the other requirements_check_*_enabled flags

All other per-category enable flags are grouped together at lines 11–20. requirements_check_health_enabled is placed far down the file next to the URL config. Keeping it with the other flags improves discoverability and consistency.

♻️ Proposed fix
 set('requirements_check_database_grants_enabled', true);
+set('requirements_check_health_enabled', true);
 
 // Locales
 // Health check
-set('requirements_check_health_enabled', true);
 set('requirements_health_url', 'http://localhost');
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deployer/requirements/config/set.php` around lines 111 - 113, Move the
set('requirements_check_health_enabled', true) so it sits with the other
per-category enable flags (the group of set('requirements_check_*_enabled')
entries) instead of next to the URL; leave set('requirements_health_url',
'http://localhost') in its current location. Edit the file to relocate the
requirements_check_health_enabled flag into the enable-flags block (alongside
the other requirements_check_*_enabled settings) to improve consistency and
discoverability, ensuring no other keys or order-dependent logic are changed.
deployer/requirements/task/health.php (1)

71-72: HTTP 4xx responses classified as REQUIREMENT_OK — consider adding a clarifying comment

$httpCode >= 200 && $httpCode < 500 marks all 2xx, 3xx, and 4xx responses as healthy. For a "is the server responding at all" check this is reasonable, but a 404 from the configured URL could mask a misconfigured requirements_health_url. A short inline comment documenting the intent would prevent future confusion.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deployer/requirements/task/health.php` around lines 71 - 72, The HTTP status
check in health.php currently treats any $httpCode >= 200 && $httpCode < 500
(2xx–4xx) as REQUIREMENT_OK which can hide misconfigured
requirements_health_url; update the code around the conditional that calls
addRequirementRow('HTTP response', REQUIREMENT_OK, "HTTP $httpCode from $url")
to include a short inline comment explaining the intent (e.g., that 4xx
responses mean the server responded but the resource may be missing and
therefore are considered "server reachable" for this health check) so future
maintainers understand why 4xx are acceptable here; mention the relevant symbols
$httpCode, $url, addRequirementRow and REQUIREMENT_OK in the comment.
deployer/requirements/functions.php (1)

362-374: pgrep is never tried when systemctl is in PATH but non-functional (e.g., containers)

The elseif means pgrep is only used when systemctl is entirely absent. If the target host has the systemctl binary in PATH (e.g., an Ubuntu/Debian image or VM where systemd isn't PID 1), $hasSystemctl is true, systemctl is-active returns empty / "failed" output (stderr is discarded), $status !== 'active', and the function iterates through all names and returns null — pgrep is never attempted. The docblock says "pgrep fallback" but the implementation provides it only at the system level, not the per-service level.

Consider falling through to pgrep whenever systemctl doesn't confirm the service is active:

♻️ Proposed fix
         if ($hasSystemctl) {
             $status = trim(run("systemctl is-active $name 2>/dev/null || true"));
 
             if ($status === 'active') {
                 return $name;
             }
-        } elseif (test("pgrep -x $name > /dev/null 2>&1")) {
-            return $name;
-        }
+        }
+
+        // Fallback: pgrep when systemctl is absent, non-functional, or the
+        // service isn't registered as a systemd unit but the process is running.
+        if (!$hasSystemctl || $status === 'unknown' || $status === '') {
+            if (test("pgrep -x $name > /dev/null 2>&1")) {
+                return $name;
+            }
+        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deployer/requirements/functions.php` around lines 362 - 374, The code uses
elseif so pgrep is only attempted when systemctl is completely absent; change
the flow to try pgrep per-service whenever systemctl exists but does not report
the service as active. Concretely, in the loop that sets $status via
run("systemctl is-active $name...") (and uses $hasSystemctl), replace the elseif
branch with a separate if that runs test("pgrep -x $name > /dev/null 2>&1") when
either $hasSystemctl is false or when $hasSystemctl is true but $status !==
'active' (i.e., fall through to pgrep if systemctl didn't confirm active).
Ensure you reference the same variables ($hasSystemctl, $status, $name) and
commands (systemctl is-active, pgrep -x) so the per-service pgrep fallback
executes correctly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@deployer/requirements/task/health.php`:
- Around line 45-51: The DB ping currently always succeeds because the shell
string passed to run() includes "|| true" and redirects stderr with "2>&1";
remove the "|| true" so run("$adminCmd ping --silent 2>/dev/null") will return
non-zero and trigger the RunException catch when the admin tool is missing or
the DB is unreachable, and change the redirect to "2>/dev/null" (not "2>&1")
since output is ignored; update the call using the $adminCmd variable and leave
the catch(RunException) and $dbChecked logic intact so
addRequirementRow('Database server', ...) is only set on a genuine zero exit.
- Around line 17-19: Validate and sanitize the result of run('php -r "echo
PHP_MAJOR_VERSION.\'.\'.PHP_MINOR_VERSION;"') before using it in the service
name: after assigning $phpVersion, strip any non-digit-and-dot characters and
ensure it matches the X.Y pattern (e.g. using a regex like '/^\d+\.\d+$/'), and
if it fails validation fall back to the generic service identifier used by
isServiceActive (e.g. 'php-fpm') so that isServiceActive("php$phpVersion-fpm",
'php-fpm') is only called with a well-formed version string or the safe
fallback; keep references to $phpVersion, run(...) and isServiceActive(...) to
locate the change.

---

Nitpick comments:
In `@deployer/requirements/config/set.php`:
- Around line 111-113: Move the set('requirements_check_health_enabled', true)
so it sits with the other per-category enable flags (the group of
set('requirements_check_*_enabled') entries) instead of next to the URL; leave
set('requirements_health_url', 'http://localhost') in its current location. Edit
the file to relocate the requirements_check_health_enabled flag into the
enable-flags block (alongside the other requirements_check_*_enabled settings)
to improve consistency and discoverability, ensuring no other keys or
order-dependent logic are changed.

In `@deployer/requirements/functions.php`:
- Around line 362-374: The code uses elseif so pgrep is only attempted when
systemctl is completely absent; change the flow to try pgrep per-service
whenever systemctl exists but does not report the service as active. Concretely,
in the loop that sets $status via run("systemctl is-active $name...") (and uses
$hasSystemctl), replace the elseif branch with a separate if that runs
test("pgrep -x $name > /dev/null 2>&1") when either $hasSystemctl is false or
when $hasSystemctl is true but $status !== 'active' (i.e., fall through to pgrep
if systemctl didn't confirm active). Ensure you reference the same variables
($hasSystemctl, $status, $name) and commands (systemctl is-active, pgrep -x) so
the per-service pgrep fallback executes correctly.

In `@deployer/requirements/task/health.php`:
- Around line 71-72: The HTTP status check in health.php currently treats any
$httpCode >= 200 && $httpCode < 500 (2xx–4xx) as REQUIREMENT_OK which can hide
misconfigured requirements_health_url; update the code around the conditional
that calls addRequirementRow('HTTP response', REQUIREMENT_OK, "HTTP $httpCode
from $url") to include a short inline comment explaining the intent (e.g., that
4xx responses mean the server responded but the resource may be missing and
therefore are considered "server reachable" for this health check) so future
maintainers understand why 4xx are acceptable here; mention the relevant symbols
$httpCode, $url, addRequirementRow and REQUIREMENT_OK in the comment.

@konradmichalik
Copy link
Contributor Author

@coderabbitai Addressing the nitpick comments from the review:

set.php — enable flag placement: Fixed. Moved requirements_check_health_enabled to the enable-flags group at the top.

health.php:71-72 — HTTP 4xx comment: Skipped. The check name "HTTP response" (not "HTTP success") makes the intent clear — this is a reachability check, not a status validation.

functions.php — pgrep fallback in containers: Fixed. Changed elseif to always fall through to pgrep when systemctl doesn't confirm active, covering container environments where systemctl binary exists but systemd isn't PID 1.

@coderabbitai
Copy link

coderabbitai bot commented Feb 19, 2026

Tip

For best results, initiate chat on the files or code changes.

@konradmichalik Thank you for the detailed update on the review feedback!

Fixes confirmed:

  • set.php: Great—moving the enable flag to the top with the other enable flags improves consistency.
  • functions.php: Perfect—the fallthrough to pgrep now properly handles containers where systemctl exists but systemd isn't running.

Skipped item:

  • health.php:71-72: Your reasoning makes sense—"HTTP response" as the check name clearly indicates this is about reachability, not status validation. Accepted.

The changes look good!

🐰✨

  (\_/)
  (•‿•)
  />📋 Fixes noted!

@konradmichalik konradmichalik merged commit d0eec55 into main Feb 19, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments