Search by

honchoagency / craft-deadman

mijewe

Package info

github.com/honchoagency/craft-deadman

Documentation

Type:craft-plugin

pkg:composer/honchoagency/craft-deadman

Statistics

Installs: 23

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

0.2.0 2026-09-04 10:04 UTC

This package is auto-updated.

Last update: 2026-09-04 10:13:02 UTC


README

Banner

Deadman

A general-purpose dead-man's-switch monitoring plugin for Craft CMS 5.

Requires Craft CMS ^5.9 and PHP ^8.2.

TL;DR

Deadman runs configured health checks on a schedule and pings an external monitor (StatusCake Push, Healthchecks.io, etc.) when a check passes. If a check doesn't pass, the absence of an alert is what the external service reacts to.

The problem

There are many aspects of a site that can break unnoticed. Maybe your queue is stuck due to a crashed daemon; maybe your contact form hasn't had a submission for a week; maybe a regular FeedMe import has stopped running. By setting up Deadman alerts, you can be alerted as soon as these things fail.

Deadman evaluates whatever checks you define and pushes to an external monitor only when a check passes. If a check starts failing, or Deadman itself stops running, the push simply stops arriving and your monitor's own silence-based alerting takes it from there.

Quick start

  1. Install the plugin
  2. Copy the config file and define your checks in config/deadman.php.
  3. Schedule php craft deadman/run via cron
  4. 🎉

From there, each due check runs on schedule, pings its configured URL on pass, and stays quiet on failure.

Installation

1. Install Deadman

You can install Deadman by searching for "Deadman" in the Craft Plugin Store, or install manually using composer.

composer require honchoagency/craft-deadman

2. Configure the plugin

Copy the default config file into your project:

cp vendor/honchoagency/craft-deadman/src/config.php config/deadman.php

Then edit config/deadman.php to define your checks.

Included checks

FailedJobCountCheck

Fails once too many jobs in Craft's own queue have failed. Takes a threshold (int) param: the number of failed jobs tolerated before the check fails.

OldestPendingJobCheck

Fails if the oldest job still waiting in the queue has been sitting there longer than expected. This is the check that catches a dead or stuck queue daemon. Takes a thresholdMinutes (int) param: how long a pending job is allowed to wait before it's considered stuck.

RecentFormieSubmissionCheck

Fails if a Formie form hasn't received a real (non-spam) submission within a window. This is useful for catching a form that's silently broken. Takes a thresholdHours (int, defaults to 24) param and an optional formHandle to scope the check to one form; omit it to check submissions across all forms.

Bring Your Own Checks

You can build your own custom checks by implementing CheckInterface and returning a CheckResult from the check's run() method.

For example, if you wanted to check if a regular import has been run:

<?php

namespace modules\mysite\deadman;

use honchoagency\deadman\checks\CheckInterface;
use honchoagency\deadman\models\CheckResult;

class ImportFreshnessCheck implements CheckInterface
{
    public function run(array $params): CheckResult
    {
        $isFresh = /* your own logic here, using $params */ true;

        return $isFresh
            ? CheckResult::pass('Import is up to date.')
            : CheckResult::fail('Import looks stale.');
    }
}

Then point a config/deadman.php entry's type at it, same as a prefab check:

'importFreshness' => [
    'type' => \modules\mysite\deadman\ImportFreshnessCheck::class,
    'params' => ['maxAgeHours' => 26],
    'successUrl' => getenv('DEADMAN_IMPORT_URL'),
],

3. Set up the cron job

# Run all due, enabled checks (eg every 5 minutes)
*/5 * * * * php craft deadman/run

Configuration

Everything is defined per check entry in config/deadman.php:

Key Type Notes
displayName ?string A human-readable label shown in the CP (settings, the utility) in place of the handle. Falls back to the handle if omitted.
enabled bool Defaults to true. Disabled checks are skipped.
type class-string A class implementing CheckInterface. Mutually exclusive with checkFn.
params array Passed to a class-based check's run().
checkFn Closure(): CheckResult An inline check. Mutually exclusive with type.
interval int Minimum seconds between runs. Defaults to 300.
successUrl ?string Pinged (GET) when the check passes.
onFalse ?Closure(CheckResult): void Called when the check returns a failing result.
onException ?Closure(\Throwable): void Called when the check itself throws.

Exactly one of type or checkFn must be set per entry, or an InvalidConfigException is thrown.

Usage

# Run all due, enabled checks
php craft deadman/run

# Run one check by handle
php craft deadman/run --handle=failedJobs

# Run every enabled check regardless of interval / last-run state
php craft deadman/run --force

Disabling Deadman on an environment

Set DEADMAN_ENABLED=false (also accepts 0/no/off) in an environment's .env to stop craft deadman/run from evaluating or pushing anything there — useful for staging/QA copies of a production database+config, so they don't start alerting on behalf of an environment nobody's monitoring. Defaults to enabled; omit the var entirely on environments that should run normally.

Testing your setup

craft deadman/test/seed-jobs pushes a batch of jobs onto Craft's queue that always fail when run — useful for confirming FailedJobCountCheck and OldestPendingJobCheck actually catch problems before you rely on them.

# Push 5 jobs (default)
php craft deadman/test/seed-jobs

# Push 20, each delayed 30s before becoming eligible for pickup
php craft deadman/test/seed-jobs --count=20 --delay=30

Leave them unprocessed (queue daemon stopped, or pushed with --delay) to exercise OldestPendingJobCheck; run php craft queue/run to let them fail and exercise FailedJobCountCheck.

State and history

The plugin keeps a deadman_checkstates table with a single, overwritten row per check handle (last run time and most recent outcome). It exists only to answer "is this check due yet?" — it is not a history log. For historical debugging, log from the onFalse / onException closures and read Craft's log files.

Credits

Built by honcho.agency