Configuration
Complete reference for all Singularity configuration options — Settings fields, Celery configuration, database pool tuning, logging levels, and Redis connection settings.
Singularity uses Pydantic Settings for configuration management. All settings are loaded from environment variables or a .env file at the project root.
Settings Class
config.settings.Settings
The Settings class inherits from pydantic_settings.BaseSettings. A module-level singleton settings is created at import time and shared across the entire application.
from singularity.config import settings
# Access any field
db_url = settings.database_url
env = settings.environmentSettings Fields
| Field | Type | Default | Description |
|---|---|---|---|
environment | str | "dev" | Application environment (ENVIRONMENT). Accepted values: dev, beta, prod. Controls logging levels and worker pool type. |
database_url | str | "postgresql+asyncpg://...localhost:5432/postgres" | PostgreSQL connection URL (DATABASE_URL). Must use the asyncpg driver for async support. |
celery_broker_url | str | "redis://localhost:6379/0" | Redis URL for the Celery message broker (CELERY_BROKER_URL). Also used for RPC spec publishing, heartbeat, and WebSocket notification pub/sub. |
celery_result_backend | str | "redis://localhost:6379/0" | Redis URL for Celery task result storage (CELERY_RESULT_BACKEND). |
jwt_secret | str | "dummy_value" | Secret key for JWT token signing and verification (JWT_SECRET). |
rpc_base_url | str | "http://localhost:8000" | Base URL remote callers use to reach this deployment (RPC_BASE_URL). Published to Redis for discovery, and combined with the app's prefix to build endpoint URLs. |
rpc_timeout | float | 30.0 | Timeout in seconds for outbound remote RPC calls (RPC_TIMEOUT). |
rpc_heartbeat_interval | int | 30 | Seconds between Redis re-registration and peer re-scan (RPC_HEARTBEAT_INTERVAL). |
rpc_spec_ttl | int | 60 | TTL in seconds on published RPC specs (RPC_SPEC_TTL). Keep it above the heartbeat interval, or peers will briefly disappear between beats. |
rpc_api_key | str | "" | Key sent as X-API-Key on outbound RPC calls (RPC_API_KEY). |
rpc_api_keys | str | "" | Comma-separated keys accepted on inbound RPC calls (RPC_API_KEYS). Falls back to rpc_api_key when empty. |
rpc_require_api_key | bool | False | Reject inbound RPC requests without a valid X-API-Key (RPC_REQUIRE_API_KEY). See Securing Inbound RPC. |
Pydantic Config
| Setting | Type | Default | Description |
|---|---|---|---|
env_file | str | ".env" | Path to the environment file |
env_file_encoding | str | "utf-8" | Encoding of the environment file |
Example .env File
ENVIRONMENT=dev
DATABASE_URL=postgresql+asyncpg://user:password@localhost:5432/mydb
CELERY_BROKER_URL=redis://localhost:6379/0
CELERY_RESULT_BACKEND=redis://localhost:6379/1
JWT_SECRET=your-secret-key-here
RPC_BASE_URL=http://localhost:8000
RPC_TIMEOUT=30
RPC_HEARTBEAT_INTERVAL=30
RPC_SPEC_TTL=60
# Set on both sides to authenticate calls between deployments
RPC_API_KEY=
RPC_REQUIRE_API_KEY=falseThe default values for database_url, celery_broker_url, and jwt_secret are placeholder values. Always set these via environment variables or .env in any non-local environment.
Adding Custom Settings
Extend the Settings class in singularity/config.py to add your own fields:
class Settings(BaseSettings):
# ... existing fields ...
# Custom fields
stripe_api_key: str = ""
stripe_webhook_secret: str = ""
max_upload_size: int = 10_485_760 # 10MB
billing_host_url: str = "http://localhost:8001"
billing_api_key: str = ""All custom fields automatically support environment variable loading. The env var name is the uppercased field name (e.g. STRIPE_API_KEY).
Celery Configuration
common.q
Celery is configured in singularity/common/q.py. The configuration is applied via celery_app.conf.update().
Configuration Keys
| Key | Value | Description |
|---|---|---|
task_serializer | "json" | Serialization format for task messages |
accept_content | ["json"] | Accepted content types for deserialization |
result_serializer | "json" | Serialization format for task results |
timezone | "UTC" | Timezone for Celery scheduling |
enable_utc | True | Use UTC for all timestamps |
task_track_started | True | Track when tasks transition to the STARTED state |
task_time_limit | 3600 | Global hard timeout in seconds (1 hour) |
worker_pool | "threads" / "prefork" | Worker pool implementation. Uses threads in dev for easier debugging, prefork in other environments. |
worker_concurrency | 2 | Default number of concurrent workers |
worker_prefetch_multiplier | 1 | Number of messages to prefetch per worker. Set to 1 for fair task distribution. |
beat_scheduler | "redbeat.RedBeatScheduler" | Redis-backed beat scheduler for schedule persistence across restarts |
redbeat_redis_url | settings.celery_broker_url | Redis URL for RedBeat schedule storage |
redbeat_key_prefix | "celery:beat:" | Key prefix for RedBeat entries in Redis |
broker_connection_retry_on_startup | True | Retry broker connection if unavailable at startup |
beat_schedule | {} | Periodic task schedule (empty by default; add entries as needed) |
The singularity tasks worker CLI command lets you override worker_pool (--pool) and worker_concurrency (--concurrency) at runtime without changing the configuration file.
Database Pool Configuration
database.postgres
Singularity configures two SQLAlchemy engines: an async engine for FastAPI endpoints and a sync engine for Celery tasks.
Async Engine (FastAPI)
| Option | Value | Description |
|---|---|---|
poolclass | AsyncAdaptedQueuePool | Async-compatible connection pool |
pool_size | 20 | Maximum number of persistent connections in the pool |
pool_timeout | 3600 | Seconds to wait for a connection from the pool before raising an error |
pool_pre_ping | True | Issue a SELECT 1 before reusing a connection to verify it is still alive |
echo | False | Disable SQL statement logging |
Sync Engine (Celery Workers)
| Option | Value | Description |
|---|---|---|
poolclass | QueuePool | Standard synchronous connection pool |
pool_size | 100 | Maximum number of persistent connections |
max_overflow | 200 | Maximum number of connections beyond pool_size allowed temporarily |
pool_timeout | 30 | Seconds to wait for a connection from the pool |
pool_pre_ping | True | Verify connections before reuse |
echo | False | Disable SQL statement logging |
Session Configuration
Both session factories use expire_on_commit=False to allow access to object attributes after a commit without requiring a refresh.
# Async session (for services)
async_session = async_sessionmaker[AsyncSession](async_engine, class_=AsyncSession, expire_on_commit=False)
# Sync session (for Celery tasks)
sync_session = sessionmaker[Session](sync_engine, class_=Session, expire_on_commit=False)get_db() Dependency
The get_db() async generator is available as a FastAPI dependency for direct use in route handlers:
from singularity.db import get_db
@router.get("/users")
async def list_users(db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User))
return result.scalars().all()The sync database URL is derived automatically from settings.database_url by replacing postgresql+asyncpg:// with postgresql://. No separate env var is needed.
Logging Configuration
common.logger
Singularity uses Loguru for structured logging. The logging level and targets are determined by the environment setting.
Logging Levels per Environment
| dev | beta | prod | |
|---|---|---|---|
| Level | DEBUG | DEBUG | INFO |
| Targets | stderr + file | stderr | stderr |
| Details | Console + logs/app.log (10 MB rotation) | Console-only debug logging | Console-only, info level and above |
Usage
from singularity.common.logger import log as logger
# Structured logging
logger.info("Task completed", task_name="send_email", duration_ms=150)
logger.error("Payment failed", order_id="123", error="Insufficient funds")
logger.debug("RPC call", caller="orders", target="payments", method="charge")Loguru supports rich contextual logging via keyword arguments. Each key-value pair becomes a structured field in the log output.
Redis Connection Settings
Redis is used for three purposes in Singularity:
| Purpose | Config Field | Redis Key Pattern |
|---|---|---|
| Celery broker (task queue) | celery_broker_url | Managed by Celery |
| Celery result backend | celery_result_backend | Managed by Celery |
| RPC service discovery | celery_broker_url | singularity:rpc:services:{name}, singularity:rpc:spec |
| RedBeat scheduler | celery_broker_url | celery:beat:* |
| WebSocket notifications | celery_broker_url | Pub/sub channel: task_notifications |
All Redis connections currently share the same URL (celery_broker_url). If you need to separate them (e.g. different Redis instances for broker vs. RPC), you can add additional fields to the Settings class and update the relevant modules.
RPC Redis Keys
| Key | TTL | Content | Set By |
|---|---|---|---|
singularity:rpc:services:{name} | 60s | JSON spec for a single service (base_url, blacklist, methods) | RPCRegistry.publish_to_redis() |
singularity:rpc:spec | 60s | Full RPC spec for all local services | RPCRegistry.publish_to_redis() |
RPC Heartbeat
| Setting | Value | Description |
|---|---|---|
| Interval | 30 seconds | How often the heartbeat refreshes Redis keys |
| TTL | 60 seconds | Time-to-live for each Redis key |
| Disable flag | --no-heartbeat | CLI flag on app.py that sets SINGULARITY_NO_HEARTBEAT=1 |
If the heartbeat is disabled, RPC keys will expire after 60 seconds and remote services will no longer be discoverable.
Environment Variable Summary
Complete list of all environment variables recognized by Singularity:
| Variable | Type | Default | Used By |
|---|---|---|---|
ENVIRONMENT | str | "dev" | Settings, Logger, Celery pool selection |
DATABASE_URL | str | (required) | SQLAlchemy engines (async + sync) |
CELERY_BROKER_URL | str | (required) | Celery, RPC Redis, RedBeat, WebSocket notifications |
CELERY_RESULT_BACKEND | str | (required) | Celery result storage |
JWT_SECRET | str | (required) | JWT authentication |
RPC_BASE_URL | str | "http://localhost:8000" | RPC spec generation, endpoint prefix |
SINGULARITY_NO_HEARTBEAT | str | (unset) | Set to "1" to disable the RPC heartbeat (set automatically by --no-heartbeat) |