123 lines
4.7 KiB
Markdown
123 lines
4.7 KiB
Markdown
# Daily Blackout Check
|
|
|
|
Checks the official SAAPA planned-outage API and sends Persian notifications to
|
|
an Eitaa chat when an outage is added, changed, cancelled, or restored.
|
|
|
|
The checker is designed for an hourly Gitea Actions workflow. Its deduplication
|
|
state is stored in `state/outages.json` and committed back to this repository.
|
|
|
|
## Behavior
|
|
|
|
- Queries each configured bill ID from today through five days ahead.
|
|
- Uses Tehran time regardless of the runner container's timezone.
|
|
- Sends all upcoming outages when starting with empty state.
|
|
- Treats an existing outage number with changed time, address, date, reason, or
|
|
planned status as an update.
|
|
- Reports a future outage as cancelled only after two consecutive successful
|
|
checks omit it.
|
|
- Records a notification only after Eitaa accepts it. This favors delivery over
|
|
perfect deduplication: a failed state push can cause a duplicate next hour.
|
|
- Rejects malformed responses and snapshots larger than the configured safety
|
|
limit without changing that bill's state.
|
|
|
|
## Local setup
|
|
|
|
Python 3.11 or newer is required. The Gitea runner image uses Debian's Python 3.11.
|
|
|
|
```sh
|
|
python -m venv .venv
|
|
source .venv/bin/activate
|
|
python -m pip install -e '.[test]'
|
|
cp .env.example .env
|
|
```
|
|
|
|
Fill in the required values in `.env`, then preview the next run without sending
|
|
messages or changing state:
|
|
|
|
```sh
|
|
python -m blackout_notifier check --dry-run
|
|
```
|
|
|
|
Run the live checker with:
|
|
|
|
```sh
|
|
python -m blackout_notifier check
|
|
```
|
|
|
|
## Configuration
|
|
|
|
| Variable | Required | Default | Purpose |
|
|
| --- | --- | --- | --- |
|
|
| `BARGHEMAN_TOKEN` | Yes | — | SAAPA bearer token |
|
|
| `EITAAYAR_TOKEN` | Yes | — | EitaaYar bot token |
|
|
| `CHAT_ID` | Yes | — | Destination Eitaa chat |
|
|
| `BILL_IDS` | Yes | — | Comma-separated decimal bill IDs |
|
|
| `STATE_FILE` | No | `state/outages.json` | Durable notification state |
|
|
| `LOOKAHEAD_DAYS` | No | `5` | Query horizon, from 1 to 30 days |
|
|
| `REQUEST_TIMEOUT_SECONDS` | No | `15` | HTTP timeout, from 1 to 120 seconds |
|
|
| `MAX_EVENTS_PER_BILL` | No | `25` | Response safety limit, from 1 to 100 |
|
|
|
|
Shell and Gitea-provided variables take precedence over `.env`.
|
|
|
|
## Gitea deployment
|
|
|
|
This repository targets Gitea 1.25.x and a Docker-based runner advertising the
|
|
`ubuntu-latest` label. Both workflows run inside the locally built
|
|
`daily-blackout-check-runner:latest` image. It contains Node for the checkout
|
|
action plus Python, Git, timezone data, application dependencies, pytest, and
|
|
Ruff. Scheduled jobs therefore do not install Python or download Python packages.
|
|
|
|
Build the image on the Docker host used by `act_runner`:
|
|
|
|
```sh
|
|
cd /path/to/daily-blackout-check
|
|
docker build \
|
|
--tag daily-blackout-check-runner:latest \
|
|
runner-image
|
|
docker image inspect daily-blackout-check-runner:latest >/dev/null
|
|
```
|
|
|
|
Only `runner-image/` is sent as the Docker build context, so local secrets and
|
|
outage state never enter the build context or image.
|
|
|
|
The image is local rather than registry-hosted, matching the deployment pattern
|
|
used by `mahak-api-docs`. Build it on every runner host that can claim this job.
|
|
Rebuild it whenever `runner-image/Dockerfile`, `runner-image/requirements.lock`,
|
|
or dependency declarations in `pyproject.toml` change. The image build requires
|
|
Docker Hub and PyPI access; normal workflow runs only need the Gitea instance,
|
|
`gitea.com`, SAAPA, and EitaaYar.
|
|
|
|
1. Build `daily-blackout-check-runner:latest` on the runner's Docker host.
|
|
2. Enable Actions in the repository settings.
|
|
3. Confirm an online Docker runner advertises `ubuntu-latest`.
|
|
4. Add these repository Actions secrets:
|
|
`BARGHEMAN_TOKEN`, `EITAAYAR_TOKEN`, `CHAT_ID`, and `BILL_IDS`.
|
|
5. Run the test workflow manually.
|
|
6. Run **Hourly blackout check** manually once and inspect the notification and
|
|
resulting state commit.
|
|
7. Leave the `@hourly` schedule enabled.
|
|
|
|
The workflow uses fully qualified `https://gitea.com/actions/...` actions rather
|
|
than resolving actions through GitHub. Gitea 1.25 ignores workflow `permissions`
|
|
and `concurrency`, so the notifier workflow deliberately does not rely on them.
|
|
Its checkout credential must retain the default ability to push to the current
|
|
repository. Scheduled jobs should not be manually overlapped; in the rare event
|
|
of a push race, the job fails and unsaved notices may be repeated on the next run.
|
|
|
|
If a workflow tries to pull the local image instead of using it, ensure the image
|
|
exists in the same Docker daemon used by `act_runner` and set
|
|
`container.force_pull: false` in the runner's generated `config.yaml`, then
|
|
restart the runner.
|
|
|
|
## Development
|
|
|
|
```sh
|
|
ruff check .
|
|
pytest
|
|
```
|
|
|
|
Tests mock both external services and never send real messages.
|
|
|
|
Historical state from the previous implementation is retained at
|
|
`archive/blackouts-1404.json` for reference only and is not imported.
|