Skip to Content

gRPC Architecture & Design

This document explains the architecture and design patterns behind Django-CFG’s gRPC integration.

🏗️ System Architecture

High-Level Overview

🔄 Request Flow Architecture

Complete Request Lifecycle

Error Flow

🧩 Component Architecture

1. Interceptors Pipeline

Architecture Update (v1.5+): Interceptors have been consolidated into ObservabilityInterceptor to fix bidirectional streaming bugs. The old 5-layer architecture caused premature StopAsyncIteration after ~15 messages.

Why ObservabilityInterceptor?

Each interceptor wraps request_iterator in an async generator. With 5 separate interceptors, buffer backpressure caused premature StopAsyncIteration in bidirectional streaming after ~15 messages.

Solution: Consolidate all observability features into ONE interceptor with a SINGLE counting_iterator().

ObservabilityInterceptor Features

FeatureDescriptionConfiguration
MetricsRequest counts, response times, error ratesAlways ON
LoggingStructured console loggingAlways ON
DB LoggingGRPCRequestLog entriesobservability.log_to_db
CentrifugoWebSocket event publishingAuto-detected from config
Error HandlingMap exceptions to gRPC statusBuilt-in

Configuration

from django_cfg import GRPCConfig, GRPCObservabilityConfig grpc = GRPCConfig( enabled=True, observability=GRPCObservabilityConfig( log_to_db=True, # Enable DB logging log_streaming=False, # Don't log bidi streams (creates 'pending' entries) log_errors_only=False, # Log all requests, not just errors sampling_rate=1.0, # Log 100% of requests ), )

Key Design Decisions:

  1. Auth First - User context available for all observability features
  2. Single Observability Interceptor - Eliminates generator nesting bug
  3. Auto-Configuration - Centrifugo auto-detected from django-cfg config
  4. Streaming-Safe - No timeout on anext(), uses ping/keepalive instead

2. Service Discovery System

3. Base Service Classes Hierarchy

🔐 Authentication Architecture

API Key Flow

Public vs Protected Methods

📊 Monitoring Architecture

Request Logging System

Statistics & Metrics

🔄 Phase 4: Dynamic Invocation

Dynamic gRPC Client Architecture

Key Features:

  1. Service Discovery - Automatically discover all available services
  2. Method Introspection - Get method signatures and schemas
  3. Dynamic Message Creation - Create protobuf messages from JSON/dict
  4. No Proto Files Required - Use reflection to understand service contracts

Learn more: Dynamic Invocation Guide


🎯 Design Patterns

1. Interceptor Pattern

Purpose: Cross-cutting concerns (logging, auth, metrics) without modifying service code.

Implementation:

class MyInterceptor(grpc.ServerInterceptor): def intercept_service(self, continuation, handler_call_details): # Pre-processing # ... # Call next interceptor/service response = continuation(handler_call_details) # Post-processing # ... return response

2. Service Discovery Pattern

Purpose: Automatic registration of gRPC services from Django apps.

Key Components:

  • Module scanning (grpc_services.py, grpc_handlers.py)
  • Lazy loading support
  • Convention over configuration

3. Django Integration Pattern

Purpose: Seamless access to Django features in gRPC services.

Integration Points:

  • ORM via models
  • User authentication via API keys
  • Permissions via Django auth
  • Admin interface for monitoring
  • Signals for events

4. Error Mapping Pattern

Purpose: Convert Django exceptions to appropriate gRPC status codes.

Mapping:

Django Exception → gRPC Status Code ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ ValidationError → INVALID_ARGUMENT ObjectDoesNotExist → NOT_FOUND PermissionDenied → PERMISSION_DENIED NotImplementedError → UNIMPLEMENTED TimeoutError → DEADLINE_EXCEEDED Exception → INTERNAL

Bidirectional Streaming Architecture

For long-running bidirectional connections, use BidirectionalStreamingService:

Key Components

ComponentResponsibility
InputProcessorReads messages via anext(), routes to handlers
OutputProcessorSends commands and ping/pong messages
ConnectionManagerTracks client state, handles cleanup
ResponseRegistryMaps command IDs to pending responses

Critical Configuration

Never set connection_timeout - it causes premature StopAsyncIteration in grpcio. See Troubleshooting.

BidirectionalStreamingConfig( streaming_mode=StreamingMode.ANEXT, ping_strategy=PingStrategy.INTERVAL, ping_interval=5.0, ping_timeout=180.0, connection_timeout=None, # CRITICAL! )

Learn more: Streaming Patterns


Performance Considerations

Threading Model

Configuration:

GRPCServerConfig( max_workers=10, # Thread pool size # More workers = more concurrent requests # But higher memory usage )

Database Optimization

  • Connection Pooling - Reuse database connections
  • Select Related / Prefetch Related - Reduce N+1 queries
  • Indexed Fields - Fast lookups on service/method/status
  • Async Logging - Non-blocking request logging

Next: Learn how to get started with gRPC or explore streaming patterns.