Spaces:
Paused
Download README.md from imkrish/ig-costing: direct link, hf CLI and curl.
- Browser
- Download file 5.11 kB
-
https://huggingface.co/spaces/imkrish/ig-costing/resolve/main/README.md
- Command line
-
hf download hf://spaces/imkrish/ig-costing/README.md
-
curl -L -o README.md https://huggingface.co/spaces/imkrish/ig-costing/resolve/main/README.md
title: IG Costing Server
emoji: πΈ
colorFrom: indigo
colorTo: purple
sdk: docker
app_port: 7860
pinned: false
IG Costing β ingest + query server
Collects LLM cost events and Lambda invocations from the InterviewGod backend and spreads them across multiple Atlas clusters. Stateless: MongoDB is external, so the container holds nothing and restarts cost nothing.
Stable base URL: https://<user>-<space>.hf.space β no tunnel, never rotates.
Secrets
Set by CI (.github/workflows/deploy-space.yml mirrors them from GitHub secrets),
or by hand in Settings β Variables and secrets.
| Secret | Required | Purpose |
|---|---|---|
CostingDBURL1, CostingDBURL2, β¦ |
yes | Atlas URIs for llm_events + budget_config |
LambdaDBURL1, LambdaDBURL2, β¦ |
yes | Atlas URIs for lambda_events |
REPORTING_CLIENT_ID |
yes | HMAC client id β must match prod |
REPORTING_CLIENT_SECRET |
yes | HMAC secret β must match prod |
SPACE_URL |
for keep-alive | This Space's own public URL |
MONGO_DB_NAME |
no | Database name on every cluster (default costingDB) |
SHARD_ROLLOVER_AT |
no | Quota fraction at which writes roll to the next shard (default 0.9) |
KEEPALIVE_MINUTES |
no | Self-ping interval (default 30) |
Numbering is 1-based and sorted numerically, so LambdaDBURL10 comes after
LambdaDBURL9. Order is the write policy β see below.
Each shard is opened with an explicit database name. Connection strings ending in
/ would otherwise land in test on some clusters and costingDB on others.
Sharding
Writes β fill-and-spill. Everything goes to the first shard under
SHARD_ROLLOVER_AT; when it fills, writes roll to the next. Sizes are cached for
5 minutes, and an Atlas quota error forces an immediate re-probe and retry rather
than dropping the batch.
Hashing by func_name was the obvious alternative and is wrong here: one function
is ~99% of Lambda traffic, so it would pin nearly every write to one shard while
the rest sat empty.
Note this multiplies storage, not throughput β all writes still land on one cluster at a time, and a free cluster caps at 100 ops/sec.
Reads β fan out and merge. Older data lives on earlier shards, so every read
queries all of them. $sort/$limit were removed from the by_provider /
by_model / by_func facets and applied after merging: a top-10 taken per shard
can miss an entry ranking 11th everywhere but first overall.
Endpoints
POST /v1/llm-calls ingest, HMAC-signed
POST /v1/lambda-executions ingest, HMAC-signed
GET /v1/stats /v1/overview β¦ dashboard queries
GET /v1/setup-indexes creates indexes on EVERY shard β run once
GET /v1/admin/shards per-shard usage + which one is taking writes
GET /v1/admin/health liveness, does not touch Mongo
Keep-alive
instrumentation.ts pings SPACE_URL/api/v1/admin/health every
KEEPALIVE_MINUTES. It hits the public URL deliberately β HF's idle timer counts
requests through their router, not traffic inside the container.
It keeps a running Space awake. It cannot restart a stopped one; nothing is left to send the ping. Pair it with an external cron if that matters.
Going live
- Push to
masterβ CI syncs secrets, uploads this folder, Space rebuilds GET /v1/admin/healthGET /v1/setup-indexesβ every shard needs indexes, including empty onesGET /v1/admin/shardsβ confirm all clusters reachable- Repoint prod's reporting base URL here
Provisioning new clusters
Atlas allows one free cluster per project, so each new shard means a new project,
cluster, user and IP rule. scripts/atlas-provision.mjs does all of it.
One-time setup in the Atlas UI:
- Organization β Access Manager β Applications β Add Service Account
- Role: Organization Project Creator (needs to create projects, not just read)
- Copy the Client ID and Client Secret β the secret is shown once
- Organization β Settings for the Organization ID
- Put all three in
backend/.env:
ATLAS_CLIENT_ID=...
ATLAS_CLIENT_SECRET=...
ATLAS_ORG_ID=...
Then:
node scripts/atlas-provision.mjs lambda 5 6 # LambdaDBURL5, LambdaDBURL6
node scripts/atlas-provision.mjs costing 3
Each cluster takes ~3-5 minutes. The script skips numbers already in .env, so
re-running after a failure is safe.
Each connection string is written to backend/.env and pushed to GitHub
secrets, because that is where the Space reads its config from. Then:
gh workflow run deploy-space.yml
The ATLAS_* service-account credentials stay on your machine. Only this script
uses them, and they are absent from the deploy workflow's secret allowlist, so
they cannot reach the Space even if added to GitHub by hand.
Watch
/v1/admin/shards. Raw Lambda events run ~47 MB/day, so each 512 MB cluster
fills in about 11 days.
npm run check:shards # read-only preflight against every configured cluster
npm test # cross-shard merge checks