Skip to main content

JSON-RPC implementation for Django's channels library.

Project description

channels-rpc

channels-rpc enables JSON-RPC 2.0 functionality on top of Django Channels WebSockets with strict protocol compliance, type safety, and production-ready features.

Features

  • Strict JSON-RPC 2.0 compliance - Fully implements the JSON-RPC 2.0 specification
  • Django Channels integration - Built on Django Channels for WebSocket support
  • Type safety - Comprehensive type hints with mypy validation (0 type errors)
  • Security - DoS protection with request size limits, no information leakage
  • Performance - Optimized with cached introspection (31x faster method execution)
  • WebSocket only - Focused on real-time bidirectional communication (HTTP removed in 1.0.0)
  • Easy integration - Simple decorator-based API
  • Django settings - Runtime configuration via Django settings (new in 1.0.0)
  • Lifecycle signals - Monitor RPC calls with Django signals (new in 1.0.0)
  • Middleware support - Extensible middleware pipeline for cross-cutting concerns (new in 1.0.0)
  • Custom serialization - Support for custom JSON encoders (new in 1.0.0)
  • Permission control - Decorator-based authorization with Django permissions (new in 1.0.0)
  • API introspection - Discover methods, signatures, and documentation at runtime (new in 1.0.0)
  • Well tested - 363 tests with 88% coverage

JSON-RPC 2.0 Compliance

channels-rpc implements the JSON-RPC 2.0 specification with strict protocol adherence.

Supported Features

Version Checking

  • Only "jsonrpc": "2.0" is accepted
  • Other versions are rejected with INVALID_REQUEST error (-32600)
  • Validation enforced in channels_rpc/rpc_base.py

Request Format

  • Required fields: jsonrpc (string), method (string)
  • Optional fields: params (object or array), id (string, number, or null)
  • Notification requests: Requests without id are treated as notifications (no response sent)
// Method call (expects response)
{
    "jsonrpc": "2.0",
    "method": "subtract",
    "params": {"minuend": 42, "subtrahend": 23},
    "id": 1
}

// Notification (no response)
{
    "jsonrpc": "2.0",
    "method": "notify",
    "params": {"message": "hello"}
}

Response Format

  • Success response: Contains result field
  • Error response: Contains error object with code (integer), message (string), and optional data field
  • All responses include jsonrpc: "2.0" and id matching the request
// Success
{"jsonrpc": "2.0", "result": 19, "id": 1}

// Error
{
    "jsonrpc": "2.0",
    "error": {
        "code": -32601,
        "message": "Method Not Found: 'nonexistent'",
        "data": {"method": "nonexistent"}
    },
    "id": 1
}

Parameter Formats

  • Named parameters (object): "params": {"name": "value"}
  • Positional parameters (array): "params": [1, 2, 3]
  • Empty/omitted: Both "params": {} and omitted params field are valid

Error Codes

Standard JSON-RPC 2.0 error codes (defined in channels_rpc/exceptions.py):

Code Constant Meaning
-32700 PARSE_ERROR Invalid JSON received
-32600 INVALID_REQUEST JSON is not a valid Request object
-32601 METHOD_NOT_FOUND Method does not exist
-32602 INVALID_PARAMS Invalid method parameters
-32603 INTERNAL_ERROR Internal JSON-RPC error

Server-defined error codes (-32099 to -32000):

Code Constant Meaning
-32000 GENERIC_APPLICATION_ERROR Generic application error (deprecated, use specific codes)
-32001 REQUEST_TOO_LARGE Request exceeds size limits
-32701 PARSE_RESULT_ERROR Error serializing result

Request Size Limits

To prevent denial-of-service attacks, the following limits are enforced (see channels_rpc/limits.py):

  • MAX_MESSAGE_SIZE: 10MB per message
  • MAX_ARRAY_LENGTH: 10,000 items in params array
  • MAX_STRING_LENGTH: 1MB per string parameter
  • MAX_NESTING_DEPTH: 20 levels of nested objects/arrays
  • MAX_METHOD_NAME_LENGTH: 256 characters

Requests exceeding these limits return REQUEST_TOO_LARGE error (-32001).

