Skip to content

Repository files navigation

Overdue

Overdue is a small HTTP check-in monitor.

It waits for periodic check-ins, moves through a simple lifecycle when a check-in is late, and sends notifications through configured webhook or email targets when the alerting deadline is reached.

Lifecycle

scheduled -> awaiting -> overdue -> alerting -> awaiting
  • scheduled: no check-in has been received yet.
  • awaiting: a check-in was received and the next deadline is active.
  • overdue: the expected check-in deadline passed and the alerting delay is running.
  • alerting: the alerting delay elapsed and an alert notification was queued.
  • resolved: a resolved notification is queued when check-ins resume after alerting and the receiver has send-resolved=true.

Quick start

docker run --rm -p 8080:8080 \
-e OVERDUE__EXPECTED_EVERY=1m \
-e OVERDUE__ALERTING_DELAY=10s \
ghcr.io/containeroo/overdue:latest

Send a check-in:

curl -X POST http://localhost:8080/checkin

Check status:

curl http://localhost:8080/status

Configuration

Overdue is configured through CLI flags or environment variables.

Environment variables use the OVERDUE__ prefix. Flag names are uppercased and dashes become underscores.

Examples:

--expected-every -> OVERDUE__EXPECTED_EVERY
--alerting-delay -> OVERDUE__ALERTING_DELAY
--public-url -> OVERDUE__PUBLIC_URL
--webhook.ops.url -> OVERDUE__WEBHOOK_OPS_URL
--webhook.ops.custom-data -> OVERDUE__WEBHOOK_OPS_CUSTOM_DATA
--email.primary.smtp-host -> OVERDUE__EMAIL_PRIMARY_SMTP_HOST
--email.primary.from -> OVERDUE__EMAIL_PRIMARY_FROM

Core flags

FlagEnvironment variableDefaultDescription
--listen-addressOVERDUE__LISTEN_ADDRESS:8080HTTP server listen address.
--route-prefixOVERDUE__ROUTE_PREFIXemptyOptional path prefix when Overdue is served below a sub-path.
--public-urlOVERDUE__PUBLIC_URLemptyPublic base URL used in notification template links.
--nameOVERDUE__NAMEdefaultName of the check-in monitor used in responses and notifications.
--pathOVERDUE__PATH/checkinRoute used to receive check-ins.
--expected-everyOVERDUE__EXPECTED_EVERYrequiredMaximum time between check-ins.
--alerting-delayOVERDUE__ALERTING_DELAYrequiredExtra time after the expected deadline before alerting.
--start-activeOVERDUE__START_ACTIVEfalseActivate the monitor at startup instead of waiting for the first check-in.
--allow-get-checkinOVERDUE__ALLOW_GET_CHECKINfalseAlso accept GET requests on the check-in route.
--response-detailsOVERDUE__RESPONSE_DETAILSfalseReturn detailed timing fields from check-in responses by default.
--auth-tokenOVERDUE__AUTH_TOKENemptyOptional bearer token required for check-in and status requests.
--debugOVERDUE__DEBUGfalseEnable debug logging.
--log-formatOVERDUE__LOG_FORMATjsonLog format: json or text.

Notifications

Overdue supports multiple named webhook and email targets.

Each target is configured as a dynamic group instance:

webhook.<name>.<field>
email.<name>.<field>

Examples:

--webhook.ops.url=https://hooks.slack.com/services/...
--email.primary.smtp-host=smtp.example.com

If no notification targets are configured, Overdue still runs and records status, but no notifications are sent.

Webhook flags

