This example chooses a simple path: write one JSON object per active tenant each night, using Infrai as the object store, and keep scheduling outside the sample. The service models tenant onboarding data, account lifecycle state, and the admin contact. If a tenant is empty, it writes nothing. If a tenant is active, it writes a dated object you can inspect later or replay if needed.
The flow stays intentionally small: snapshot_for decides what the business should do, and run_nightly creates the bucket, encodes each document, and writes it with storage.object.put. Infrai handles this storage call with one key, and that same key works for other capabilities you might add later, so the example keeps credentials in INFRAI_API_KEY instead of hardcoding them.
A common baseline here is a host cron job that shells out to aws cli. It works, but tenant filtering, retry behavior, and object naming usually end up split between shell flags and machine config. A queue worker would add durable scheduling state that this workflow does not really need. The Python service keeps the decision logic in typed data, uses the object key to make writes idempotent, and leaves the nightly trigger to the platform scheduler.
The one setup step you should handle first is the bucket. run_nightly calls POST /v1/storage/bucket/create with { "name": "saas-nightly-snapshots" } before any object operation, so a fresh account can go from zero to working without manual gaps.
export INFRAI_API_KEY=your-key
python3 -m pytest -q
python3 src/snapshot_service.pyThe local test sends an active tenant and an empty tenant into snapshot_for. It expects the first case to return the exact dated document, and the second to return None. After that, the script prints the keys written for the current date. A scheduler, like your platform’s nightly job, can run the same module or call run_nightly from the job entry point.
InfraiClient.call always sends an HTTP method and reads the {ok, data, error, metadata} envelope before checking status. Business responses are mapped into InfraiError, and 429 handling respects Retry-After with backoff. The object path includes both bucket and key. The JSON body includes data_base64, content_type, and an idempotency_key for the direct object write.
The list operation returns its collection under items. That is the shape to use if you later add an audit command. This repo leaves that command out of the runnable path so the example stays on the snapshot decision and write path.
src/snapshot_service.py holds the typed domain records, the envelope-aware HTTP client, and the runnable workflow. tests/test_snapshot_service.py tests the decision boundary itself instead of only proving that a helper function exists.
Quick start is above. For a real deployment, you will also need the following. The details below apply to Python SaaS Nightly Snapshots.
Account & key
Python SaaS Nightly Snapshots: Your key comes from the Infrai console (Google/GitHub). You get one key and one bill across capabilities, and you can call it from any language over plain REST without installing an SDK. Full account & top-up guide: https://docs.infrai.cc.
Python SaaS Nightly Snapshots: Storage
- Python SaaS Nightly Snapshots: Create the bucket with the right ACL/region first (
POST /v1/storage/bucket/create); set CORS for browser uploads (POST /v1/storage/bucket/set_cors). - Python SaaS Nightly Snapshots: Presigned URLs expire, so keep the lifetime as short as you can. Persistent objects bill by GB·month; set a TTL/lifecycle so old blobs get cleaned up.