NOT Supported

Batch Requests

Batch requests (arrays of multiple JSON-RPC requests) are intentionally not supported. Each WebSocket message must contain a single JSON-RPC request or notification.

// NOT SUPPORTED - will be rejected
[
    {"jsonrpc": "2.0", "method": "sum", "params": [1, 2], "id": 1},
    {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 2}
]

To execute multiple methods, send separate WebSocket messages for each request.

Installation

$ pip install git+ssh://git@github.com/quantivly/channels-rpc.git

Use

It is intended to be used as a WebSocket consumer. Use the async consumer AsyncJsonRpcWebsocketConsumer:

from channels_rpc import AsyncJsonRpcWebsocketConsumer

class MyJsonRpcConsumer(AsyncJsonRpcWebsocketConsumer):

    async def connect(self):
        """Perform things on WebSocket connection start"""
        await self.accept()
        print("connect")
        # Do stuff if needed

    async def disconnect(self, code):
        """Perform things on WebSocket connection close"""
        print("disconnect")
        # Do stuff if needed

AsyncJsonRpcWebsocketConsumer derives from channels AsyncJsonWebsocketConsumer. Then, the last step is to create the RPC method hooks using the rpc_method decorator:

@MyJsonRpcConsumer.rpc_method()
async def ping():
    return "pong"

Or, with a custom name:

@MyJsonRpcConsumer.rpc_method("mymodule.rpc.ping")
async def ping():
    return "pong"

Will now be callable with "method":"mymodule.rpc.ping" in the rpc call:

{
    "id":1,
    "jsonrpc":"2.0",
    "method":"mymodule.rpc.ping",
    "params":{}
}

RPC methods can obviously accept parameters. They also return "results" or "errors":

@MyJsonRpcConsumer.rpc_method("mymodule.rpc.ping")
async def ping(fake_an_error):
    if fake_an_error:
        # Will return an error to the client
        #  --> {"id":1, "jsonrpc":"2.0","method":"mymodule.rpc.ping","params":{}} #  <-- {"id": 1, "jsonrpc": "2.0", "error": {"message": "fake_error", "code": -32000, "data": ["fake_error"]}}  raise Exception("fake_error")
    else:
        # Will return a result to the client
        #  --> {"id":1, "jsonrpc":"2.0","method":"mymodule.rpc.ping","params":{}} #  <-- {"id": 1, "jsonrpc": "2.0", "result": "pong"}  return "pong"

Accessing Consumer and Request Context

RPC methods can access the consumer instance, request metadata, and Django Channels scope through the RpcContext parameter. When a method's first parameter (after self for bound methods) is typed as RpcContext, it will be automatically injected during execution.

from channels_rpc import RpcContext

@MyJsonRpcConsumer.rpc_method()
async def json_rpc_method(ctx: RpcContext, param1: str):
    # Access the consumer instance
    consumer = ctx.consumer

    # Access Django Channels scope (sessions, user, etc.)
    session = ctx.scope.get("session", {})

    # Access request metadata
    method_name = ctx.method_name  # "json_rpc_method"
    rpc_id = ctx.rpc_id  # Request ID from JSON-RPC call
    is_notification = ctx.is_notification  # False for methods, True for notifications

    # Do something with the context
    return f"Hello {param1}"

Complete Example:

from channels_rpc import AsyncJsonRpcWebsocketConsumer, RpcContext

class MyJsonRpcConsumer(AsyncJsonRpcWebsocketConsumer):
    pass

@MyJsonRpcConsumer.rpc_method()
async def ping(ctx: RpcContext):
    # Access session through context
    ctx.scope["session"]["test"] = True

    # Log the request
    print(f"Ping called with ID {ctx.rpc_id}")

    return "pong"

@MyJsonRpcConsumer.rpc_method()
async def get_user_info(ctx: RpcContext):
    # Access authenticated user from scope
    user = ctx.scope.get("user")
    if user and user.is_authenticated:
        return {
            "username": user.username,
            "email": user.email
        }
    return {"error": "Not authenticated"}