Flag patternEnvironment variable patternDefaultDescription
--webhook.<name>.urlOVERDUE__WEBHOOK_<NAME>_URLrequiredWebhook URL.
--webhook.<name>.methodOVERDUE__WEBHOOK_<NAME>_METHODPOSTHTTP method: POST, PUT, PATCH, or DELETE.
--webhook.<name>.timeoutOVERDUE__WEBHOOK_<NAME>_TIMEOUT10sHTTP request timeout.
--webhook.<name>.tls-skip-verifyOVERDUE__WEBHOOK_<NAME>_TLS_SKIP_VERIFYfalseSkip TLS certificate verification.
--webhook.<name>.send-resolvedOVERDUE__WEBHOOK_<NAME>_SEND_RESOLVEDfalseSend resolved notifications to this receiver.
--webhook.<name>.title-templateOVERDUE__WEBHOOK_<NAME>_TITLE_TEMPLATEstatus titleOptional notification title template.
--webhook.<name>.headersOVERDUE__WEBHOOK_<NAME>_HEADERSemptyHTTP headers in KEY=VALUE format.
--webhook.<name>.custom-dataOVERDUE__WEBHOOK_<NAME>_CUSTOM_DATAemptyCustom template data in KEY=VALUE format.
--webhook.<name>.templateOVERDUE__WEBHOOK_<NAME>_TEMPLATErequiredBody template path or builtin:<name>.
--webhook.<name>.log-responseOVERDUE__WEBHOOK_<NAME>_LOG_RESPONSEsummaryWebhook response logging: summary, body, full, or none.
--webhook.<name>.response-body-limitOVERDUE__WEBHOOK_<NAME>_RESPONSE_BODY_LIMIT4096Maximum response body bytes to read for logs and errors.

Email flags

Flag patternEnvironment variable patternDefaultDescription
--email.<name>.smtp-hostOVERDUE__EMAIL_<NAME>_SMTP_HOSTrequiredSMTP host.
--email.<name>.smtp-portOVERDUE__EMAIL_<NAME>_SMTP_PORT587SMTP port.
--email.<name>.smtp-userOVERDUE__EMAIL_<NAME>_SMTP_USERemptySMTP username.
--email.<name>.smtp-passOVERDUE__EMAIL_<NAME>_SMTP_PASSemptySMTP password.
--email.<name>.smtp-tls-skip-verifyOVERDUE__EMAIL_<NAME>_SMTP_TLS_SKIP_VERIFYfalseSkip SMTP TLS certificate verification.
--email.<name>.send-resolvedOVERDUE__EMAIL_<NAME>_SEND_RESOLVEDfalseSend resolved notifications to this receiver.
--email.<name>.title-templateOVERDUE__EMAIL_<NAME>_TITLE_TEMPLATEstatus titleOptional notification title template.
--email.<name>.fromOVERDUE__EMAIL_<NAME>_FROMrequiredSender address.
--email.<name>.toOVERDUE__EMAIL_<NAME>_TOrequiredRecipient address. May be repeated.
--email.<name>.headersOVERDUE__EMAIL_<NAME>_HEADERSemptyEmail headers in KEY=VALUE format.
--email.<name>.custom-dataOVERDUE__EMAIL_<NAME>_CUSTOM_DATAemptyCustom template data in KEY=VALUE format.
--email.<name>.templateOVERDUE__EMAIL_<NAME>_TEMPLATErequiredBody template path or builtin:<name>.

Webhook examples

Slack incoming webhook

docker run --rm -p 8080:8080 \
-e OVERDUE__EXPECTED_EVERY=1m \
-e OVERDUE__ALERTING_DELAY=10s \
-e OVERDUE__PUBLIC_URL=https://overdue.example.com \
-e OVERDUE__WEBHOOK_OPS_URL="$SLACK_WEBHOOK_URL" \
-e OVERDUE__WEBHOOK_OPS_TEMPLATE=builtin:slack-incoming-webhook \
-e OVERDUE__WEBHOOK_OPS_CUSTOM_DATA=channel=#alertmanager \
-e OVERDUE__WEBHOOK_OPS_SEND_RESOLVED=true \
ghcr.io/containeroo/overdue:latest

Generic JSON webhook

