Abrova
☰ Docs menu · Cron monitoring

Cron Monitoring

Monitor scheduled jobs and cron tasks with HTTP check-ins. Get notified through Email, webhooks or your other integrations when a job misses its check-in, and see failed runs in the Console. No SDK required.

RESTcurlNode.jsPythonLaravelLast updated: 27 Oct 2026
Cron Monitoring

Monitor your scheduled jobs and cron tasks. Abrova Trace notifies you through your configured integrations when a check-in is missed, and records failed runs. No SDK required — any HTTP client can send check-ins.

Free monitors.

3 cron monitors are free every month. Each extra monitor costs 2,000 Toman a month from your wallet — see Pricing. Check-ins themselves cost nothing.

Server secret needed. Check-ins send your server secret (ab_srv_…) in the X-API-Key header. Run them from your server or CI, from an environment variable — never from an app.

Cron Monitoring#

Monitor scheduled jobs and cron tasks with HTTP check-ins. Missed check-ins notify you through Email, webhooks or your other integrations; failed runs are recorded and shown on the monitor. No SDK required — any HTTP client can send check-ins.

How It Works

  1. Create a Monitor — Define a cron monitor in Abrova Console with a unique slug, a schedule (cron expression or interval), and a grace period.
  2. Send Check-Ins — Your cron job sends an HTTP POST to the check-in API when it runs. No SDK needed — just a simple HTTP call.
  3. Detect Missed Jobs — AbrovaTrace evaluates all monitors every 5 minutes. If a check-in is overdue (past expected interval + grace period), the monitor status changes to "missed".
  4. Get Notified — When a job is missed, notifications are sent to the integrations you selected on the monitor (Email, Webhook, etc.).

Create a Monitor (Dashboard)

  1. In Abrova Console, open your project → Trace → Crons
  2. Click "New monitor"
  3. Fill in the monitor details (see configuration below)
  4. Optionally select notification channels from your active integrations
  5. Click "Create monitor" to save

Managing monitors (create, edit, pause, delete) needs the admin or owner role; every role can see monitors and their check-in history. See Roles & Permissions.

Monitor Configuration

OptionTypeRequiredDescription
NamestringYesDescriptive name (e.g., "Daily Database Backup")
SlugstringYesUnique identifier used in check-in API (e.g., "daily-backup"). Auto-generated from name.
SchedulestringNoCron expression (e.g., "0 2 * * *"). When set, it decides the expected interval.
Expected IntervalnumberYesHow often the job should run, in minutes (default: 60). Used when no cron expression is set.
Grace PeriodnumberYesExtra minutes to wait before marking as missed (default: 5)
EnvironmentstringNoFilter by environment (e.g., production)
Notification Channelsmulti-selectNoSelect from your active integrations

Send Check-Ins from Your Jobs

When your cron job runs, send an HTTP POST to the check-in endpoint. Authenticate with your project's server secret (ab_srv_...) in the X-API-Key header. The monitor will be auto-created if the slug doesn't exist yet.

Which key?

Cron jobs run on your servers, so use the server secret. The app key (ab_live_...) is also accepted while the project setting Server routes require the server secret is off — but it ships inside your apps, so anyone who extracts it could send a fake "ok" check-in. Switch the setting on once your jobs use the server secret. See Server Secret & Server Routes.

Auto-Create Monitors.

If you send a check-in with a slug that doesn't exist, AbrovaTrace will automatically create a monitor with default settings (60-minute interval, 5-minute grace period). You can then customize it in the dashboard.

Check-In API

POSThttps://trace.abrova.ir/api/cron-monitors/check-in
FieldTypeRequiredDescription
monitor_slugstringYesThe unique slug of the monitor
statusstringYes"ok", "error", or "in_progress"
check_in_idstringNoUUID to track multi-step jobs (returned as `id` from in_progress)
duration_msnumberNoHow long the job took in milliseconds
environmentstringNoEnvironment name (e.g., "production")
messagestringNoOptional message or error details

