michalkortas/pingme-now
A Laravel package for firing off quick notifications, or pings, from your application. It gives you a simple way to alert yourself or your team when events occur, helping you stay informed without wiring up extra tooling or boilerplate.
This package handles queue heartbeat tracking and age reporting — i.e. recording that a worker is alive and exposing how long ago that last heartbeat was. The v0.3.2 patch is a targeted compatibility fix for Carbon 3, which is the default in Laravel 11+, so most modern apps will be running the code path that was just fixed.
Minimal steps:
php artisan vendor:publish) and confirm the heartbeat store/connection it defaults to — this is the first thing to check, because an in-memory or cache-backed store behaves very differently from a database-backed one across worker restarts.Heartbeat on the worker loop. The common integration is a periodic touch from inside the queue worker — either an event listener on job processing, a middleware, or a scheduled ping. Keep the write cheap and idempotent: you want "last seen at" semantics, not an append-only log, unless you specifically need history for debugging.
Age as the health signal. The useful primitive is not the heartbeat timestamp but the derived age. Read the age, compare it against a threshold, and expose that as a boolean health check. Wire it into:
/health or /up endpoint for your load balancer,n × your expected heartbeat interval,Threshold sizing. Set the alert threshold to roughly three missed heartbeat intervals. Tying it to exactly one interval produces flapping alerts on normal GC pauses and deploy restarts.
Timezone discipline. Store heartbeats in UTC and compute the age in UTC. Mixing config('app.timezone') into the comparison is the most common source of "age is off by hours" reports, and it is unrelated to the Carbon 3 fix.
Testing your integration. Use Carbon::setTestNow() to freeze time, write a heartbeat, advance time, and assert the reported age. Because this patch shipped without tests, your own suite is the only regression net you have for the age calculation.
Carbon 2 vs Carbon 3 diff semantics (the v0.3.2 fix). Carbon 3 changed diffIn* methods to return signed values by default, whereas Carbon 2 returned absolute values. Code that computed now()->diffInSeconds($lastHeartbeat) silently started returning negative numbers once a heartbeat was in the past. v0.3.2 corrects this by explicitly requesting an absolute difference. Implications:
$age > $threshold will never fire on a negative number, so your alerting may have been silently dead).diffIn* call you wrote against this package's timestamps has the same trap.No tests in this release. Tests were skipped at the maintainer's request, so there is no published regression coverage for the Carbon 3 path. Treat v0.3.2 as a patch to verify rather than trust: pin the version, run your own frozen-time assertion on the age output, and only then roll it out. This is a one-line verification, not a reason to avoid the upgrade.
Stale heartbeats after deploys. A long-running worker that is killed mid-job leaves a heartbeat that ages out naturally — which is correct — but a worker that restarts without writing an initial heartbeat creates a window where age is computed from an old timestamp. Write a heartbeat at boot, not only on the first job.
Clock skew across hosts. If heartbeats are written by one host and age is computed on another, drift shows up as small negative or inflated ages. The absolute-difference fix masks the sign but not the magnitude; keep NTP in place or compute age on the same host that reads it.
Extension points. The two seams worth knowing are the heartbeat store (swap for Redis or the database depending on your worker topology) and the threshold configuration. If the package's built-in age reporting does not fit your alerting model, the derived age is a single value — pull it into your own health check rather than forking.
How can I help you explore Laravel packages today?