Skip to content

Commit c6474c9

Browse files
committed
Add lite mode: optional Redis and Celery dependencies
- Session backend falls back to SQLAlchemy when Redis unavailable - Celery only initializes when installed and configured - Move redis/celery to [full] optional dependencies - Zero-config startup with uv sync && flask run
1 parent 2101842 commit c6474c9

File tree

5 files changed

+74
-48
lines changed

5 files changed

+74
-48
lines changed

enferno/app.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,9 @@ def clear_workspace_on_login(sender, user, **extra):
6161
if debug_toolbar:
6262
debug_toolbar.init_app(app)
6363

64-
# Session initialization
64+
# Session initialization - pass db for SQLAlchemy sessions
65+
if app.config.get("SESSION_TYPE") == "sqlalchemy":
66+
app.config["SESSION_SQLALCHEMY"] = db
6567
session.init_app(app)
6668

6769
babel.init_app(

enferno/settings.py

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
1+
import importlib.util
12
import os
23
from datetime import timedelta
34

45
import bleach
5-
import redis
66
from dotenv import load_dotenv
77

8+
# Detect optional dependencies (installed via --extra full)
9+
REDIS_AVAILABLE = importlib.util.find_spec("redis") is not None
10+
811
os_env = os.environ
912
load_dotenv()
1013

14+
# Session configuration - computed at module level
15+
_redis_url = os.environ.get("REDIS_URL") or os.environ.get("REDIS_SESSION")
16+
if REDIS_AVAILABLE and _redis_url:
17+
import redis # type: ignore[import-not-found]
18+
19+
_SESSION_TYPE = "redis"
20+
_SESSION_REDIS = redis.from_url(_redis_url)
21+
else:
22+
_SESSION_TYPE = "sqlalchemy"
23+
_SESSION_REDIS = None
24+
1125

1226
def uia_username_mapper(identity):
1327
# Sanitize and strip whitespace from email input - Flask-Security handles case insensitivity
@@ -28,9 +42,10 @@ class Config:
2842
# SQLALCHEMY_DATABASE_URI = os.environ.get('SQLALCHEMY_DATABASE_URI', 'postgresql:///enferno')
2943
SQLALCHEMY_TRACK_MODIFICATIONS = True
3044

31-
CELERY_BROKER_URL = os.environ.get("CELERY_BROKER_URL", "redis://localhost:6379/2")
32-
CELERY_RESULT_BACKEND = os.environ.get(
33-
"CELERY_RESULT_BACKEND", "redis://localhost:6379/3"
45+
# Celery configuration - only set if Redis available and configured
46+
CELERY_BROKER_URL = os.environ.get("CELERY_BROKER_URL") if REDIS_AVAILABLE else None
47+
CELERY_RESULT_BACKEND = (
48+
os.environ.get("CELERY_RESULT_BACKEND") if REDIS_AVAILABLE else None
3449
)
3550

3651
# security
@@ -83,11 +98,10 @@ class Config:
8398

8499
SESSION_PROTECTION = "strong"
85100

86-
# Session configuration
87-
SESSION_TYPE = "redis"
88-
SESSION_REDIS = redis.from_url(
89-
os.environ.get("REDIS_SESSION", "redis://localhost:6379/1")
90-
)
101+
# Session configuration - uses module-level computed values
102+
SESSION_TYPE = _SESSION_TYPE
103+
SESSION_REDIS = _SESSION_REDIS
104+
SESSION_SQLALCHEMY_TABLE = "sessions"
91105
SESSION_KEY_PREFIX = "session:"
92106
SESSION_USE_SIGNER = True
93107
PERMANENT_SESSION_LIFETIME = 3600

enferno/tasks/__init__.py

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,37 @@
1-
from celery import Celery
1+
import importlib.util
22

3-
from enferno.settings import Config as cfg
3+
# Detect optional dependencies
4+
CELERY_AVAILABLE = importlib.util.find_spec("celery") is not None
45

5-
celery = Celery(
6-
"enferno.tasks",
7-
broker=cfg.CELERY_BROKER_URL,
8-
backend=cfg.CELERY_RESULT_BACKEND,
9-
broker_connection_retry_on_startup=True,
10-
)
6+
celery = None
117

12-
celery.conf.add_defaults(cfg)
8+
if CELERY_AVAILABLE:
9+
from celery import Celery # type: ignore[import-not-found]
1310

11+
from enferno.settings import Config as cfg
1412

15-
class ContextTask(celery.Task):
16-
abstract = True
13+
# Only initialize Celery if broker is configured
14+
if cfg.CELERY_BROKER_URL:
15+
celery = Celery(
16+
"enferno.tasks",
17+
broker=cfg.CELERY_BROKER_URL,
18+
backend=cfg.CELERY_RESULT_BACKEND,
19+
broker_connection_retry_on_startup=True,
20+
)
1721

18-
def __call__(self, *args, **kwargs):
19-
from enferno.app import create_app
22+
celery.conf.add_defaults(cfg)
2023

21-
with create_app(cfg).app_context():
22-
return super().__call__(*args, **kwargs)
24+
class ContextTask(celery.Task):
25+
abstract = True
2326

27+
def __call__(self, *args, **kwargs):
28+
from enferno.app import create_app
2429

25-
celery.Task = ContextTask
30+
with create_app(cfg).app_context():
31+
return super().__call__(*args, **kwargs)
2632

33+
celery.Task = ContextTask
2734

28-
@celery.task
29-
def task():
30-
pass
35+
@celery.task
36+
def task():
37+
pass

pyproject.toml

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ dependencies = [
3939
"webauthn>=2.6.0",
4040
"cffi>=1.17.1",
4141
"pycparser>=2.22",
42-
# Task queue and caching
43-
"celery>=5.5.3",
44-
"redis>=6.2.0",
45-
"amqp>=5.3.1",
46-
"kombu>=5.5.4",
47-
"vine>=5.1.0",
4842
# Utilities and data handling
4943
"email-validator>=2.2.0",
5044
"python-dotenv>=1.1.1",
@@ -72,6 +66,13 @@ dependencies = [
7266
]
7367

7468
[project.optional-dependencies]
69+
full = [
70+
"redis>=7.1.0",
71+
"celery>=5.5.3",
72+
"kombu>=5.5.4",
73+
"amqp>=5.3.1",
74+
"vine>=5.1.0",
75+
]
7576
dev = [
7677
# Code formatting and linting
7778
"ruff",

uv.lock

Lines changed: 15 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)