Available Context Attributes:

  • ctx.consumer: The consumer instance handling the RPC request
  • ctx.method_name: Name of the RPC method being called
  • ctx.rpc_id: Request ID from the JSON-RPC call (None for notifications)
  • ctx.is_notification: Whether this is a notification (no response expected)
  • ctx.scope: Django Channels scope dict containing:
    • client: (host, port) tuple
    • headers: Request headers
    • cookies: Request cookies
    • session: Django session (if http_user enabled)
    • user: Authenticated user (if http_user enabled)

Testing

The JsonRpcConsumer class can be tested the same way Channels Consumers are tested. See here

Logging Configuration

channels-rpc uses Python's logging module with the logger name "channels_rpc". Configure it in your Django settings:

# settings.py
LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'verbose': {
            'format': '{levelname} {asctime} {module} {message}',
            'style': '{',
        },
    },
    'handlers': {
        'console': {
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        },
    },
    'loggers': {
        'channels_rpc': {
            'handlers': ['console'],
            'level': 'INFO',  # Use 'DEBUG' for detailed RPC call logging
            'propagate': False,
        },
    },
}

Log Levels:

  • DEBUG - Detailed RPC method execution, parameter logging
  • INFO - Connection events, application errors
  • WARNING - Invalid requests, unexpected data
  • ERROR - Internal errors (should not occur in production)

Security Features

Request Size Limits (DoS Protection)

channels-rpc enforces size limits to prevent denial-of-service attacks:

  • MAX_MESSAGE_SIZE: 10MB per message
  • MAX_ARRAY_LENGTH: 10,000 items in params array
  • MAX_STRING_LENGTH: 1MB per string parameter
  • MAX_NESTING_DEPTH: 20 levels of nested objects
  • MAX_METHOD_NAME_LENGTH: 256 characters

These limits are enforced automatically. Oversized requests return a JsonRpcErrorCode.REQUEST_TOO_LARGE error.

Error Response Sanitization

Error responses never leak internal details:

  • Generic exceptions return sanitized messages
  • Stack traces are logged but not sent to clients
  • Parameter validation errors include only safe context

Scope Validation

Call self.validate_scope() in your connect() method to validate WebSocket connection metadata:

from channels_rpc import AsyncJsonRpcWebsocketConsumer

class MyJsonRpcConsumer(AsyncJsonRpcWebsocketConsumer):
    async def connect(self):
        self.validate_scope()  # Validates scope structure
        await self.accept()

Error Handling

channels-rpc uses an IntEnum for error codes:

from channels_rpc import JsonRpcErrorCode, JsonRpcError

# Standard JSON-RPC 2.0 error codes
JsonRpcErrorCode.PARSE_ERROR          # -32700
JsonRpcErrorCode.INVALID_REQUEST      # -32600
JsonRpcErrorCode.METHOD_NOT_FOUND     # -32601
JsonRpcErrorCode.INVALID_PARAMS       # -32602
JsonRpcErrorCode.INTERNAL_ERROR       # -32603

# Server-defined error codes
JsonRpcErrorCode.GENERIC_APPLICATION_ERROR  # -32000
JsonRpcErrorCode.REQUEST_TOO_LARGE          # -32001
JsonRpcErrorCode.PARSE_RESULT_ERROR         # -32701

Raise JsonRpcError in your RPC methods for controlled error responses:

from channels_rpc import JsonRpcError, JsonRpcErrorCode

@MyConsumer.rpc_method()
def my_method(value):
    if value < 0:
        raise JsonRpcError(
            rpc_id=None,  # Will be filled automatically
            code=JsonRpcErrorCode.INVALID_PARAMS,
            data={"field": "value", "constraint": "must be non-negative"}
        )
    return value * 2

Error Code Usage Guide

Choose the appropriate error code to help clients handle errors correctly:

Standard Protocol Errors - Automatically generated:

  • PARSE_ERROR - Automatically raised by framework for invalid JSON
  • INVALID_REQUEST - Automatically raised for malformed JSON-RPC requests
  • METHOD_NOT_FOUND - Automatically raised when method doesn't exist
  • INVALID_PARAMS - Use for parameter validation failures
  • INTERNAL_ERROR - Internal server errors

