10 KiB
Deployment Guide - Meta API Grabber
Quick Start (Test Deployment for Tonight)
1. Get a Fresh Access Token
Run the OAuth flow to get a new long-lived token (60 days):
uv run python -m meta_api_grabber.auth
This will:
- Open browser for OAuth authorization
- Exchange short-lived token for long-lived token (60 days)
- Save token to
.envand.meta_token.json - Token will auto-refresh before expiry ✅
2. Verify Your .env File
Ensure your .env has these variables:
# Meta API Credentials
META_APP_ID=your_app_id
META_APP_SECRET=your_app_secret
META_ACCESS_TOKEN=your_long_lived_token # From step 1
# Database (docker-compose handles this)
DATABASE_URL=postgresql://meta_user:meta_password@localhost:5555/meta_insights
3. Build and Start Everything
# Build the Docker image and start all services
docker-compose up -d --build
This starts:
- timescaledb: Database for storing insights
- meta-grabber: Your data collection service ⭐
- grafana: Visualization dashboard (optional)
4. Monitor the Logs
# Watch the grabber logs in real-time
docker-compose logs -f meta-grabber
# Expected output:
# ============================================================
# SCHEDULED INSIGHTS GRABBER STARTED
# ============================================================
# ✅ Token valid (X days remaining)
# Loading accessible ad accounts...
# Loaded X ad account(s)
# Collection interval: 2.0 hours
# ============================================================
#
# COLLECTION CYCLE - 2025-10-21T...
# ============================================================
# Processing X ad account(s)
# ...
5. Verify It's Running
# Check container status
docker-compose ps
# Should show:
# NAME STATUS PORTS
# meta_timescaledb Up (healthy) 0.0.0.0:5555->5432/tcp
# meta_api_grabber Up
# meta_grafana Up 0.0.0.0:3555->3000/tcp
6. Let It Run Overnight
The service will:
- ✅ Collect "today" data every 2 hours
- ✅ Detect when a new day starts
- ✅ Fetch "yesterday" data immediately when new day is detected
- ✅ Update "yesterday" data every 12 hours
- ✅ Auto-refresh the access token before it expires
- ✅ Restart automatically if it crashes (
restart: unless-stopped)
Token Auto-Refresh
How It Works
The system uses MetaTokenManager which:
- On startup: Checks if token expires within 7 days
- If expiring soon: Exchanges current token for a new long-lived token
- Saves new token: Updates both
.envand.meta_token.json - Every cycle: Re-checks token validity before fetching data
Token Lifecycle
New Token (via OAuth)
↓
60 days validity
↓
Day 53 (7 days before expiry)
↓
Auto-refresh triggered
↓
New 60-day token issued
↓
Cycle repeats indefinitely ♾️
What If Token Expires?
If the token somehow expires (e.g., manual revocation):
- Container will error out immediately with clear message
- Logs will show:
❌ Fatal error - Token validation failed - Container stops (won't waste API calls)
- You'll see it in:
docker-compose logs meta-grabber
To fix:
- Stop the container:
docker-compose stop meta-grabber - Get new token:
uv run python -m meta_api_grabber.auth - Restart:
docker-compose up -d meta-grabber
Data Collection Schedule
Normal Operation (Same Day)
00:00 - Cycle 1: Fetch "today" (2025-10-21)
02:00 - Cycle 2: Fetch "today" (2025-10-21)
04:00 - Cycle 3: Fetch "today" (2025-10-21)
...
22:00 - Cycle 12: Fetch "today" (2025-10-21)
When New Day Starts
00:00 - Cycle 13:
- Fetch "today" (2025-10-22) ← New date detected!
- 📅 New day detected: 2025-10-21 -> 2025-10-22
- Fetch "yesterday" (2025-10-21) immediately
02:00 - Cycle 14:
- Fetch "today" (2025-10-22)
- Skip "yesterday" (< 12h since last fetch)
...
12:00 - Cycle 19:
- Fetch "today" (2025-10-22)
- Update "yesterday" (12h passed since last fetch)
Checking Data in Database
Connect to Database
# From host machine
docker exec -it meta_timescaledb psql -U meta_user -d meta_insights
# Or using psql directly
psql -h localhost -p 5555 -U meta_user -d meta_insights
# Password: meta_password
Query Today's Data
SELECT
time,
account_id,
date_preset,
date_start,
impressions,
spend
FROM account_insights
WHERE date_preset = 'today'
ORDER BY time DESC
LIMIT 10;
Query Yesterday's Data
SELECT
time,
account_id,
date_preset,
date_start,
impressions,
spend
FROM account_insights
WHERE date_preset = 'yesterday'
ORDER BY time DESC
LIMIT 10;
Check Last Collection Time
SELECT
date_preset,
MAX(fetched_at) as last_fetch,
COUNT(*) as total_records
FROM account_insights
GROUP BY date_preset;
Stopping and Restarting
Stop Everything
docker-compose down
This stops all containers but preserves data:
- ✅ Database data (in volume
timescale_data) - ✅ Token files (mounted from host:
.env,.meta_token.json) - ✅ Grafana dashboards (in volume
grafana_data)
Stop Just the Grabber
docker-compose stop meta-grabber
Restart the Grabber
docker-compose restart meta-grabber
View Logs
# Follow logs in real-time
docker-compose logs -f meta-grabber
# Last 100 lines
docker-compose logs --tail=100 meta-grabber
# All services
docker-compose logs -f
Configuration
Adjusting Collection Interval
Edit scheduled_grabber.py line 522:
await grabber.run_scheduled(
interval_hours=2.0, # ← Change this (in hours)
refresh_metadata_every_n_cycles=12,
)
Then rebuild:
docker-compose up -d --build meta-grabber
Adjusting Number of Accounts
Edit scheduled_grabber.py line 519:
grabber = ScheduledInsightsGrabber(
max_accounts=3, # ← Change this (None = all accounts)
)
Adjusting Yesterday Fetch Interval
Currently hardcoded to 12 hours in _should_fetch_yesterday() method at line 175.
To change, edit:
return hours_since_last_fetch >= 12.0 # ← Change to 6.0 for 6 hours, etc.
Troubleshooting
Container Keeps Restarting
# Check logs for error
docker-compose logs meta-grabber
# Common issues:
# 1. Token invalid → Get new token
# 2. Database not ready → Wait for timescaledb health check
# 3. Missing .env file → Create from .env.example
No Data Being Collected
# Check if grabber is running
docker-compose ps
# Check logs for API errors
docker-compose logs meta-grabber | grep "Error"
# Verify token
uv run python -m meta_api_grabber.token_manager
Database Connection Failed
# Check if TimescaleDB is healthy
docker-compose ps timescaledb
# Should show: "Up (healthy)"
# If not healthy, check TimescaleDB logs
docker-compose logs timescaledb
Yesterday Data Not Appearing
Check logs for:
📅 New day detected: YYYY-MM-DD -> YYYY-MM-DD
Fetching yesterday's data (first time)
If you don't see this, the system hasn't detected a new day yet.
To force a test:
- Stop grabber:
docker-compose stop meta-grabber - Manually insert yesterday data (see manual testing section)
- Restart:
docker-compose start meta-grabber
Manual Testing (Before Overnight Run)
Test Token Validity
# This will check token and auto-refresh if needed
uv run python -m meta_api_grabber.token_manager
Test Single Collection Cycle
# Run one cycle without Docker
uv run python -c "
import asyncio
from src.meta_api_grabber.scheduled_grabber import ScheduledInsightsGrabber
async def test():
grabber = ScheduledInsightsGrabber(max_accounts=1)
await grabber.db.connect()
await grabber.db.initialize_schema()
await grabber.load_ad_accounts()
await grabber.run_collection_cycle()
await grabber.db.close()
asyncio.run(test())
"
Verify Database Schema
docker exec -it meta_timescaledb psql -U meta_user -d meta_insights -c "\dt"
# Should show:
# account_insights
# campaign_insights
# adset_insights
# ad_accounts
# campaigns
# adsets
Monitoring in Production
Health Checks
The container has a built-in health check:
docker inspect meta_api_grabber | grep -A 5 Health
Resource Usage
# Monitor container resources
docker stats meta_api_grabber
Log Rotation
Logs are automatically rotated (see docker-compose.yml):
- Max size: 10MB per file
- Max files: 3
- Total max: ~30MB of logs
Backup Considerations
What to Backup
-
Database (most important):
docker exec meta_timescaledb pg_dump -U meta_user meta_insights > backup.sql -
Token files:
cp .env .env.backup cp .meta_token.json .meta_token.json.backup -
Configuration:
.envdocker-compose.yml
Restore from Backup
# Restore database
docker exec -i meta_timescaledb psql -U meta_user meta_insights < backup.sql
# Restore token files
cp .env.backup .env
cp .meta_token.json.backup .meta_token.json
# Restart
docker-compose restart meta-grabber
Production Checklist
Before leaving it running overnight:
- Fresh access token obtained (60 days validity)
.envfile has all required variables.meta_token.jsonexists with token metadatadocker-compose up -d --buildsucceeded- All containers show "Up" in
docker-compose ps - Logs show successful data collection
- Database contains data (
SELECT COUNT(*) FROM account_insights) - Token auto-refresh is enabled (
auto_refresh_token=True) - Restart policy is set (
restart: unless-stopped)
Summary
To deploy for overnight testing:
# 1. Get token
uv run python -m meta_api_grabber.auth
# 2. Start everything
docker-compose up -d --build
# 3. Verify it's working
docker-compose logs -f meta-grabber
# 4. Let it run!
# Come back tomorrow and check:
docker-compose logs meta-grabber | grep "New day detected"
The system will handle everything automatically:
- ✅ Data collection every 2 hours
- ✅ New day detection
- ✅ Yesterday data collection
- ✅ Token auto-refresh
- ✅ Auto-restart on failures
Sleep well! 😴