update the docker-compose
This commit is contained in:
parent
d8c349f4fb
commit
2026e0fbfb
12
README.md
12
README.md
@ -46,8 +46,8 @@ A FastAPI application with Docker and docker-compose support.
|
||||
BOXAPI_LOG_DIR=/app/logs/boxapi
|
||||
BOXAPI_LOG_LEVEL=all # or "error" for production
|
||||
|
||||
# Redis for pagination (optional but recommended)
|
||||
REDIS_URL=redis://localhost:6379/0
|
||||
# Redis for pagination (optional but recommended)
|
||||
REDIS_URL=redis://redis:6379/0 # Use 'redis' hostname in Docker
|
||||
```
|
||||
|
||||
2. **Build and start the application:**
|
||||
@ -191,6 +191,7 @@ The application uses environment variables for configuration. Copy `env.example`
|
||||
|
||||
### Redis Configuration (for pagination)
|
||||
- `REDIS_URL`: Redis connection URL (default: `redis://localhost:6379/0`)
|
||||
- **Note**: Redis is optional but recommended for pagination. If Redis is not available, the system will work without pagination (posts may be duplicated on subsequent calls).
|
||||
|
||||
### Database Configuration
|
||||
- `POSTGRES_DB`: Database name (default: `fastapi_db`)
|
||||
@ -290,6 +291,13 @@ The application includes health checks that can be accessed at:
|
||||
- Check if PostgreSQL container is running: `docker-compose ps`
|
||||
- Check database logs: `docker-compose logs postgres`
|
||||
|
||||
5. **Redis connection issues:**
|
||||
- Redis is optional - the system will work without it (posts may be duplicated)
|
||||
- If you want Redis: `docker-compose up redis` to start Redis service
|
||||
- Check Redis logs: `docker-compose logs redis`
|
||||
- For Docker: use `REDIS_URL=redis://redis:6379/0`
|
||||
- For local development: use `REDIS_URL=redis://localhost:6379/0`
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
|
||||
@ -16,6 +16,8 @@ services:
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: service_healthy
|
||||
redis:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
@ -45,9 +47,24 @@ services:
|
||||
networks:
|
||||
- fastapi-network
|
||||
|
||||
redis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
networks:
|
||||
- fastapi-network
|
||||
|
||||
networks:
|
||||
fastapi-network:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
redis_data:
|
||||
@ -1,22 +1,64 @@
|
||||
# utils/seen_store.py
|
||||
import os, redis
|
||||
from typing import Iterable
|
||||
from typing import Iterable, Optional
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
REDIS_URL = os.environ.get("REDIS_URL", "redis://localhost:6379/0")
|
||||
r = redis.from_url(REDIS_URL, decode_responses=True)
|
||||
_redis_client: Optional[redis.Redis] = None
|
||||
|
||||
def _get_redis_client() -> Optional[redis.Redis]:
|
||||
"""Get Redis client with error handling"""
|
||||
global _redis_client
|
||||
if _redis_client is not None:
|
||||
return _redis_client
|
||||
|
||||
try:
|
||||
_redis_client = redis.from_url(REDIS_URL, decode_responses=True)
|
||||
# Test the connection
|
||||
_redis_client.ping()
|
||||
logger.info("✅ Redis connection established")
|
||||
return _redis_client
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ Redis connection failed: {e}")
|
||||
logger.warning("📝 Pagination will be disabled - posts may be duplicated")
|
||||
_redis_client = None
|
||||
return None
|
||||
|
||||
def seen_key(username: str) -> str:
|
||||
return f"ig:seen:{username}"
|
||||
|
||||
def mark_seen(username: str, ids: Iterable[str]) -> None:
|
||||
if not ids: return
|
||||
r.sadd(seen_key(username), *ids)
|
||||
"""Mark posts as seen (Redis optional)"""
|
||||
if not ids:
|
||||
return
|
||||
|
||||
r = _get_redis_client()
|
||||
if r is None:
|
||||
return # Skip if Redis is not available
|
||||
|
||||
try:
|
||||
r.sadd(seen_key(username), *ids)
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ Failed to mark posts as seen: {e}")
|
||||
|
||||
def filter_unseen(username: str, ids: Iterable[str]) -> list[str]:
|
||||
# pipeline for speed
|
||||
key = seen_key(username)
|
||||
pipe = r.pipeline()
|
||||
for i in ids:
|
||||
pipe.sismember(key, i)
|
||||
flags = pipe.execute()
|
||||
return [i for i, seen in zip(ids, flags) if not seen]
|
||||
"""Filter out already seen posts (Redis optional)"""
|
||||
r = _get_redis_client()
|
||||
if r is None:
|
||||
# If Redis is not available, return all IDs (no filtering)
|
||||
return list(ids)
|
||||
|
||||
try:
|
||||
# pipeline for speed
|
||||
key = seen_key(username)
|
||||
pipe = r.pipeline()
|
||||
for i in ids:
|
||||
pipe.sismember(key, i)
|
||||
flags = pipe.execute()
|
||||
return [i for i, seen in zip(ids, flags) if not seen]
|
||||
except Exception as e:
|
||||
logger.warning(f"⚠️ Failed to filter unseen posts: {e}")
|
||||
# Fallback: return all IDs if Redis fails
|
||||
return list(ids)
|
||||
Loading…
Reference in New Issue
Block a user