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_REQUESTerror (-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
idare 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
resultfield - Error response: Contains
errorobject withcode(integer),message(string), and optionaldatafield - All responses include
jsonrpc: "2.0"andidmatching 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 requestctx.method_name: Name of the RPC method being calledctx.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) tupleheaders: Request headerscookies: Request cookiessession: 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 loggingINFO- Connection events, application errorsWARNING- Invalid requests, unexpected dataERROR- 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 JSONINVALID_REQUEST- Automatically raised for malformed JSON-RPC requestsMETHOD_NOT_FOUND- Automatically raised when method doesn't existINVALID_PARAMS- Use for parameter validation failuresINTERNAL_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 exceededPARSE_RESULT_ERROR- Result serialization failures
Best Practices:
- Use standard codes when appropriate - The JSON-RPC 2.0 spec codes cover most common scenarios
- Include data field - Provide context about what went wrong
- Don't leak secrets - Never include passwords, tokens, or internal paths in error data
- 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 startsrpc_method_completed- Method completes successfullyrpc_method_failed- Method raises errorrpc_client_connected- WebSocket client connectsrpc_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_RPCDjango 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
RpcMiddlewareprotocol - Example middleware:
LoggingMiddlewarefor 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_classattribute 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 metadatadescribe_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
JsonRpcErrorCodeIntEnum
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
idfield (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:
AsyncRpcHttpConsumerclassRPC_ERROR_TO_HTTP_CODEmapping- Individual error code constant exports
Migration:
- Use
AsyncJsonRpcWebsocketConsumerinstead ofAsyncRpcHttpConsumer - Import
JsonRpcErrorCodeenum 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_asyncfromchannels.dbfor 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_LARGEerror - 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
- Always set
SANITIZE_ERRORS: Truein production - Prevents information disclosure - Never set
LOG_RPC_PARAMS: Truein production - May log PII/credentials - Validate all inputs - Use
INVALID_PARAMSfor invalid data - Implement connection limits - Prevent resource exhaustion (see QSpace example)
- Use HTTPS/WSS - Never expose WebSocket endpoints over unencrypted connections
- Implement authentication - Use middleware or
@permission_requireddecorator - Monitor error rates - Use signals to track
rpc_method_failedevents
Performance Recommendations
- Use async consumers - Better concurrency and timeout support
- Cache method introspection - Already done automatically (31x speedup)
- Implement connection pooling - For database connections in async methods
- Monitor promise cleanup - Track periodic cleanup in logs
- 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.
Metadata
Release files for channels-rpc 1.0.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| channels_rpc-1.0.1.tar.gz | 50.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| channels_rpc-1.0.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 100.5 kB
Release files / channels_rpc-1.0.1.tar.gz
| Download URL | channels_rpc-1.0.1.tar.gz |
|---|---|
| Size | 50.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7336637836eff893e1dbc87506d7e9549f1b9d544dca3277809f28fbf006a9a3
|
|
BLAKE2b-256 checksum How to use checksums |
4b2132330be0359b509f5354576f6271ce78294e628e3bb7f2354478b13d80fc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.3 CPython/3.10.6 Linux/6.5.0-1024-aws
|
Release files / channels_rpc-1.0.1-py3-none-any.whl
| Download URL | channels_rpc-1.0.1-py3-none-any.whl |
|---|---|
| Size | 50.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
80d4ac266ee90041523a961b5c11d583f8eeac24dae7730e0374793fbd1e0fe0
|
|
BLAKE2b-256 checksum How to use checksums |
d8ea3ae0c43aafd3a01ab0f8994dc88757a3d1450d7e45bd371add20870b8129
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/2.1.3 CPython/3.10.6 Linux/6.5.0-1024-aws
|