Database Setup¶
Supported Databases¶
| Database | Minimum Version | Notes |
|---|---|---|
| PostgreSQL | 9.5 | Recommended |
| MySQL | 8.0.1 | Supported |
| SQLite | - | Not supported |
PostgreSQL Setup¶
Use separate credentials for schema migrations and for the runtime app/relay processes. The runtime role should not own the schema.
CREATE DATABASE myapp;
CREATE ROLE myapp_deploy LOGIN PASSWORD 'deploy-secret';
ALTER DATABASE myapp OWNER TO myapp_deploy;
CREATE ROLE myapp_runtime LOGIN PASSWORD 'runtime-secret' NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT;
GRANT CONNECT ON DATABASE myapp TO myapp_runtime;
Run python manage.py migrate with the deploy role, then grant the runtime DML needed by enqueue, relay, replay, and purge flows:
\c myapp
GRANT USAGE ON SCHEMA public TO myapp_runtime;
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE celery_outbox, celery_outbox_dead_letter TO myapp_runtime;
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO myapp_runtime;
ALTER DEFAULT PRIVILEGES FOR ROLE myapp_deploy IN SCHEMA public
GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO myapp_runtime;
ALTER DEFAULT PRIVILEGES FOR ROLE myapp_deploy IN SCHEMA public
GRANT USAGE, SELECT ON SEQUENCES TO myapp_runtime;
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'myapp',
'USER': 'myapp_runtime',
'PASSWORD': 'runtime-secret',
'HOST': 'localhost',
'PORT': '5432',
}
}
MySQL Setup¶
Use one role for migrations and a separate least-privilege role for runtime traffic.
CREATE DATABASE myapp CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'myapp_deploy'@'%' IDENTIFIED BY 'deploy-secret';
CREATE USER 'myapp_runtime'@'%' IDENTIFIED BY 'runtime-secret';
GRANT ALTER, CREATE, CREATE TEMPORARY TABLES, DELETE, DROP, INDEX, INSERT, REFERENCES, SELECT, UPDATE
ON myapp.* TO 'myapp_deploy'@'%';
GRANT SELECT, INSERT, UPDATE, DELETE
ON myapp.* TO 'myapp_runtime'@'%';
# settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'myapp',
'USER': 'myapp_runtime',
'PASSWORD': 'runtime-secret',
'HOST': 'localhost',
'PORT': '3306',
'OPTIONS': {
'charset': 'utf8mb4',
}
}
}
Multi-Database Setup¶
If using a separate database for the outbox:
# myapp/routers.py
class OutboxRouter:
def db_for_read(self, model, **hints):
if model._meta.app_label == 'django_celery_outbox':
return 'outbox'
return None
def db_for_write(self, model, **hints):
if model._meta.app_label == 'django_celery_outbox':
return 'outbox'
return None
Migrations¶
Run migrations with the deploy role, not the runtime role. Production runtime credentials should not own the schema or grant rights onward.
Creates two tables:
celery_outbox— Pending messagescelery_outbox_dead_letter— Failed messages