A containerized restock monitoring service.
This project polls the external API of Amul's online store on a fixed interval, keeps persistent state in SQLite, and sends notifications only on real stock transitions (out → in) and (in → out). It’s designed as a long-running service with explicit configuration, clear separation of concerns, and predictable behavior under restarts and failures.
This is a system rewrite of an earlier prototype. The focus here is correctness, operability, and discipline rather than speed or cleverness.
- Persistent state (no fake alerts on restart)
- Transition-based notifications, not level-based spam
- Explicit intent (what to track is configured, not inferred)
- One process, one loop, no cron
- Docker as the runtime and supervisor
-
ingest_items.pyOne-time / occasional configuration. Inserts or updates items to track. -
amul.pyLong-running controller. Polls the API, compares state, calls notify. -
SQLite Durable memory. Tracks items, current state, and history.
-
Docker + docker-compose Reproducible runtime, restart on crash, no host Python required.
Notifications are sent using ntfy.
When a restock is detected, the service publishes a message to a single ntfy topic via an HTTP POST. Any client subscribed to that topic will receive the alert.
Transport: ntfy (public HTTP)
Semantics: best-effort
Notification failures do not stop the watcher
Default topic in this repo: amulstockbot-qwerty
You can view notifications by:
opening https://ntfy.sh/amulstockbot-qwerty in a browser, or
subscribing to the topic in the ntfy mobile app.
The topic name is configurable via the NTFY_TOPIC environment variable. The topic used in this repository is public and unprotected; for personal use, you should change it to an unguessable value.
- Docker
- Docker Compose
Nothing else is required on the host.
git clone https://github.com/adot-7/amulstockbot-v2.git
cd amulstockbot-v2mkdir dataThis directory holds the SQLite database. Deleting it resets all state.
docker compose buildRun again only if code or dependencies change.
docker compose run --rm watcher python ingest_items.pyThis:
- runs ingestion inside Docker
- populates the database in
data/ - exits cleanly
Run this whenever you want to add or update tracked items.
docker compose up -dThe service now runs continuously.
- Survives crashes
- Survives VM reboots
- Keeps state across restarts
docker logs -f amul-stock-botsqlite3 data/state_and_history.dbSELECT *
FROM items
.quitsqlite3 data/state_and_history.dbUPDATE items
SET notify_enabled = 1
WHERE sku = 'DBDCP45_02';
UPDATE items
SET notify_enabled = 0
WHERE sku = 'DBDCP45_01';
.quitChanges apply on the next poll cycle.
sqlite3 data/state.dbSELECT *
FROM history;
.quitdocker compose downState is preserved.
All configuration is done via environment variables in docker-compose.yml, including:
- poll interval
- database path
- notification parameters
No hardcoded values are required.
- This project intentionally avoids frameworks, brokers, and schedulers.
- Notifications are treated as best-effort side effects.
- If there are no items configured, the watcher will refuse to run.
MIT License.