Skip to content
LastPing
GUIDE · CELERY · FREE

Monitor Celery beat tasks: task_success and task_failure signals with LastPing

Connect Celery's built-in task_success and task_failure signals to ping LastPing on success and POST to /fail on failure. Filter by sender to scope each signal to a specific task. Alternatively, use a @monitored decorator for self-contained task instrumentation. Absence detection covers a down beat process. Free, no monitor cap.

Your assistant can do this for you

Monitor my Celery tasks with LastPing

On this page
  1. The snippets
  2. What this catches
  3. Questions people ask

The snippets

Create a monitor in the console, set the schedule to match your beat schedule plus a grace window, and copy the ping URL.

Signals: per-task scope with sender=

Connect the signals in your tasks module after defining the task. Filtering by sender ensures only the monitored task triggers the ping:

import requests
from celery import Celery
from celery.signals import task_success, task_failure

app = Celery("tasks", broker="redis://localhost:6379/0")

PING = "https://ping.lastping.dev/<your-monitor-id>"

@app.task(bind=True, max_retries=3)
def nightly_report(self):
    # your task body
    pass

# connect after the task is defined so `sender` resolves
@task_success.connect(sender=nightly_report)
def on_success(sender, result, **kwargs):
    requests.get(PING, timeout=10)

@task_failure.connect(sender=nightly_report)
def on_failure(sender, task_id, exception, traceback, **kwargs):
    msg = f"{type(exception).__name__}: {exception}"
    requests.post(f"{PING}/fail", data=msg[:10_000], timeout=10)

# celery beat schedule (celeryconfig.py or app.conf):
app.conf.beat_schedule = {
    "nightly-report": {
        "task": "tasks.nightly_report",
        "schedule": 86400.0,  # every 24 h in seconds
    },
}

Decorator approach: self-contained per task

A @monitored decorator wraps the task body directly. Cleaner when you want the ping URL co-located with the task definition rather than in separate signal handlers:

import functools, requests
from celery import Celery

app = Celery("tasks", broker="redis://localhost:6379/0")

def monitored(ping_url):
    """Decorator that pings LastPing on task success or failure."""
    def decorator(task_fn):
        @functools.wraps(task_fn)
        def wrapper(*args, **kwargs):
            try:
                result = task_fn(*args, **kwargs)
                requests.get(ping_url, timeout=10)
                return result
            except Exception as exc:
                msg = f"{type(exc).__name__}: {exc}"
                requests.post(f"{ping_url}/fail", data=msg[:10_000], timeout=10)
                raise
        return wrapper
    return decorator

@app.task(bind=True, max_retries=3)
@monitored("https://ping.lastping.dev/<your-monitor-id>")
def nightly_report(self):
    # your task body
    pass

Retry guard: ping /fail only on final failure

By default, task_failure fires on each failed attempt including retries. To ping /fail only when retries are exhausted, check sender.request.retries against sender.max_retries:

@task_failure.connect(sender=nightly_report)
def on_failure(sender, task_id, exception, traceback, **kwargs):
    task = sender
    # only ping /fail on the last retry
    if task.request.retries >= task.max_retries:
        msg = f"{type(exception).__name__}: {exception}"
        requests.post(f"{PING}/fail", data=msg[:10_000], timeout=10)

What celery beat going down looks like

If the beat process stops, no tasks are scheduled. No signal fires, no ping is sent. Absence detection is the correct safety net: the missing ping opens an incident after the grace window regardless of why the task didn't run. See also the Airflow guide for a comparison with DAG-level callbacks, the Python guide for script-level monitoring, and the LastPing MCP server for AI-agent provisioning.

What this catches

The signals report what they can; the silence reports the rest.

  • Task exception: task_failure fires and POSTs the exception class and message to /fail, opening an incident immediately.
  • Task success: task_success fires and GETs the success ping, resetting the absence timer.
  • celery beat is down: no task is scheduled, no signal fires; the missing ping opens the incident after the grace window.
  • Worker process killed: the in-flight task is lost; no success ping arrives; the absence opens the incident.
  • Recovery: the next successful task run fires task_success, closing the incident automatically.

Questions people ask

Front-loaded answers: the most important fact first.

  • How do I monitor a Celery beat task with LastPing?

    Connect the task_success and task_failure signals from celery.signals. In the success handler GET https://ping.lastping.dev/<your-monitor-id>; in the failure handler POST the exception message to /fail. Use the sender argument to filter by specific task class.

  • What is the difference between signals and a decorator approach?

    Signals are global: they fire for every task unless you filter by sender, and they are better when you want a single place to configure monitoring for multiple tasks. A decorator wraps specific tasks and is cleaner when only some tasks need monitoring, or when you want the ping URL co-located with the task and don't want global signal handlers. Both approaches work; signals require less boilerplate for a single-task setup. Choose based on your team's conventions.

  • What if celery beat is down and never schedules the task?

    If celery beat is down, it never enqueues tasks: no task is scheduled, no signal fires, and no ping is sent. Absence-detection monitoring catches this: the missing ping after the schedule+grace window opens an incident even if the beat process never starts, with no signal handler code required.

  • Does task_failure fire on every retry?

    Yes, by default: task_failure fires on every failed attempt, including retries. To ping /fail only on the final failure, check sender.request.retries >= sender.max_retries inside the handler before posting. Alternatively, use after_return on the task and check the state argument for FAILURE.

  • Is Celery task monitoring free?

    Yes. LastPing is free for individuals with no monitor cap. See how it compares to Healthchecks.io and Cronitor.

FREE FOR INDIVIDUALS · FULLY HOSTED

A down celery beat fires no signal. Absence detection does.

Two signal handlers now beat a silent task queue later. First alert wired up in about a minute, and LastPing monitors itself the same way.