Examples

Simple Check-In (curl)

Send a single "ok" check-in when your job completes successfully:

bash
curl -X POST https://trace.abrova.ir/api/cron-monitors/check-in \
  -H "X-API-Key: ab_srv_your_server_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "monitor_slug": "daily-backup",
    "status": "ok",
    "duration_ms": 4500
  }'

Report an Error (curl)

If the job fails, report it with "error" status:

bash
curl -X POST https://trace.abrova.ir/api/cron-monitors/check-in \
  -H "X-API-Key: ab_srv_your_server_secret" \
  -H "Content-Type: application/json" \
  -d '{
    "monitor_slug": "daily-backup",
    "status": "error",
    "message": "Connection to database timed out"
  }'

Multi-Step Job (curl)

For long-running jobs, start with "in_progress" and complete with "ok" or "error":

bash
# Step 1: Mark job as in_progress (returns a check_in_id)
CHECK_IN_ID=$(curl -s -X POST https://trace.abrova.ir/api/cron-monitors/check-in \
-H "X-API-Key: ab_srv_your_server_secret" \
-H "Content-Type: application/json" \
-d '{"monitor_slug": "nightly-report", "status": "in_progress"}' \
| jq -r '.id')

# ... run your job ...

# Step 2: Mark job as complete
curl -X POST https://trace.abrova.ir/api/cron-monitors/check-in \
-H "X-API-Key: ab_srv_your_server_secret" \
-H "Content-Type: application/json" \
-d "{
  \"monitor_slug\": \"nightly-report\",
  \"status\": \"ok\",
  \"check_in_id\": \"$CHECK_IN_ID\",
  \"duration_ms\": 120000
}"

Node.js

javascript
const axios = require('axios');

const API_KEY = process.env.ABROVA_SERVER_SECRET; // ab_srv_...
const BASE_URL = 'https://trace.abrova.ir/api/cron-monitors/check-in';

async function runDailyBackup() {
  const start = Date.now();

  try {
    // ... your backup logic here ...
    await performBackup();

    // Report success
    await axios.post(BASE_URL, {
      monitor_slug: 'daily-backup',
      status: 'ok',
      duration_ms: Date.now() - start,
    }, { headers: { 'X-API-Key': API_KEY } });

  } catch (error) {
    // Report failure
    await axios.post(BASE_URL, {
      monitor_slug: 'daily-backup',
      status: 'error',
      duration_ms: Date.now() - start,
      message: error.message,
    }, { headers: { 'X-API-Key': API_KEY } });
  }
}

Python

python
import os
import requests
import time

API_KEY = os.environ["ABROVA_SERVER_SECRET"]  # ab_srv_...
BASE_URL = "https://trace.abrova.ir/api/cron-monitors/check-in"

def run_daily_backup():
    start = time.time()
    headers = {"X-API-Key": API_KEY, "Content-Type": "application/json"}

    try:
        # ... your backup logic here ...
        perform_backup()

        # Report success
        requests.post(BASE_URL, json={
            "monitor_slug": "daily-backup",
            "status": "ok",
            "duration_ms": int((time.time() - start) * 1000),
        }, headers=headers)

    except Exception as e:
        # Report failure
        requests.post(BASE_URL, json={
            "monitor_slug": "daily-backup",
            "status": "error",
            "duration_ms": int((time.time() - start) * 1000),
            "message": str(e),
        }, headers=headers)

Laravel (Artisan Command)

php
<?php
// In your scheduled command or Kernel.php

use Illuminate\Support\Facades\Http;

$start = microtime(true);

try {
  // ... your job logic ...
  $this->performCleanup();

  Http::withHeaders([
      'X-API-Key' => env('ABROVATRACE_SERVER_SECRET'),
  ])->post('https://trace.abrova.ir/api/cron-monitors/check-in', [
      'monitor_slug' => 'daily-cleanup',
      'status' => 'ok',
      'duration_ms' => (int)((microtime(true) - $start) * 1000),
  ]);

} catch (\Exception $e) {
  Http::withHeaders([
      'X-API-Key' => env('ABROVATRACE_SERVER_SECRET'),
  ])->post('https://trace.abrova.ir/api/cron-monitors/check-in', [
      'monitor_slug' => 'daily-cleanup',
      'status' => 'error',
      'message' => $e->getMessage(),
  ]);
}

Bash Script

Wrap any cron job with a simple check-in call at the end:

bash
#!/bin/bash
# Add this to the end of your cron job script

API_KEY="$ABROVA_SERVER_SECRET"   # ab_srv_...

# Run your job
/usr/local/bin/my-backup-script.sh

# Report based on exit code
if [ $? -eq 0 ]; then
  curl -s -X POST https://trace.abrova.ir/api/cron-monitors/check-in \
    -H "X-API-Key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"monitor_slug": "my-backup", "status": "ok"}'
else
  curl -s -X POST https://trace.abrova.ir/api/cron-monitors/check-in \
    -H "X-API-Key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"monitor_slug": "my-backup", "status": "error"}'
fi

Monitor Statuses

OK

Last check-in was successful

Error

Last check-in reported an error

Missed

No check-in received within expected time

Disabled

Monitor is paused

API Reference

Your cron job sends check-ins to one public endpoint:

POST /api/cron-monitors/check-in

It takes a project credential in the X-API-Key header: the server secret (recommended), or the app key while the "Server routes require the server secret" setting is off.

Manage monitors in Abrova Console. What a signed-in user may do there depends on their role — see Roles & Permissions.

Best Practices

Use Descriptive Slugs

Choose slugs like "daily-backup", "hourly-sync", or "weekly-report" that clearly identify the job.

Set Appropriate Grace Periods

Give enough buffer for natural job duration variation. A 5-minute grace period works for most jobs; use longer for jobs with variable runtimes.

Report Errors, Not Just Success

Always send a check-in with status "error" when a job fails. This gives you visibility into both missed and failed jobs.

Track Duration

Include duration_ms in your check-ins to spot performance degradation over time.

Use Multi-Step for Long Jobs

For jobs that take minutes or hours, use in_progress + ok/error pattern. This lets you distinguish between "still running" and "missed".

Configure Notifications

Connect at least one integration (Email or a Webhook work without a connection outside Iran) to get alerted when jobs are missed.

Troubleshooting

Monitor shows as missed but job ran?
  • Verify the key is correct and active — check the HTTP status of the check-in; a 401 means it was refused
  • Check that the monitor_slug matches exactly
  • Ensure the check-in request is reaching the server (check network/firewall)
  • Review the expected interval — if your job runs every 24 hours, set the interval to 1440 minutes
  • Check the grace period — increase it if your job has variable start times
Not receiving missed notifications?
  • Verify notification channels are selected on the monitor
  • Check that the selected integrations are active (test them in Trace → Integrations)
  • Missed detection runs every 5 minutes — there may be a short delay
  • Ensure the monitor is enabled (not disabled/toggled off)
Check-in API returns 401?
  • Verify the key starts with ab_srv_ (or ab_live_)
  • If the response says server_credential_required, the project setting Server routes require the server secret is on and the job sent the app key — use the server secret
  • Check that the key is being sent in the X-API-Key header
  • Ensure the API key belongs to an active project with Trace enabled
Cannot create another monitor?
  • 3 monitors are free; more monitors are paid from your organisation's wallet (2,000 Toman per extra monitor a month)
  • Top up the wallet in Abrova Console, or delete a monitor you no longer need
Auto-created monitor has wrong settings?
  • Auto-created monitors use defaults (60 min interval, 5 min grace)
  • Go to Trace → Crons in Abrova Console and edit the monitor
  • Alternatively, create the monitor in the dashboard first with your desired settings
Was this page helpful?
Report a problem