Application Errors:

  • GENERIC_APPLICATION_ERROR - Generic application-level errors (deprecated, prefer specific custom codes)
  • REQUEST_TOO_LARGE - Automatically raised when size limits exceeded
  • PARSE_RESULT_ERROR - Result serialization failures

Best Practices:

  1. Use standard codes when appropriate - The JSON-RPC 2.0 spec codes cover most common scenarios
  2. Include data field - Provide context about what went wrong
  3. Don't leak secrets - Never include passwords, tokens, or internal paths in error data
  4. Be consistent - Use the same error codes for similar failures across your API

Example:

from channels_rpc import JsonRpcError, JsonRpcErrorCode, RpcContext

@MyConsumer.rpc_method()
async def update_user(ctx: RpcContext, user_id: int, email: str):
    # Input validation failure
    if not validate_email(email):
        raise JsonRpcError(
            ctx.rpc_id,
            JsonRpcErrorCode.INVALID_PARAMS,
            data={"field": "email", "error": "Invalid format"}
        )

    # Application-level error
    try:
        user = await User.objects.aget(id=user_id)
    except User.DoesNotExist:
        raise JsonRpcError(
            ctx.rpc_id,
            JsonRpcErrorCode.GENERIC_APPLICATION_ERROR,
            data={"resource": "user", "id": user_id}
        )

    user.email = email
    await user.asave()
    return {"success": True}

Configuration

Configure channels-rpc via Django settings under the CHANNELS_RPC key:

# settings.py
CHANNELS_RPC = {
    # Size limits for DoS protection (all optional, defaults shown)
    'MAX_MESSAGE_SIZE': 10 * 1024 * 1024,  # 10MB
    'MAX_ARRAY_LENGTH': 10000,
    'MAX_STRING_LENGTH': 1024 * 1024,  # 1MB
    'MAX_NESTING_DEPTH': 20,
    'MAX_METHOD_NAME_LENGTH': 256,

    # Logging configuration
    'LOG_RPC_PARAMS': False,  # Set True only in development (may expose PII)
    'SANITIZE_ERRORS': True,  # Always sanitize errors in responses
}

Access configuration programmatically:

from channels_rpc.config import get_config

config = get_config()
print(config.limits.max_message_size)  # 10485760

Middleware

Middleware provides a way to add cross-cutting concerns to RPC request/response handling:

from channels_rpc import AsyncJsonRpcWebsocketConsumer

class LoggingMiddleware:
    def process_request(self, data, consumer):
        print(f"RPC call: {data.get('method')}")
        return data

    def process_response(self, response, consumer):
        print(f"RPC response: {response.get('id')}")
        return response

class MyConsumer(AsyncJsonRpcWebsocketConsumer):
    # Middleware applied in order
    middleware = [
        LoggingMiddleware(),
        # Add more middleware...
    ]

Built-in Middleware (in channels_rpc.middleware):

  • LoggingMiddleware - Example middleware that logs RPC calls with timing

Middleware Patterns (see examples/comprehensive_example.py):

  • Custom middleware implementation
  • Request/response processing
  • Authentication and logging patterns

Signals

Monitor RPC lifecycle with Django signals:

from channels_rpc.signals import rpc_method_started, rpc_method_completed, rpc_method_failed
import logging

logger = logging.getLogger(__name__)

def log_rpc_call(sender, method_name, duration, **kwargs):
    logger.info(f"RPC {method_name} completed in {duration:.3f}s")

def alert_on_error(sender, method_name, error, **kwargs):
    logger.error(f"RPC {method_name} failed: {error}")

rpc_method_completed.connect(log_rpc_call)
rpc_method_failed.connect(alert_on_error)

Available signals:

  • rpc_method_started - Method execution starts
  • rpc_method_completed - Method completes successfully
  • rpc_method_failed - Method raises error
  • rpc_client_connected - WebSocket client connects
  • rpc_client_disconnected - WebSocket client disconnects

Permission-Based Access Control

Restrict RPC methods with Django permissions:

from channels_rpc import AsyncJsonRpcWebsocketConsumer, RpcContext
from channels_rpc.decorators import permission_required

class MyConsumer(AsyncJsonRpcWebsocketConsumer):
    pass

