Spaces:
Running
Running
|
Download docs/operations-runbook.md from Benaah/MicProtocol: direct link, hf CLI and curl.
- Browser
- Download file 12.1 kB
-
https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/docs/operations-runbook.md
- Command line
-
hf download hf://spaces/Benaah/MicProtocol/docs/operations-runbook.md
-
curl -L -o operations-runbook.md https://huggingface.co/spaces/Benaah/MicProtocol/resolve/main/docs/operations-runbook.md
12.1 kB
| # Operations Runbook | |
| Day-to-day and incident-runbook guidance for MicProtocol in production. This is the central ops doc; per-service deep dives live in [Formbricks Runbook](./formbricks-runbook.md) and the relevant sections of [Self-Hosted Stack](./self-hosted-stack.md). | |
| ## 1. Service Inventory | |
| For every container and the resource you need to keep healthy, see the catalog in [Self-Hosted Stack β Service Catalog](./self-hosted-stack.md#service-catalog). Collectively you operate: | |
| - Core infra: Postgres (`pgvector`), Redis, Meilisearch, MinIO, Mailhog (dev) / SMTP relay (prod) | |
| - MicProtocol apps: API, worker, CLIP scorer, mic-realtime, web, admin | |
| - Self-hosted integrations: Cal.com, Formbricks (5 containers), Documenso, Chatwoot (2 containers), Listmonk, Umami, LiveKit | |
| ## 2. Standard Operating Procedures | |
| ### 2.1 Daily checks | |
| ```bash | |
| # Cluster health | |
| docker compose ps | |
| curl -s http://localhost:4000/health/detailed | jq | |
| curl -s http://localhost:4000/integrations/health | jq | |
| # Job queue depth | |
| docker exec micprotocol-redis redis-cli -a "$REDIS_PASSWORD" llen "bull:outreach:wait" | |
| docker exec micprotocol-redis redis-cli -a "$REDIS_PASSWORD" llen "bull:content:wait" | |
| docker exec micprotocol-redis redis-cli -a "$REDIS_PASSWORD" llen "bull:clip-scoring:wait" | |
| # API error rate (last hour) | |
| curl -s http://localhost:4000/tracing/metrics | jq '.errorRate' | |
| ``` | |
| Thresholds: | |
| - Queue depth: alert at > 500 per queue for 15 min | |
| - API p95 latency: alert at > 500 ms for 5 min (read), > 2000 ms for 5 min (write/AI) | |
| - API error rate: alert at > 1% sustained | |
| ### 2.2 Weekly maintenance window | |
| ```bash | |
| # Pull latest images (out-of-band from CI deploys) | |
| docker compose pull | |
| # Roll each integration in isolation (see Self-Hosted Stack β Rolling update a single integration) | |
| docker compose up -d --no-deps calcom | |
| # Formbricks requires re-running migrations (see runbook) | |
| # Restart worker to release orphaned Redis locks | |
| docker compose restart worker | |
| # Vacuum Postgres | |
| docker exec micprotocol-postgres psql -U micprotocol -d micprotocol -c 'VACUUM ANALYZE;' | |
| # Check disk usage | |
| docker system df | |
| ``` | |
| ### 2.3 Backup | |
| Daily backups are the minimum RPO target. Example cron against the live container: | |
| ```bash | |
| # Snapshot all integration databases | |
| for db in micprotocol chatwoot calcom documenso formbricks listmonk umami; do | |
| docker exec micprotocol-postgres pg_dump -U micprotocol -Fc "$db" | \ | |
| gzip > "/backups/${db}_$(date +%Y%m%d).sql.gz" | |
| done | |
| # Retention: prune anything older than 30 days | |
| find /backups -name '*.sql.gz' -mtime +30 -delete | |
| ``` | |
| Test restore quarterly into a sandbox cluster β an untested backup is no backup. | |
| ## 3. Health & Monitoring | |
| ### 3.1 Health endpoints | |
| Every service exposes its own health check; see [Self-Hosted Stack β Health Endpoints](./self-hosted-stack.md#health-endpoints) for the full list. The single consolidated health check is: | |
| ```bash | |
| curl -s http://localhost:4000/health/detailed | |
| ``` | |
| This pings DB, Redis, Meilisearch, and reports the API's own subsystem status. For self-hosted integration reachability: | |
| ```bash | |
| curl -s http://localhost:4000/integrations/health | |
| ``` | |
| ### 3.2 Recommended exporters | |
| | Metric | Source | Alert on | | |
| |---|---|---| | |
| | Container up/down | `docker compose ps` / orchestration | `up == 0` for > 1 min | | |
| | API p95 latency | `/tracing/metrics` or Datadog APM | > 500 ms for 5 min | | |
| | API error rate | `/tracing/metrics` | > 1% sustained | | |
| | Queue depth | Redis `LLEN bull:*:wait` | > 500 pending per queue | | |
| | Postgres connections | `pg_stat_activity` | Active / max > 0.8 | | |
| | Redis memory | `INFO memory` | `used_memory_peak / maxmemory > 0.85` | | |
| | Webhook 401s | API logs (`UnauthorizedException`) | Spike rate | | |
| | CLIP scorer errors | Worker logs | Any timeout / subprocess non-zero exit | | |
| ### 3.3 Sentry integration | |
| Set `SENTRY_DSN` to enable error grouping and release tracking. Optional sampling: | |
| ``` | |
| SENTRY_TRACE_SAMPLE_RATE=0.1 # 10% of traces | |
| SENTRY_PROFILE_SAMPLE_RATE=0.05 # 5% of profiles | |
| ``` | |
| ## 4. Incident Response | |
| ### 4.1 Severity definitions | |
| | Severity | Definition | Response time | Owner | | |
| |---|---|---|---| | |
| | P0 | All API unavailable, no bookings, no recordings | 15 min | Platform on-call | | |
| | P1 | Single workspace affected, or one integration down | 1 hour | Platform team | | |
| | P2 | Analytics delayed, non-critical background jobs backed up | 4 hours | Platform team | | |
| | P3 | Feature request / cosmetic | Next sprint | Product team | | |
| ### 4.2 P0 playbook β API down | |
| 1. `curl -s http://localhost:4000/health/detailed` β confirms scope (DB, Redis, search). | |
| 2. `docker compose ps` β for any container not in `Up` state. | |
| 3. Tail API logs: `docker compose logs -f --tail=200 api`. | |
| 4. Restart in dependency order: `postgres` β `redis` β `meilisearch` β `api` β `worker`. | |
| 5. If DB is the issue, fail back to the latest snapshot (see Β§2.3). | |
| 6. Confirm recovery via `/health/detailed` and a synthetic agent sweep. | |
| 7. File an incident report within 24 hours; review in the next retro. | |
| ### 4.3 P0 playbook β recording sessions failing (LiveKit) | |
| 1. `curl -s http://localhost:4000/integrations/health` β confirms LiveKit reachable. | |
| 2. `docker logs micprotocol-livekit` β check for ICE/UDP port binding errors. | |
| 3. Confirm UDP `7882` is open end-to-end (firewall, security group, NAT). | |
| 4. Verify `LIVEKIT_API_KEY` and `LIVEKIT_API_SECRET` match the configured keys inside the LiveKit container. | |
| 5. For U-Fiber/nat'd networks, configure `rtc.use_external_ip: true` or run behind a TURN server. | |
| ### 4.4 P1 playbook β webhook storm | |
| Symptom: API CPU pegged, `UnauthorizedException` or `IntegrationsWebhookController` log spam. | |
| 1. `docker compose logs -f --tail=200 api | grep IntegrationsWebhookController` β identifies the offender. | |
| 2. Confirm secret rotation hasn't broken verification (`*_WEBHOOK_SECRET` on both sides). | |
| 3. If a provider is redelivering failed events in a tight loop, temporarily pause redelivery upstream (Formbricks / Cal.com / Listmonk admin UI). | |
| 4. Refresh the `WebhookIdempotencyService` cache if the duplicate-detection rate has dropped to zero. | |
| 5. Restore redelivery once root cause is fixed. | |
| ### 4.5 P1 playbook β clip-scoring stuck | |
| Symptom: clips stuck in "Scoringβ¦" badge indefinitely. | |
| 1. Scoring runs inside the worker container via a Python subprocess β `docker ps | grep micprotocol-worker` confirms the process is up. | |
| 2. `docker logs micprotocol-worker` β look for model download failures or FFmpeg errors. | |
| 3. Orphaned Redis distributed locks self-expire with the 5-minute TTL; restarting the worker clears them immediately. | |
| 4. Re-queue affected clips via the Content Studio UI. | |
| See [CLIP Scoring Engine β Troubleshooting](./clip-scoring.md#troubleshooting) for full detail. | |
| ### 4.6 P0 playbook β Postgres corruption | |
| Recovery point objective (RPO): 24 hours (daily backups). Recovery time objective (RTO): 2 hours. | |
| 1. Provision a new Postgres instance. | |
| 2. Restore the latest snapshot: `gunzip -c micprotocol_latest.sql.gz | psql -h new-pg -U micprotocol micprotocol`. | |
| 3. Re-run schema migrations to ensure fresh state. | |
| 4. Update `DATABASE_URL` and restart the API. | |
| 5. Verify data integrity via Prisma Studio + synthetic agent sweep. | |
| Per-integration recovery: Formbricks, Chatwoot, Cal.com etc. each have their own DB. Restore only what's affected β restoring one integration's DB from a 12-hour-old snapshot does not compromise the others. | |
| ## 5. Performance Tuning | |
| ### 5.1 Postgres | |
| ```sql | |
| -- Indexes for the heaviest MicProtocol queries (already in schema, audit periodically) | |
| -- guests(podcast_id, status), guests(podcast_id, priority_score) | |
| -- outreach_sequences(guest_id, status) | |
| -- bookings(start_time, end_time) | |
| -- asset_requests(episode_id, type) | |
| -- Slow query log | |
| ALTER SYSTEM SET log_min_duration_statement = 200; | |
| SELECT pg_reload_conf(); | |
| ``` | |
| ### 5.2 Redis | |
| Production Redis with BullMQ should not share its memory budget with caching: | |
| ```yaml | |
| # docker-compose override | |
| command: redis-server --maxmemory 1gb --maxmemory-policy noeviction --requirepass "${REDIS_PASSWORD}" | |
| ``` | |
| `noeviction` ensures BullMQ job metadata is never evicted; for caching keys, prefer a separate Redis instance. | |
| ### 5.3 CLIP scorer | |
| CLIP is CPU-bound; GPU optional but cuts per-clip time by 5β10Γ. See [CLIP Scoring β Scaling Considerations](./clip-scoring.md) and [Deployment β Scaling Considerations for CLIP Scorer](./deployment.md#scaling-considerations-for-clip-scorer). | |
| ### 5.4 Meilisearch | |
| Re-indexing is cheap; if search latency regresses after a large guest import, trigger a re-index via the API or `curl -X POST http://localhost:7700/indexes/guests/update`. | |
| ## 6. Scaling Triggers | |
| See [Deployment & Scaling β Scaling Triggers](./deployment.md#scaling-triggers) for the full phase-by-phase plan. Operators should plan capacity against the documented phase triggers rather than waiting for alerts. | |
| | Phase | Trigger | Architectural change | | |
| |---|---|---| | |
| | 1 (β€1K podcasts) | Launch | Single ECS task per service; RDS `t4g.micro`; ElastiCache Serverless | | |
| | 2 (1β5K podcasts) | P95 > 500ms OR CPU > 70% sustained | Split workers from API; dedicated Redis for BullMQ vs. cache; RDS read replica | | |
| | 3 (5β20K podcasts) | Email > 100K/day OR queue depth > 1K | Extract Outreach Domain to microservice; migrate orchestration to Temporal.io | | |
| | 4 (20K+ podcasts) | Cross-domain query > 2s P95 | Full microservices split; NATS JetStream event bus; per-service RDS | | |
| ## 7. Common Operations | |
| ### 7.1 Rotate a webhook secret | |
| ```bash | |
| NEW=$(openssl rand -hex 32) | |
| # Update .env: CALCOM_WEBHOOK_SECRET=${NEW} | |
| # Update Cal.com Admin UI: Settings β Webhooks β secret | |
| docker compose restart api | |
| # Tail logs to confirm webhooks still pass verification | |
| docker compose logs -f api | grep -i webhook | |
| ``` | |
| ### 7.2 Add a new workspace for a customer | |
| Synthetic agent seed: [`apps/api/prisma/seed-agents.ts`](../apps/api/prisma/seed-agents.ts) is the reference for deterministic workspace creation. Use the same pattern via tRPC `workspace.create` with the customer's Clerk user ID. | |
| ### 7.3 Run a synthetic agent sweep manually | |
| ```bash | |
| pnpm db:seed:agents # reset seed (optional) | |
| pnpm agents:orchestrator # requires API running on :4000 | |
| cat scripts/synthetic-agents/test-report.txt | |
| jq '.[] | select(.severity == "high")' scripts/synthetic-agents/weaknesses.json | |
| ``` | |
| ### 7.4 Onboard a new self-hosted integration | |
| 1. Add the service block to `docker-compose.yml` (mirror an existing block). | |
| 2. Add its database to `scripts/init-databases.sql` if it needs a Postgres schema. | |
| 3. Create the API client methods in `apps/api/src/integrations/clients/self-hosted-clients.service.ts` (mirroring the `calCom*`, `chatwoot*`, `formbricks*`, `listmonk*`, `documenso*` families). | |
| 4. Add a webhook handler in `apps/api/src/integrations/integrations-webhook.controller.ts`. | |
| 5. Document the new endpoint in [Webhooks](./webhooks.md) and [Third-Party & Self-Hosted Integrations](./third-party-integrations.md). | |
| 6. Add a `*_WEBHOOK_SECRET` to `.env.example` and `scripts/generate-secrets.sh`. | |
| 7. Add a health check method and wire it into the `/integrations/health` aggregator. | |
| ## 8. Change Management | |
| - Production deploys happen only through the CI/CD pipeline (see [Deployment & Scaling β CI/CD Pipeline](./deployment.md#cicd-pipeline)). | |
| - Database migrations: prefer additive changes (new columns nullable, new tables empty, new indexes `CONCURRENTLY`). Prisma migrations ship with the API image. | |
| - Configuration changes (env vars): update `.env` in the secrets store first; orchestrator reads new value on next deploy. | |
| - Backwards-incompatible API changes: gate behind feature flags (`ENABLE_AI_FEATURES`, `ENABLE_CONTENT_STUDIO`, `ENABLE_ANALYTICS`) for at least one release. | |
| ## 9. Contacts & Escalation | |
| | Issue Severity | Response Time | Contact | | |
| |---|---|---| | |
| | P0 (all API down) | 15 min | Platform on-call | | |
| | P1 (single workspace) | 1 hour | Platform team | | |
| | P2 (analytics delayed) | 4 hours | Platform team | | |
| | P3 (feature request) | Next sprint | Product team | | |
| Runbook owner: Platform Engineering. Review quarterly. | |