Skip to content

Commit ac51128

Browse files
refactor: manage enforcer state within class when app is ready
1 parent cb10b9a commit ac51128

2 files changed

Lines changed: 45 additions & 9 deletions

File tree

openedx_authz/apps.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,9 @@ class OpenedxAuthzConfig(AppConfig):
3939
},
4040
},
4141
}
42+
43+
def ready(self):
44+
"""Initialization layer for the openedx_authz app."""
45+
from openedx_authz.engine.enforcer import AuthzEnforcer
46+
# Initialize the enforcer to ensure it's ready when the app starts
47+
AuthzEnforcer()

openedx_authz/engine/enforcer.py

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,48 @@
2121
from casbin import FastEnforcer
2222
from django.conf import settings
2323

24+
from openedx_authz.engine import adapter
2425
from openedx_authz.engine.adapter import ExtendedAdapter
2526
from openedx_authz.engine.watcher import Watcher
2627

2728
logger = logging.getLogger(__name__)
2829

29-
adapter = ExtendedAdapter()
30-
enforcer = FastEnforcer(settings.CASBIN_MODEL, adapter, enable_log=True)
31-
enforcer.enable_auto_save(True)
3230

33-
if Watcher:
34-
try:
35-
enforcer.set_watcher(Watcher)
36-
logger.info("Watcher successfully set on Casbin enforcer")
37-
except Exception as e: # pylint: disable=broad-exception-caught
38-
logger.error(f"Failed to set watcher on Casbin enforcer: {e}")
31+
class AuthzEnforcer:
32+
"""Singleton class to manage the Casbin FastEnforcer instance.
33+
34+
Ensures a single enforcer instance is created safely and configured with the
35+
ExtendedAdapter and Redis watcher for policy management and synchronization.
36+
"""
37+
38+
enforcer = None
39+
40+
def __new__(cls):
41+
"""Singleton pattern to ensure a single enforcer instance."""
42+
if cls.enforcer is None:
43+
cls.enforcer = cls.initialize_enforcer()
44+
return cls.enforcer
45+
46+
def initialize_enforcer(self) -> FastEnforcer:
47+
"""
48+
Create and configure the Casbin FastEnforcer instance.
49+
50+
This function initializes the Casbin FastEnforcer with the ExtendedAdapter
51+
for database-backed policy storage and sets up the Redis watcher for
52+
real-time policy synchronization.
53+
54+
Returns:
55+
FastEnforcer: Configured Casbin enforcer with adapter and watcher
56+
"""
57+
adapter = ExtendedAdapter()
58+
enforcer = FastEnforcer(settings.CASBIN_MODEL, adapter, enable_log=True)
59+
enforcer.enable_auto_save(True)
60+
61+
if Watcher:
62+
try:
63+
enforcer.set_watcher(Watcher)
64+
logger.info("Watcher successfully set on Casbin enforcer")
65+
except Exception as e: # pylint: disable=broad-exception-caught
66+
logger.error(f"Failed to set watcher on Casbin enforcer: {e}")
67+
68+
return enforcer

0 commit comments

Comments
 (0)