@MyConsumer.rpc_method()
@permission_required('myapp.can_delete_users')
async def delete_user(ctx: RpcContext, user_id: int):
    # Only users with permission can call this
    User.objects.get(id=user_id).delete()
    return {'deleted': True}

@MyConsumer.rpc_method()
@permission_required('myapp.view_reports', 'myapp.export_data')
async def export_report(ctx: RpcContext, report_id: int):
    # User must have BOTH permissions
    return generate_report(report_id)

Security Note: Unauthorized calls return METHOD_NOT_FOUND (not auth error) to prevent method enumeration.

Custom JSON Encoder

Serialize custom types (datetime, Decimal, dataclasses):

import json
from datetime import datetime
from decimal import Decimal
from channels_rpc import AsyncJsonRpcWebsocketConsumer

class CustomEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        if isinstance(obj, Decimal):
            return float(obj)
        return super().default(obj)

class MyConsumer(AsyncJsonRpcWebsocketConsumer):
    json_encoder_class = CustomEncoder

@MyConsumer.rpc_method()
async def get_data():
    return {
        'timestamp': datetime.now(),  # Serialized as ISO string
        'amount': Decimal('123.45'),  # Serialized as float
    }

API Introspection

Discover available methods and generate documentation:

# List all methods
methods = MyConsumer.get_rpc_methods()
# ['add', 'subtract', 'get_user']

# Get detailed method info
info = MyConsumer.get_method_info('get_user')
# MethodInfo(
#     name='get_user',
#     signature='(ctx: RpcContext, user_id: int) -> dict',
#     docstring='Get user by ID...',
#     accepts_context=True,
#     transport_options={'websocket': True}
# )

# Generate complete API description (OpenRPC-compatible)
api_doc = MyConsumer.describe_api()
# {
#     'methods': [...],
#     'notifications': [...],
#     'consumer_class': 'MyConsumer'
# }

What's New in 1.0.0

New Features

🎯 Django Settings Integration

  • Configure size limits, logging, and behavior via CHANNELS_RPC Django setting
  • Runtime configuration without code changes
  • See Configuration section

📡 Lifecycle Signals

  • Monitor RPC calls with 5 Django signals: rpc_method_started, rpc_method_completed, rpc_method_failed, rpc_client_connected, rpc_client_disconnected
  • Integrate with APM tools (DataDog, New Relic, etc.)
  • Track performance metrics and errors
  • See Signals section

🔌 Middleware Support

  • Extensible middleware pipeline for cross-cutting concerns
  • Protocol-based middleware system via RpcMiddleware protocol
  • Example middleware: LoggingMiddleware for call tracking
  • Middleware patterns in examples/comprehensive_example.py
  • See Middleware section

Note: Rate limiting, connection limits, and request tracking are application-level concerns in channels-rpc. The library provides the middleware framework and examples, but implementations are application-specific. For production deployments, see QSpace server's implementation as a reference.

🔧 Custom JSON Encoder

  • Support for custom JSON encoders (datetime, Decimal, dataclasses, etc.)
  • Set json_encoder_class attribute on consumer
  • Automatic fallback to str() for non-serializable objects

🔐 Permission-Based Access Control

  • @permission_required() decorator for Django permission integration
  • Automatic authorization checking before method execution
  • Security-first design (returns METHOD_NOT_FOUND to prevent enumeration)

🔍 API Introspection

  • get_method_info(method_name) - Get detailed method metadata
  • describe_api() - Generate OpenRPC-compatible API descriptions
  • Runtime method discovery for documentation generation

📊 Comprehensive Error Handling

  • Standard JSON-RPC 2.0 error codes (PARSE_ERROR, INVALID_REQUEST, METHOD_NOT_FOUND, INVALID_PARAMS, INTERNAL_ERROR)
  • Server-defined error codes (GENERIC_APPLICATION_ERROR, REQUEST_TOO_LARGE, PARSE_RESULT_ERROR)
  • Type-safe JsonRpcErrorCode IntEnum

