Metadata-Version: 2.5
Name: cronalive
Version: 0.3.0
Summary: CronAlive heartbeat monitoring: ping helper, decorator and CLI wrapper
Project-URL: Documentation, https://cronalive.com/en/docs/
Project-URL: Source, https://github.com/opopeshku/cronalive
License: MIT
License-File: LICENSE
Keywords: cron,healthcheck,heartbeat,monitoring,uptime
Requires-Python: >=3.9
Description-Content-Type: text/markdown

# cronalive

Heartbeat monitoring for cron jobs and scripts with [CronAlive](https://cronalive.com):
if a job stops pinging on schedule, you get an alert.

Pings never raise — monitoring must not break the monitored job.

## Install

```bash
pip install cronalive
```

The ping domain can be overridden with the `CRONALIVE_PING_DOMAIN` env variable.

## Usage

```python
import cronalive

# plain pings (fire-and-forget, never raise):
cronalive.ping("<uuid>")          # success
cronalive.ping("<uuid>", "fail")  # explicit failure

# decorator: /start before the call, success or /fail after it —
# CronAlive also measures the job duration:
@cronalive.monitor("<uuid>")
def nightly_job():
    ...
```

CLI wrapper — run any command under monitoring (sends `/start`, then the
exit code; 0 = success):

```bash
cronalive run --id <uuid> -- /usr/local/bin/backup.sh --fast
```

## Creating a check with the first ping

Ping by **slug** with `?create=1` and the check appears on first contact —
no dashboard trip. There is no scheduler to read the schedule from here (the
Laravel package derives it automatically), so pass it in the query yourself:

```python
import cronalive

# a plain period, in seconds
cronalive.ping("<ping-key>/etl-run?create=1&period=3600&grace=300")

# or a cron expression with a time zone (url-encode the spaces)
cronalive.ping("<ping-key>/backup?create=1&cron=30+3+*+*+*&tz=Europe/Moscow")

# tags for grouping on the dashboard
cronalive.ping("<ping-key>/etl-run?create=1&period=3600&tags=etl,prod")
```

`period` is 60–31536000 seconds, `grace` is 30–2592000, `cron` replaces
`period`, `tz` defaults to UTC, and `tags` is a comma-separated list (up to
20 tags of 64 characters; the server trims and truncates rather than
rejecting — a label is not worth failing a ping over). With no parameters
the project defaults apply. Creating is not updating: once the check exists these parameters are
ignored, so change the schedule in the dashboard or through the API.

Signal suffixes live **in the path, ahead of the query** — do not pass them
as the second argument here, or they would land inside a parameter value:

```python
cronalive.ping("<ping-key>/etl-run/start?create=1&period=3600")
```

## Pings never hold your job

Signals are sent inline, around the job you actually care about, so they
carry a short explicit timeout (`cronalive.TIMEOUT`, 2 seconds) covering
both the connect and the read. An unreachable — or worse, a hung — ping
domain costs the job a couple of seconds, not the default socket wait.

A failed signal is swallowed and never retried: a retry would only double
the delay, and the next run sends a fresh ping anyway.

## Docs

Full documentation: <https://cronalive.com/en/docs/> (Russian: <https://cronalive.com/docs/>).

## License

MIT
