Beamfar

Website monitoring for Laravel and PHP apps: schedulers, queues and maintenance mode

A Laravel or custom PHP application fails in the parts a home-page check cannot see: the scheduler that quietly stopped, the queue worker that kept running old code after a deploy, maintenance mode left on after a failed release, a cached configuration that lost its environment. Monitor the page with required text, an API check on a route that proves the application boots, and heartbeats that the scheduler and the queue report to. Beamfar reads any site over HTTP(S) and does not need access to the code.

Beamfar is an independent product. It is not affiliated with, endorsed by, sponsored by or certified by Laravel or PHP or their owners. The names are used only to say which kind of site this page is about, and they belong to their owners.

Heartbeats for the parts that run in the background

The scheduler. Laravel’s documentation says that when you use its scheduler “we only need to add a single cron configuration entry to our server that runs the schedule:run command every minute”:

* * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1

If that one line disappears, because a server was rebuilt or the crontab was overwritten, every scheduled task stops at once and nothing returns an error. The framework can ping a URL itself. Laravel documents pingBefore, thenPing, pingOnSuccess and pingOnFailure, and says a failure means the command “terminated with a non-zero exit code”. Create a scheduled-task check in Beamfar, copy its ping URL, and attach it to the jobs that matter:

Schedule::command('reports:send')
    ->dailyAt('02:00')
    ->pingBefore($pingUrl . '/start')
    ->pingOnSuccess($pingUrl)
    ->pingOnFailure($pingUrl . '/fail');

The /start and /fail calls are optional: Beamfar measures the run time from them and opens an incident at once on a failure ping, and a missed ping after the period plus the grace time also opens one. For a plain “is the scheduler alive” signal, add a task that does nothing but ping every five minutes with thenPing.

Maintenance mode hides the heartbeat. The documentation says scheduled tasks “will not run when the application is in maintenance mode” unless a task calls evenInMaintenanceMode(). A site left in maintenance mode therefore produces both a visible outage and a missed heartbeat. That is correct, but it is two alerts, so know which one you are reading.

The queue. Queue workers are long-lived processes. Laravel Forge’s documentation says to restart them from the deployment script so they pick up new code, with php artisan queue:restart, and warns that the command “requires a cache driver that persists data between requests”; with the array driver it “will fail silently”. On Laravel Forge, Supervisor watches the workers and restarts them if they crash. None of this shows on a page. Laravel’s scheduling documentation includes a queued Heartbeat job dispatched every five minutes; make that job call the ping URL when it runs, and a stopped worker, a full queue or a dead scheduler all end in the same missed ping.

What the outside request tells you

Maintenance mode answers 503. With php artisan down, requests get an HTTP 503. The --retry option sets the Retry-After header, though “browsers generally ignore” it. A planned release that takes the app down for a few seconds will show in the evidence as a short 503, which the two-region rule treats like any other failure. Keep releases short, and say so in the incident communication when they are not. The classic outage is the other one: php artisan down was run and php artisan up never was.

A cached configuration loses its environment. After config:cache, Laravel does not load the .env file, so the env function “will only return external, system level environment variables”. A deploy that caches configuration on a server that does not have those variables can fail every request that needs them. The page check shows the status and timing in the incident.

Debug mode in production. The documentation says APP_DEBUG should always be false in production, because with true in production “you risk exposing sensitive configuration values” to users. An outside check that requires text cannot prove a negative, so this belongs in the deploy checklist, not the monitor.

The checks that matter most

CheckWhat it catches hereHow to set it up in Beamfar
Page with required textA 500 or 503 page, a blank page, a maintenance pageThe page check; require a phrase from the layout that always prints
A route that boots the frameworkThe application failing while a cached page answersAn API check on a lightweight route you add, status 200 and a response-time limit
Scheduler heartbeatThe cron entry removed or the scheduler failingA scheduled-task check and thenPing on a five-minute task
Job heartbeatA task that fails or runs too longpingBefore, pingOnSuccess and pingOnFailure on the task
Queue heartbeatA worker that is stopped or running old codeA queued job that pings when it runs
Certificate, domain, DNSExpiry and records changedAutomatic on every site

Set it up

  1. Add the site’s host name in the portfolio. The page, certificate and DNS checks start at once.
  2. Require a phrase from the layout that every page prints, so a blank page or an error view fails the page check.
  3. Add a small route to the application, such as a health route that touches the database, and an API check for it: status 200 and a response-time limit.
  4. Add a scheduled-task check for the scheduler with a period of five minutes and a short grace time, and attach thenPing with its ping URL to a five-minute task.
  5. Add the job-level pings to reports, backups and imports, and a second scheduled-task check for the queue that a queued job answers.
  6. Send alerts to a person who can redeploy, and agree beforehand what a missed heartbeat during planned maintenance means.

What an outside check cannot see

It cannot see exceptions in the logs, failed jobs that the queue retried silently, a slow query or a worker leaking memory. It does not know your routes unless you give it one. Put an error tracker and the framework’s own logging next to the monitor, and use the monitor for what they cannot do: tell you from outside that the whole thing is gone, and that a background task never reported in.

How Beamfar helps

Beamfar is not a Laravel package and has no agent to install. It calls a site down only when two regions agree, runs API checks with assertions on the status, headers, JSON values and response time, and receives heartbeat pings with a start and a fail signal. An incident keeps the status code, redirects, certificate and DNS answer. It has been tried on test pages only and has no customers yet.

Questions

How do I monitor the Laravel scheduler?

Add a scheduled-task check, then attach its ping URL to a task with thenPing, or to important jobs with pingBefore, pingOnSuccess and pingOnFailure. A missed ping opens an incident.

Why is my Laravel site returning 503?

The application is probably in maintenance mode, which Laravel answers with an HTTP 503. Run php artisan up if the release is finished.

Does a page check catch a stopped queue worker?

No. The pages keep answering. Use a queued job that pings a heartbeat URL, and restart workers from the deploy script.

Does this work for PHP apps that are not Laravel?

Yes. Any app reachable over HTTP(S) gets the page, API and certificate checks, and any cron job can call a ping URL with curl.

Sources

Read on . Standards and vendor pages change; confirm the current text before you rely on it.

Terms used in this guide

  • Cron jobA cron job is a task scheduled to run at set times on a server. Why it fails silently, how WP-Cron differs from system cron and how to monitor it.
  • Heartbeat monitoringHeartbeat monitoring waits for a scheduled job to report in and alerts when the signal is missing. How the period and grace time work and what it is good for.
  • HTTP status codeAn HTTP status code is the three-digit number that opens a server response and says how the request went: 2xx success, 3xx redirect, 4xx client error, 5xx server error.
  • IncidentAn incident is a period in which a monitored site is confirmed to be failing, from first confirmation to recovery. What an incident record should hold.

Know first. Know why. Tell your client before they call.

Paste your client list. Both regions start checking.

No card for the trial.