Performance Improvements

  • 31x faster method execution - Cached introspection eliminates reflection overhead on every call
  • Optimized logging - Lazy evaluation prevents unnecessary string formatting
  • Reduced code duplication - Eliminated 150+ lines of duplicate decorator code
  • Pre-parse size validation - Prevents DoS attacks by checking size before JSON parsing

Type Safety

  • Zero mypy errors - Comprehensive type hints throughout
  • Protocol classes - Proper typing for Django Channels mixin methods
  • IntEnum error codes - Type-safe error code handling with IDE autocomplete
  • RpcContext dataclass - Type-safe context parameter

Security Enhancements

  • DoS protection - Pre-parse message size validation
  • Sanitized error responses - Never leak internal details to clients
  • Specific exception handling - RuntimeError no longer masked (indicates bugs)
  • Protocol compliance - Fixed critical JSON-RPC 2.0 violations (null ID handling)

Code Quality

  • 363 tests with 88% coverage (+119 new tests)
  • Pre-commit hooks with mypy, ruff, black, isort
  • Clean public API - Explicit __all__ exports
  • Eliminated duplication - Shared decorator logic in decorators.py

Breaking Changes in 1.0.0

1. HTTP Parameter Removed from Decorators

The http parameter has been completely removed from all decorators.

Old:

@MyConsumer.rpc_method(websocket=True, http=False)
def my_method():
    ...

New:

@MyConsumer.rpc_method(websocket=True)
def my_method():
    ...

Migration: Remove the http parameter from all decorator calls.

2. Logger Name Changed

The logger name changed from "django.channels.rpc" to "channels_rpc" to follow Django conventions.

Old Django settings:

LOGGING = {
    'loggers': {
        'django.channels.rpc': {  # Old name
            'handlers': ['console'],
            'level': 'DEBUG',
        },
    },
}

New Django settings:

LOGGING = {
    'loggers': {
        'channels_rpc': {  # New name
            'handlers': ['console'],
            'level': 'DEBUG',
        },
    },
}

3. Null ID Now Requires Response

Fixed JSON-RPC 2.0 compliance: "id": null now correctly requires a response (not treated as notification).

Behavior change:

  • Notification: Request WITHOUT id field (no response)
  • Request with null ID: Request WITH "id": null (must receive response)

This is a protocol fix - the previous behavior was non-compliant.

4. Error Codes Now Use IntEnum

Old:

from channels_rpc import INVALID_REQUEST, METHOD_NOT_FOUND
error = JsonRpcError(rpc_id, INVALID_REQUEST)

New:

from channels_rpc import JsonRpcErrorCode
error = JsonRpcError(rpc_id, JsonRpcErrorCode.INVALID_REQUEST)

5. Consumer Context via RpcContext (Recommended)

While **kwargs still works, the recommended approach is using RpcContext:

Old (still works but deprecated):

@MyConsumer.rpc_method()
async def get_user(**kwargs):
    consumer = kwargs.get('consumer')
    user = consumer.scope.get('user')

New (recommended):

from channels_rpc import RpcContext

@MyConsumer.rpc_method()
async def get_user(ctx: RpcContext):
    user = ctx.scope.get('user')

6. HTTP Transport Removed

The HTTP transport has been removed. This library now focuses exclusively on WebSocket transport.

What was removed:

  • AsyncRpcHttpConsumer class
  • RPC_ERROR_TO_HTTP_CODE mapping
  • Individual error code constant exports

Migration:

  • Use AsyncJsonRpcWebsocketConsumer instead of AsyncRpcHttpConsumer
  • Import JsonRpcErrorCode enum instead of individual constants
  • Update routing to use WebSocket endpoints

7. Exception Handling Changed

RuntimeError is no longer caught as an application error (it indicates bugs).

Impact: RuntimeError exceptions will now be logged as internal errors instead of application errors. Migration: If your code intentionally raises RuntimeError for application logic, use ValueError or TypeError instead.

Production Deployment

Configuration Checklist

For production deployments, ensure these settings are properly configured:

# settings.py (PRODUCTION)
CHANNELS_RPC = {
    # Size limits - adjust based on your use case
    'MAX_MESSAGE_SIZE': 10 * 1024 * 1024,  # 10MB default

    # Security - always enabled in production
    'SANITIZE_ERRORS': True,  # Never leak stack traces
    'LOG_RPC_PARAMS': False,  # Never log params (may contain PII)
}

