snapshot of https://github.com/makeplane/plane.git @ d868349a55de79979eb8b98701bf1702c67ad634 (2026-09-15)
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:14:58 +05:00
commit 23059a1de3
5252 changed files with 573834 additions and 0 deletions

View File

@@ -0,0 +1,25 @@
# Copyright (c) 2023-present Plane Software, Inc. and contributors
# SPDX-License-Identifier: AGPL-3.0-only
# See the LICENSE file for details.
"""
Core utilities for Plane database routing and request scoping.
This package contains essential components for managing read replica routing
and request-scoped context in the Plane application.
"""
from .dbrouters import ReadReplicaRouter
from .mixins import ReadReplicaControlMixin
from .request_scope import (
set_use_read_replica,
should_use_read_replica,
clear_read_replica_context,
)
__all__ = [
"ReadReplicaRouter",
"ReadReplicaControlMixin",
"set_use_read_replica",
"should_use_read_replica",
"clear_read_replica_context",
]

View File

@@ -0,0 +1,75 @@
# Copyright (c) 2023-present Plane Software, Inc. and contributors
# SPDX-License-Identifier: AGPL-3.0-only
# See the LICENSE file for details.
"""
Database router for read replica selection.
This router determines which database to use for read/write operations
based on the request context set by the ReadReplicaRoutingMiddleware.
"""
import logging
from typing import Type
from django.db import models
from .request_scope import should_use_read_replica
logger = logging.getLogger("plane.db")
class ReadReplicaRouter:
"""
Database router that directs read operations to replica when appropriate.
This router works in conjunction with ReadReplicaRoutingMiddleware to:
- Route read operations to replica database when request context allows
- Always route write operations to primary database
- Ensure migrations only run on primary database
"""
def db_for_read(self, model: Type[models.Model], **hints) -> str:
"""
Determine which database to use for read operations.
Args:
model: The Django model class being queried
**hints: Additional routing hints
Returns:
str: Database alias ('replica' or 'default')
"""
if should_use_read_replica():
logger.debug(f"Routing read for {model._meta.label} to replica database")
return "replica"
else:
logger.debug(f"Routing read for {model._meta.label} to primary database")
return "default"
def db_for_write(self, model: Type[models.Model], **hints) -> str:
"""
Determine which database to use for write operations.
All write operations always go to the primary database to ensure
data consistency and avoid replication lag issues.
Args:
model: The Django model class being written to
**hints: Additional routing hints
Returns:
str: Always returns 'default' (primary database)
"""
logger.debug(f"Routing write for {model._meta.label} to primary database")
return "default"
def allow_migrate(self, db: str, app_label: str, model_name: str = None, **hints) -> bool:
"""
Ensure migrations only run on the primary database.
Args:
db: Database alias
app_label: Application label
model_name: Model name (optional)
**hints: Additional routing hints
Returns:
bool: True if migration is allowed on this database
"""
# Only allow migrations on the primary database
allowed = db == "default"
if not allowed:
logger.debug(f"Blocking migration for {app_label} on {db} database")
return allowed

View File

@@ -0,0 +1,15 @@
# Copyright (c) 2023-present Plane Software, Inc. and contributors
# SPDX-License-Identifier: AGPL-3.0-only
# See the LICENSE file for details.
"""
Core mixins for read replica functionality.
This package provides mixins for different aspects of read replica management
in Django and Django REST Framework applications.
"""
from .view import ReadReplicaControlMixin
__all__ = [
"ReadReplicaControlMixin",
]

View File

@@ -0,0 +1,24 @@
# Copyright (c) 2023-present Plane Software, Inc. and contributors
# SPDX-License-Identifier: AGPL-3.0-only
# See the LICENSE file for details.
"""
Mixins for Django REST Framework views.
"""
class ReadReplicaControlMixin:
"""
Mixin to control read replica usage in DRF views.
Set use_read_replica = True/False to route read operations to
replica/primary database. Works with ReadReplicaRoutingMiddleware.
Usage:
class MyViewSet(ReadReplicaControlMixin, ModelViewSet):
use_read_replica = True # Use replica for GET requests
Note:
- Only affects GET, HEAD, OPTIONS requests
- Write operations always use primary database
- Defaults to True for safe replica usage
"""
use_read_replica: bool = True

View File

@@ -0,0 +1,76 @@
# Copyright (c) 2023-present Plane Software, Inc. and contributors
# SPDX-License-Identifier: AGPL-3.0-only
# See the LICENSE file for details.
"""
Database routing utilities for read replica selection.
This module provides request-scoped context management for database routing,
specifically for determining when to use read replicas vs primary database.
Used in conjunction with middleware and DRF views that set use_read_replica=True.
The context is maintained per request to ensure proper isolation between
concurrent requests in async environments.
"""
from asgiref.local import Local
__all__ = [
"set_use_read_replica",
"should_use_read_replica",
"clear_read_replica_context",
]
# Request-scoped context storage for database routing preferences
# Uses asgiref.local.Local which provides ContextVar under the hood
# This ensures proper context isolation per request in async environments
_db_routing_context = Local()
def set_use_read_replica(use_replica: bool) -> None:
"""
Mark the current request context to use read replica database.
This function sets a request-scoped flag that determines database routing.
The context is isolated per request to ensure thread safety in async environments.
This function is typically called from:
- Middleware that detects read-only operations
- DRF views with use_read_replica=True attribute
- API endpoints that only perform read operations
Args:
use_replica (bool): True to route database queries to read replica,
False to use primary database
Note:
The context is automatically isolated per request and should be
cleared at the end of each request using clear_read_replica_context().
"""
_db_routing_context.use_read_replica = bool(use_replica)
def should_use_read_replica() -> bool:
"""
Check if the current request should use read replica database.
This function reads the request-scoped context to determine database routing.
It's called by the database router to decide which connection to use.
Returns:
bool: True if queries should be routed to read replica,
False if they should use primary database (default)
Note:
Returns False by default if no context is set for the current request.
The context is automatically isolated per request.
"""
return getattr(_db_routing_context, "use_read_replica", False)
def clear_read_replica_context() -> None:
"""
Clear the read replica context for the current request.
This function should be called at the end of each request to ensure
that context doesn't leak between requests. Typically called from
middleware during request cleanup.
This is important for:
- Preventing context leakage between requests
- Ensuring clean state for each new request
- Proper memory management in long-running processes
"""
try:
delattr(_db_routing_context, "use_read_replica")
except AttributeError:
pass