docker run --rm -p 8080:8080 \
-e OVERDUE__EXPECTED_EVERY=1m \
-e OVERDUE__ALERTING_DELAY=10s \
-e OVERDUE__WEBHOOK_OPS_URL=https://example.com/webhook \
-e OVERDUE__WEBHOOK_OPS_TEMPLATE=/etc/overdue/webhook.tmpl \
-v "$PWD/webhook.tmpl:/etc/overdue/webhook.tmpl:ro" \
ghcr.io/containeroo/overdue:latest

Example webhook.tmpl:

{
"title": {{ .Title | json }},
"text": {{ .Text | json }},
"status": {{ .Status | json }},
"checkInName": {{ .CheckInName | json }},
"resolved": {{ .Resolved | json }}
}

Email example

docker run --rm -p 8080:8080 \
-e OVERDUE__EXPECTED_EVERY=1m \
-e OVERDUE__ALERTING_DELAY=10s \
-e OVERDUE__PUBLIC_URL=https://overdue.example.com \
-e OVERDUE__EMAIL_OPS_SMTP_HOST=smtp.example.com \
-e OVERDUE__EMAIL_OPS_SMTP_PORT=587 \
-e OVERDUE__EMAIL_OPS_SMTP_USER=overdue@example.com \
-e OVERDUE__EMAIL_OPS_SMTP_PASS="$SMTP_PASSWORD" \
-e OVERDUE__EMAIL_OPS_FROM=overdue@example.com \
-e OVERDUE__EMAIL_OPS_TO=ops@example.com \
-e OVERDUE__EMAIL_OPS_TEMPLATE=builtin:email-html \
-e OVERDUE__EMAIL_OPS_SEND_RESOLVED=true \
ghcr.io/containeroo/overdue:latest

OVERDUE__EMAIL_OPS_FROM is required. If it is missing, notification setup or delivery fails because the email target cannot build a valid message.

Templates

Notification payloads are rendered with Go templates.

Overdue includes built-in templates:

builtin:email-html
builtin:slack-incoming-webhook
builtin:slack-chat-post-message

Custom templates can be mounted into the container and referenced by path:

-e OVERDUE__WEBHOOK_OPS_TEMPLATE=/etc/overdue/slack.tmpl

Webhook templates must render valid JSON. Email templates may render text or HTML.

Templates use strict missing-key behavior. Missing fields fail during startup validation or delivery instead of rendering silently.

Template data

Templates receive the following data:

FieldTypeDescription
.IncidentIDstringStable ID for one overdue incident.
.NotificationIDstringStable ID for this concrete notification.
.CheckInNamestringConfigured check-in name.
.LastCheckIntime.TimeLast received check-in time.
.ExpectedBytime.TimeTime when the next check-in was expected.
.OverdueSincetime.TimeTime when the check-in became overdue.
.AlertingAttime.TimeTime when alerting starts.
.Nowtime.TimeTime the notification event was created.
.PhasestringMonitor phase.
.StatusstringNotification status: alerting or resolved.
.ResolvedboolWhether this is a resolved notification.
.TitlestringRendered notification title.
.TextstringDefault plain text summary.
.ReceiverstringReceiver name.
.CustomDatamap[string]stringCustom data configured with custom-data.
.App.VersionstringOverdue version.
.App.SiteRootstringPublic base URL from --public-url.
.App.CheckInURLstringPublic check-in URL when --public-url is configured.
.App.StatusURLstringPublic status URL when --public-url is configured.

Custom data

Custom data is configured with KEY=VALUE values:

-e OVERDUE__WEBHOOK_OPS_CUSTOM_DATA=channel=#alertmanager

It is available in templates as .CustomData.

Recommended access:

{{ index .CustomData "channel" }}

Example with a default:

{{ index .CustomData "channel" | default "alertmanager" | withPrefix "#" }}

Title templates

Title templates are optional. When no title template is configured, the flag default renders [OVERDUE] Event Notification or [RESOLVED] Event Notification. Built-in body templates render their title from the event data.