Failure Modes and Graceful Degradation

Scenario: Database Unavailable

  • Methods accessing Django ORM will fail
  • Use database_sync_to_async from channels.db for safe database access in async methods
  • Mitigation: Implement database connection pooling and read replicas

Scenario: Redis (Channel Layer) Unavailable

  • WebSocket connections will fail to establish
  • Existing connections may experience message delivery delays
  • Mitigation: Use Redis Sentinel or Cluster for high availability

Scenario: Middleware Errors

  • Request middleware errors: Returns INTERNAL_ERROR, request rejected
  • Response middleware errors: Original response sent, error logged
  • Mitigation: Test middleware thoroughly, handle exceptions internally

Scenario: Method Execution Timeout

  • Async methods: Timeout enforced via @rpc_method(timeout=60)
  • Sync methods: No timeout enforcement (limitation)
  • Mitigation: Use async consumers for timeout guarantees

Scenario: Message Size Limit Exceeded

  • Request rejected with REQUEST_TOO_LARGE error
  • Connection remains open, client can retry with smaller payload
  • Mitigation: Implement chunking/pagination at application level

Scenario: Rate Limit Exceeded (Application-Level)

  • Implementation-specific (see QSpace server for reference)
  • Generally: Request rejected with custom application error
  • Mitigation: Implement exponential backoff in clients

Security Best Practices

  1. Always set SANITIZE_ERRORS: True in production - Prevents information disclosure
  2. Never set LOG_RPC_PARAMS: True in production - May log PII/credentials
  3. Validate all inputs - Use INVALID_PARAMS for invalid data
  4. Implement connection limits - Prevent resource exhaustion (see QSpace example)
  5. Use HTTPS/WSS - Never expose WebSocket endpoints over unencrypted connections
  6. Implement authentication - Use middleware or @permission_required decorator
  7. Monitor error rates - Use signals to track rpc_method_failed events

Performance Recommendations

  1. Use async consumers - Better concurrency and timeout support
  2. Cache method introspection - Already done automatically (31x speedup)
  3. Implement connection pooling - For database connections in async methods
  4. Monitor promise cleanup - Track periodic cleanup in logs
  5. Set appropriate size limits - Balance security vs functionality

Why These Changes

These changes improve protocol compliance, type safety, maintainability, and align with Django best practices. The library is now production-ready for high-scale deployments while eliminating technical debt.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

channels_rpc-1.0.1.tar.gz (50.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

channels_rpc-1.0.1-py3-none-any.whl (50.5 kB view details)

Uploaded Python 3

File details

Details for the file channels_rpc-1.0.1.tar.gz.

File metadata

  • Download URL: channels_rpc-1.0.1.tar.gz
  • Upload date:
  • Size: 50.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.10.6 Linux/6.5.0-1024-aws

File hashes

Hashes for channels_rpc-1.0.1.tar.gz
Algorithm Hash digest
SHA256 7336637836eff893e1dbc87506d7e9549f1b9d544dca3277809f28fbf006a9a3
MD5 8854ad0fda496235ea33bd0958e37cb7
BLAKE2b-256 4b2132330be0359b509f5354576f6271ce78294e628e3bb7f2354478b13d80fc

See more details on using hashes here.

File details

Details for the file channels_rpc-1.0.1-py3-none-any.whl.

File metadata

  • Download URL: channels_rpc-1.0.1-py3-none-any.whl
  • Upload date:
  • Size: 50.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: poetry/2.1.3 CPython/3.10.6 Linux/6.5.0-1024-aws

File hashes

Hashes for channels_rpc-1.0.1-py3-none-any.whl
Algorithm Hash digest
SHA256 80d4ac266ee90041523a961b5c11d583f8eeac24dae7730e0374793fbd1e0fe0
MD5 41312027787d5deb2dcdf2aa0856c070
BLAKE2b-256 d8ea3ae0c43aafd3a01ab0f8994dc88757a3d1450d7e45bd371add20870b8129

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page