ZCore LogoZCore
Core concepts

Configuration & Context Management

Deep dive into how ZCore handles application settings via lazy proxies and isolates request-scoped state using contextvars.

One of the most critical challenges in asynchronous web frameworks is managing state safely across concurrent requests. ZCore provides two foundational primitives for this: SettingsProxy for global application settings and ZContext for thread-safe, coroutine-aware request state.


1. The Settings Proxy (Lazy Resolution)

In standard Python applications, importing settings modules at the top of files often causes circular dependency errors or triggers premature database engine instantiation before the application is ready.

ZCore solves this using SettingsProxy.

Under the Hood: When you execute from zcore import settings, you are not importing a static instance. You are importing a lightweight SettingsProxy object. This proxy intercepts all attribute lookups (via __getattr__) and dynamically resolves the active Settings singleton from the IoCContainer only when an attribute is actually accessed.

This guarantees that settings.DATABASE.url, settings.DATABASE_URL, or settings.SECRET_KEY can be safely imported anywhere in your codebase without premature execution.

Structured Settings Schemas & Subsystems

Settings in ZCore are structured into dedicated sub-models and framework-wide parameters:

  • DATABASE (DatabaseSettings): Manages connection URL, pool sizing (pool_size, max_overflow), connection recycles (pool_recycle), health checks (pool_pre_ping), and engine parameters (connect_args, execution_options, extra_engine_kwargs).
  • LOGGING (LoggingSettings): Manages log levels, formatters (json_format), SQL query logging (log_sql_queries), slow query thresholds (slow_query_threshold_ms), rotating file logs (file_path), file rotation bounds (max_bytes, backup_count), and muted loggers (muted_loggers).
  • Timezone Policies: Global timezone configurations (TIMEZONE="UTC") and automatic ISO serialization conversions (AUTO_CONVERT_TIMEZONE=True).

Framework-Wide Tunable Parameters

ZCore exposes centralized, environment-driven boundaries across all framework subsystems:

SubsystemSetting KeyDefaultDescription
PaginationPAGINATION_DEFAULT_SIZE20Fallback page size when omitted in requests.
PaginationPAGINATION_MAX_SIZE100Hard upper bound enforced on page size parameters.
SearchSEARCH_MAX_DEPTH3Maximum allowed depth for nested filters and relation eager-loading.
AuthenticationAUTH_CACHE_TTL300 (5 min)Lifespan of cached user sessions in BaseAuth.
CacheCACHE_DEFAULT_TTL3600 (1 hour)Default fallback TTL for BaseCache.set().
CacheCACHE_LOCAL_MAXSIZE1000Maximum capacity of the local in-memory TTLLRUCache.
CacheCACHE_EVICTION_INTERVAL60Duration in seconds between background memory cleanup sweeps.
StreamingSTREAM_QUEUE_MAXSIZE100Bounded capacity for user real-time streaming queues in StreamManager.

Bidirectional Sync: ZCore maintains backward compatibility by automatically synchronizing flat environment variables (such as DATABASE_URL, POOL_SIZE, MAX_OVERFLOW, and LOG_LEVEL) with their corresponding structured DATABASE and LOGGING models.

Extending Settings

ZCore automatically binds your Settings instance into the IoC container. To add domain-specific variables or configure structured sub-models, inherit from Settings and pass the instance to initialize_settings at the top of your main.py:

# main.py
from zcore.config import DatabaseSettings, LoggingSettings, Settings, initialize_settings

class AppSettings(Settings):
    AWS_BUCKET: str = "default-bucket"
    EXTERNAL_API_KEY: str = ""
    DATABASE: DatabaseSettings = DatabaseSettings(
        url="postgresql+asyncpg://postgres:postgres@localhost:5432/production_db",
        pool_size=20,
    )
    LOGGING: LoggingSettings = LoggingSettings(
        level="DEBUG",
        slow_query_threshold_ms=200.0,
        max_bytes=20 * 1024 * 1024,
        backup_count=10,
    )

# Register the subclass into ZCore's IoC container
initialize_settings(AppSettings())

2. ZContext (Request-State Isolation)

FastAPI processes thousands of concurrent async requests within a single event loop. Storing request state (such as the active user's identity or tenant ID) in global variables causes race conditions where concurrent requests overwrite each other's data.

ZCore provides ZContext (ctx), an asynchronous execution context store built directly on Python's native contextvars.

How Contextvars Work in ZCore

  1. When an HTTP connection hits RequestLogMiddleware, ZCore calls ctx.initialize(), creating an isolated memory dictionary tied to that specific coroutine execution tree.
  2. During the request lifecycle, authentication and authorization layers attach state to ctx.
  3. When the HTTP response finishes, ctx.reset(token) is triggered in a finally block, releasing the memory cleanly.
Incoming HTTP Request ctx.initialize BaseAuth binds user_id & restricted_fields Business Logic & Zchema Projection ctx.reset token HTTP Response Sent

Strongly-Typed Properties

Instead of relying on unstructured dictionary strings, ZContext exposes strongly-typed, validated properties:

  • ctx.user_id: Stores the authenticated user identifier as Any | None. As of rc.2, it seamlessly supports arbitrary identifier formats (such as auto-incrementing integers, UUIDs, or external strings like Auth0/Firebase IDs) without enforcing rigid type constraints.
  • ctx.restricted_fields: Managed as an immutable frozenset. Once loaded during authentication, business logic cannot accidentally mutate restriction paths mid-flight.

Dynamic Context Operations

from zcore import ctx

# Store arbitrary request-scoped data
ctx.set("tenant_id", "enterprise_001")

# Retrieve values with optional fallbacks
tenant = ctx.get("tenant_id", default="public")

# Delete specific keys
ctx.remove("tenant_id")

Temporary Context Scoping (ctx.scope)

If you need to temporarily override context values for a specific block of logic (e.g., executing a background task as a System User or impersonating an account), use the ctx.scope() context manager:

from zcore import ctx

async def perform_system_migration():
    # Temporarily override user_id and scopes within this block
    with ctx.scope(user_id=SYSTEM_BOT_UUID, scopes=["system:admin"]):
        # All services, repos, and logs inside this block see the System Bot identity
        await run_migration_task()
        
    # The context automatically reverts to its original caller state here

Security Assurance: ZContext variables do not bleed across async task boundaries. Each concurrent coroutine maintains absolute state isolation.

On this page