Override the title per receiver when you need a custom Slack title or email subject:

-e OVERDUE__WEBHOOK_OPS_TITLE_TEMPLATE='{{ if .Resolved }}[OK]{{ else }}[ALERT]{{ end }} {{ .CheckInName }}'
-e OVERDUE__EMAIL_OPS_TITLE_TEMPLATE='{{ if .Resolved }}[OK]{{ else }}[ALERT]{{ end }} {{ .CheckInName }}'

HTTP API

POST /checkin

Records a check-in.

curl -X POST http://localhost:8080/checkin

Compact response:

{ "status": "ok" }

Detailed response:

curl -X POST 'http://localhost:8080/checkin?details=true'

GET /checkin

Disabled by default. Enable --allow-get-checkin only for simple uptime systems that cannot send POST requests. When enabled, GET /checkin also records a check-in.

GET /status

Returns the current monitor state.

curl http://localhost:8080/status

Detailed status:

curl 'http://localhost:8080/status?details=true'

GET /healthz and POST /healthz

Liveness probe.

curl http://localhost:8080/healthz

GET /readyz and POST /readyz

Readiness probe. If this endpoint is mounted, startup configuration and notification setup completed successfully.

curl http://localhost:8080/readyz

GET /version

Returns build version and commit.

curl http://localhost:8080/version

GET /metrics

Prometheus metrics endpoint. It includes monitor phase/timestamp gauges, received check-in counters, and notification queue counters for queued, skipped, and queue-failed alerting/resolved notifications.

This endpoint is intentionally not protected by --auth-token, because Prometheus commonly scrapes without application bearer tokens. Do not expose it directly to the public internet unless a reverse proxy, firewall, or network policy restricts access.

curl http://localhost:8080/metrics

Authentication

Set --auth-token or OVERDUE__AUTH_TOKEN to require a bearer token for check-in and status requests. The metrics, health, readiness, and version endpoints remain unauthenticated; protect them at the reverse proxy or network layer when exposed outside a trusted network.

curl -H "Authorization: Bearer $OVERDUE_TOKEN" \
-X POST http://localhost:8080/checkin

Route prefix

Use --route-prefix when Overdue is served below a path prefix.

-e OVERDUE__ROUTE_PREFIX=/watchdog

With this prefix, endpoints are served below /watchdog:

/watchdog/checkin
/watchdog/status
/watchdog/metrics
/watchdog/healthz
/watchdog/readyz

Set --public-url to the externally reachable base URL if you want templates to include correct links:

-e OVERDUE__PUBLIC_URL=https://overdue.example.com/watchdog

Docker Compose

---
name: overdueservices:
overdue:
image: ghcr.io/containeroo/overdue:latestrestart: unless-stoppedports:
- "8080:8080"environment:
OVERDUE__EXPECTED_EVERY: 1mOVERDUE__ALERTING_DELAY: 10sOVERDUE__PUBLIC_URL: https://overdue.example.comOVERDUE__WEBHOOK_OPS_URL: "${SLACK_WEBHOOK_URL}"OVERDUE__WEBHOOK_OPS_TEMPLATE: builtin:slack-incoming-webhookOVERDUE__WEBHOOK_OPS_CUSTOM_DATA: channel=#alertmanagerOVERDUE__WEBHOOK_OPS_SEND_RESOLVED: "true"

Development

Run tests:

make test

Run locally:

go run . \
--expected-every=1m \
--alerting-delay=10s

Run locally with an email receiver:

go run . \
--expected-every=1m \
--alerting-delay=10s \
--email.ops.smtp-host=smtp.example.com \
--email.ops.from=overdue@example.com \
--email.ops.to=ops@example.com \
--email.ops.template=builtin:email-html

License

This project is licensed under the Apache 2.0 License. See the LICENSE file for details.

About

Small HTTP check-in monitor with webhook/email notifications.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages