Automate Daily Sales and Metrics Reports

A daily sales and metrics report keeps your team informed without manual effort, but only if the job actually runs and succeeds every morning. Scheduling it with cron alone gives you no visibility into failures or missed runs. Pairing the scheduled script with a CronJobPro heartbeat monitor closes that gap, alerting you the moment a report fails to arrive.

Schedule

0 7 * * *

Every day at 7:00 AM server time

Setup

  1. 1

    Expose a report endpoint or script

    Make sure your application has either an internal HTTP endpoint (e.g. GET /api/reports/daily-sales) protected by a secret token, or a standalone script (e.g. generate_daily_report.sh or report.py) that queries your database and sends or saves the report. The script should exit with code 0 on success and non-zero on failure.

  2. 2

    Create a CronJobPro heartbeat monitor

    In CronJobPro, go to Monitors, create a new Heartbeat monitor, set the expected period to 24 hours, and add a grace period of 30 minutes. Copy the unique ping URL you receive (https://cronjobpro.com/ping/<token>). Configure alert channels such as email, Slack, or PagerDuty so you are notified if the ping does not arrive on time.

  3. 3

    Add the script to your server cron

    On your server, run crontab -e as the appropriate user and add the schedule line pointing to your wrapper script. Make sure the script is executable (chmod +x) and uses absolute paths for all commands and files, since cron runs with a minimal environment and a different working directory than your shell.

  4. 4

    Test a manual run

    Before relying on the schedule, run the script manually from the terminal and confirm it completes without errors, the report is delivered or saved as expected, and the heartbeat ping URL receives a successful HTTP 200 response. Check the Monitors page in CronJobPro to confirm the ping was recorded.

  5. 5

    Verify the first scheduled run

    After the first scheduled execution, confirm the report arrived in your inbox or destination, then check CronJobPro Monitors to see the heartbeat was received within the expected window. Review execution logs if available to catch any environment-specific issues that only appear under cron.

The script

bash

#!/usr/bin/env bash
# daily_sales_report.sh
# Generates and delivers the daily sales/metrics report.
# Place in /usr/local/bin/daily_sales_report.sh and chmod +x.
# Cron entry: 0 7 * * * /usr/local/bin/daily_sales_report.sh >> /var/log/daily_sales_report.log 2>&1

set -euo pipefail

# --- Configuration ---
REPORT_ENDPOINT="https://your-app.internal/api/reports/daily-sales"
REPORT_TOKEN="your-secret-api-token"
RECIPIENT="team@yourcompany.com"
HEARTBEAT_URL="https://cronjobpro.com/ping/YOUR_HEARTBEAT_TOKEN"
OUTPUT_FILE="/tmp/daily_sales_report_$(date +%Y%m%d).json"

# --- Fetch the report ---
HTTP_STATUS=$(curl --silent --show-error --output "$OUTPUT_FILE" \
  --write-out "%{http_code}" \
  --max-time 60 \
  --header "Authorization: Bearer $REPORT_TOKEN" \
  "$REPORT_ENDPOINT")

if [ "$HTTP_STATUS" -ne 200 ]; then
  echo "[$(date -Iseconds)] ERROR: Report endpoint returned HTTP $HTTP_STATUS"
  curl --silent "${HEARTBEAT_URL}/fail" > /dev/null
  exit 1
fi

# --- Optional: email the report ---
# Requires mailutils or similar; adjust to your mail setup.
if command -v mail &> /dev/null; then
  mail -s "Daily Sales Report $(date +%Y-%m-%d)" "$RECIPIENT" < "$OUTPUT_FILE"
fi

# --- Cleanup old report files older than 7 days ---
find /tmp -name 'daily_sales_report_*.json' -mtime +7 -delete

echo "[$(date -Iseconds)] Report generated and delivered successfully."

# --- Heartbeat ping: tell CronJobPro the job succeeded ---
curl --silent "$HEARTBEAT_URL" > /dev/null
exit 0

Monitor it

Create a Heartbeat monitor in CronJobPro with a 24-hour period and a 30-minute grace period to match the 7:00 AM daily schedule. The script calls https://cronjobpro.com/ping/YOUR_HEARTBEAT_TOKEN on successful completion, and calls /ping/YOUR_HEARTBEAT_TOKEN/fail explicitly if the report endpoint returns a non-200 status. If the ping does not arrive by 7:30 AM, CronJobPro treats the job as missed or failed and sends alerts to whichever channels you configured, such as email, Slack, or PagerDuty. This way you are alerted not only when the server is down entirely, but also when the report endpoint itself fails, the network call times out, or the cron daemon is silently misconfigured, none of which a simple uptime monitor would catch.

Frequently asked questions

What if my report takes longer than 60 seconds to generate?

Increase the --max-time value in the curl command to match your worst-case report generation time. Also extend the grace period in your CronJobPro heartbeat monitor so a slow but successful run does not trigger a false alert.

Can CronJobPro run the HTTP endpoint directly instead of using server cron?

Yes. If your report endpoint is publicly reachable (or reachable via an authenticated URL), you can create a scheduled job in CronJobPro that calls the endpoint directly on the 0 7 * * * schedule. In that case CronJobPro fires the HTTP request for you, and you can still attach a heartbeat or use the built-in execution log to confirm success.

How do I avoid leaking the API token in the cron log?

Store the token in an environment variable or a separate config file readable only by the cron user, then source that file at the top of your script. Avoid passing tokens as command-line arguments, since those appear in process listings.

What alert channels does CronJobPro support for missed heartbeats?

CronJobPro supports email, Slack, Discord, Microsoft Teams, PagerDuty, Opsgenie, and generic webhooks. You configure alert channels in your account settings and assign them to each monitor independently.

More recipes

Automate Daily Sales and Metrics Reports | CronJobPro