django-cfg 1.4.62__py3-none-any.whl → 1.4.64__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of django-cfg might be problematic. Click here for more details.
- django_cfg/__init__.py +1 -1
- django_cfg/apps/accounts/services/otp_service.py +3 -14
- django_cfg/apps/centrifugo/__init__.py +57 -0
- django_cfg/apps/centrifugo/admin/__init__.py +13 -0
- django_cfg/apps/centrifugo/admin/centrifugo_log.py +249 -0
- django_cfg/apps/centrifugo/admin/config.py +82 -0
- django_cfg/apps/centrifugo/apps.py +31 -0
- django_cfg/apps/centrifugo/codegen/IMPLEMENTATION_SUMMARY.md +475 -0
- django_cfg/apps/centrifugo/codegen/README.md +242 -0
- django_cfg/apps/centrifugo/codegen/USAGE.md +616 -0
- django_cfg/apps/centrifugo/codegen/__init__.py +19 -0
- django_cfg/apps/centrifugo/codegen/discovery.py +246 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/__init__.py +5 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/generator.py +174 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/README.md.j2 +182 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/client.go.j2 +64 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/go.mod.j2 +10 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2 +300 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2.old +267 -0
- django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/types.go.j2 +16 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/__init__.py +7 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/generator.py +241 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/README.md.j2 +128 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/__init__.py.j2 +22 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/client.py.j2 +73 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/models.py.j2 +19 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/requirements.txt.j2 +8 -0
- django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/rpc_client.py.j2 +193 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/__init__.py +5 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/generator.py +124 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/README.md.j2 +38 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/client.ts.j2 +25 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/index.ts.j2 +12 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/package.json.j2 +13 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +137 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/tsconfig.json.j2 +14 -0
- django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/types.ts.j2 +9 -0
- django_cfg/apps/centrifugo/codegen/utils/__init__.py +37 -0
- django_cfg/apps/centrifugo/codegen/utils/naming.py +155 -0
- django_cfg/apps/centrifugo/codegen/utils/type_converter.py +349 -0
- django_cfg/apps/centrifugo/decorators.py +137 -0
- django_cfg/apps/centrifugo/management/__init__.py +1 -0
- django_cfg/apps/centrifugo/management/commands/__init__.py +1 -0
- django_cfg/apps/centrifugo/management/commands/generate_centrifugo_clients.py +254 -0
- django_cfg/apps/centrifugo/managers/__init__.py +12 -0
- django_cfg/apps/centrifugo/managers/centrifugo_log.py +264 -0
- django_cfg/apps/centrifugo/migrations/0001_initial.py +164 -0
- django_cfg/apps/centrifugo/migrations/__init__.py +3 -0
- django_cfg/apps/centrifugo/models/__init__.py +11 -0
- django_cfg/apps/centrifugo/models/centrifugo_log.py +210 -0
- django_cfg/apps/centrifugo/registry.py +106 -0
- django_cfg/apps/centrifugo/router.py +125 -0
- django_cfg/apps/centrifugo/serializers/__init__.py +40 -0
- django_cfg/apps/centrifugo/serializers/admin_api.py +264 -0
- django_cfg/apps/centrifugo/serializers/channels.py +26 -0
- django_cfg/apps/centrifugo/serializers/health.py +17 -0
- django_cfg/apps/centrifugo/serializers/publishes.py +16 -0
- django_cfg/apps/centrifugo/serializers/stats.py +21 -0
- django_cfg/apps/centrifugo/services/__init__.py +12 -0
- django_cfg/apps/centrifugo/services/client/__init__.py +29 -0
- django_cfg/apps/centrifugo/services/client/client.py +582 -0
- django_cfg/apps/centrifugo/services/client/config.py +236 -0
- django_cfg/apps/centrifugo/services/client/exceptions.py +212 -0
- django_cfg/apps/centrifugo/services/config_helper.py +63 -0
- django_cfg/apps/centrifugo/services/dashboard_notifier.py +157 -0
- django_cfg/apps/centrifugo/services/logging.py +677 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +260 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +313 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +803 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +333 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +432 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +33 -0
- django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +210 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +46 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +123 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +45 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +84 -0
- django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/stat_cards.html +23 -20
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +91 -0
- django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/tab_navigation.html +15 -15
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +415 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +61 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +58 -0
- django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +48 -0
- django_cfg/apps/centrifugo/templatetags/__init__.py +1 -0
- django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +81 -0
- django_cfg/apps/centrifugo/urls.py +31 -0
- django_cfg/apps/{ipc → centrifugo}/urls_admin.py +4 -4
- django_cfg/apps/centrifugo/views/__init__.py +15 -0
- django_cfg/apps/centrifugo/views/admin_api.py +380 -0
- django_cfg/apps/centrifugo/views/dashboard.py +15 -0
- django_cfg/apps/centrifugo/views/monitoring.py +286 -0
- django_cfg/apps/centrifugo/views/testing_api.py +422 -0
- django_cfg/apps/support/utils/support_email_service.py +5 -18
- django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -2
- django_cfg/apps/urls.py +5 -5
- django_cfg/core/base/config_model.py +4 -44
- django_cfg/core/builders/apps_builder.py +2 -2
- django_cfg/core/generation/integration_generators/third_party.py +8 -8
- django_cfg/core/utils/__init__.py +5 -0
- django_cfg/core/utils/url_helpers.py +73 -0
- django_cfg/modules/base.py +7 -7
- django_cfg/modules/django_client/core/__init__.py +2 -1
- django_cfg/modules/django_client/core/config/config.py +8 -0
- django_cfg/modules/django_client/core/generator/__init__.py +42 -2
- django_cfg/modules/django_client/core/generator/go/__init__.py +14 -0
- django_cfg/modules/django_client/core/generator/go/client_generator.py +124 -0
- django_cfg/modules/django_client/core/generator/go/files_generator.py +133 -0
- django_cfg/modules/django_client/core/generator/go/generator.py +203 -0
- django_cfg/modules/django_client/core/generator/go/models_generator.py +304 -0
- django_cfg/modules/django_client/core/generator/go/naming.py +193 -0
- django_cfg/modules/django_client/core/generator/go/operations_generator.py +134 -0
- django_cfg/modules/django_client/core/generator/go/templates/Makefile.j2 +38 -0
- django_cfg/modules/django_client/core/generator/go/templates/README.md.j2 +55 -0
- django_cfg/modules/django_client/core/generator/go/templates/client.go.j2 +122 -0
- django_cfg/modules/django_client/core/generator/go/templates/enums.go.j2 +49 -0
- django_cfg/modules/django_client/core/generator/go/templates/errors.go.j2 +182 -0
- django_cfg/modules/django_client/core/generator/go/templates/go.mod.j2 +6 -0
- django_cfg/modules/django_client/core/generator/go/templates/main_client.go.j2 +60 -0
- django_cfg/modules/django_client/core/generator/go/templates/middleware.go.j2 +388 -0
- django_cfg/modules/django_client/core/generator/go/templates/models.go.j2 +28 -0
- django_cfg/modules/django_client/core/generator/go/templates/operations_client.go.j2 +142 -0
- django_cfg/modules/django_client/core/generator/go/templates/validation.go.j2 +217 -0
- django_cfg/modules/django_client/core/generator/go/type_mapper.py +380 -0
- django_cfg/modules/django_client/management/commands/generate_client.py +53 -3
- django_cfg/modules/django_client/system/generate_mjs_clients.py +3 -1
- django_cfg/modules/django_client/system/schema_parser.py +5 -1
- django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +1 -0
- django_cfg/modules/django_twilio/sendgrid_service.py +7 -4
- django_cfg/modules/django_unfold/dashboard.py +25 -19
- django_cfg/pyproject.toml +1 -1
- django_cfg/registry/core.py +2 -0
- django_cfg/registry/modules.py +2 -2
- django_cfg/static/js/api/centrifugo/client.mjs +164 -0
- django_cfg/static/js/api/centrifugo/index.mjs +13 -0
- django_cfg/static/js/api/index.mjs +5 -5
- django_cfg/static/js/api/types.mjs +89 -26
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/METADATA +1 -1
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/RECORD +142 -70
- django_cfg/apps/ipc/README.md +0 -346
- django_cfg/apps/ipc/RPC_LOGGING.md +0 -321
- django_cfg/apps/ipc/TESTING.md +0 -539
- django_cfg/apps/ipc/__init__.py +0 -60
- django_cfg/apps/ipc/admin.py +0 -232
- django_cfg/apps/ipc/apps.py +0 -98
- django_cfg/apps/ipc/migrations/0001_initial.py +0 -137
- django_cfg/apps/ipc/migrations/0002_rpclog_is_event.py +0 -23
- django_cfg/apps/ipc/migrations/__init__.py +0 -0
- django_cfg/apps/ipc/models.py +0 -229
- django_cfg/apps/ipc/serializers/__init__.py +0 -29
- django_cfg/apps/ipc/serializers/serializers.py +0 -343
- django_cfg/apps/ipc/services/__init__.py +0 -7
- django_cfg/apps/ipc/services/client/__init__.py +0 -23
- django_cfg/apps/ipc/services/client/client.py +0 -621
- django_cfg/apps/ipc/services/client/config.py +0 -214
- django_cfg/apps/ipc/services/client/exceptions.py +0 -201
- django_cfg/apps/ipc/services/logging.py +0 -239
- django_cfg/apps/ipc/services/monitor.py +0 -466
- django_cfg/apps/ipc/services/rpc_log_consumer.py +0 -330
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/main.mjs +0 -269
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/overview.mjs +0 -259
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/testing.mjs +0 -375
- django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard.mjs.old +0 -441
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/methods_content.html +0 -22
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/notifications_content.html +0 -9
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/overview_content.html +0 -9
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/requests_content.html +0 -23
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/system_status.html +0 -47
- django_cfg/apps/ipc/templates/django_cfg_ipc/components/testing_tools.html +0 -184
- django_cfg/apps/ipc/templates/django_cfg_ipc/layout/base.html +0 -71
- django_cfg/apps/ipc/templates/django_cfg_ipc/pages/dashboard.html +0 -56
- django_cfg/apps/ipc/urls.py +0 -23
- django_cfg/apps/ipc/views/__init__.py +0 -13
- django_cfg/apps/ipc/views/dashboard.py +0 -15
- django_cfg/apps/ipc/views/monitoring.py +0 -251
- django_cfg/apps/ipc/views/testing.py +0 -285
- django_cfg/static/js/api/ipc/client.mjs +0 -114
- django_cfg/static/js/api/ipc/index.mjs +0 -13
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/licenses/LICENSE +0 -0
django_cfg/apps/ipc/README.md
DELETED
|
@@ -1,346 +0,0 @@
|
|
|
1
|
-
# Django-CFG RPC Client 📡
|
|
2
|
-
|
|
3
|
-
Lightweight synchronous RPC client for Django applications to communicate with **django-ipc** WebSocket servers via Redis.
|
|
4
|
-
|
|
5
|
-
**NEW**: ✨ Built-in RPC Dashboard for real-time monitoring! See [Dashboard README](./dashboard/README.md)
|
|
6
|
-
|
|
7
|
-
## 🎯 Key Features
|
|
8
|
-
|
|
9
|
-
- ✅ **100% Synchronous** - No async/await in Django, works with WSGI
|
|
10
|
-
- ✅ **Type-Safe** - Full Pydantic 2 support when django-ipc installed
|
|
11
|
-
- ✅ **Optional Dependency** - Works without django-ipc (dict-based fallback)
|
|
12
|
-
- ✅ **Redis IPC** - Reliable communication via Streams + Lists
|
|
13
|
-
- ✅ **Connection Pooling** - Automatic Redis connection management
|
|
14
|
-
- ✅ **Singleton Pattern** - Single client instance across Django app
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## 📦 Installation
|
|
19
|
-
|
|
20
|
-
### Option 1: With django-ipc (Recommended)
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
pip install django-cfg django-ipc
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Option 2: Standalone (Basic)
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
pip install django-cfg redis
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
---
|
|
33
|
-
|
|
34
|
-
## ⚙️ Configuration
|
|
35
|
-
|
|
36
|
-
### Django Settings (via django-cfg)
|
|
37
|
-
|
|
38
|
-
```python
|
|
39
|
-
# config.py
|
|
40
|
-
from django_cfg import DjangoConfig
|
|
41
|
-
from django_cfg.modules.django_ipc_client.config import DjangoCfgRPCConfig
|
|
42
|
-
|
|
43
|
-
class MyProjectConfig(DjangoConfig):
|
|
44
|
-
project_name = "My Project"
|
|
45
|
-
|
|
46
|
-
# RPC Client Configuration
|
|
47
|
-
django_ipc = DjangoCfgRPCConfig(
|
|
48
|
-
enabled=True,
|
|
49
|
-
redis_url="redis://localhost:6379/2",
|
|
50
|
-
rpc_timeout=30,
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
config = MyProjectConfig()
|
|
54
|
-
|
|
55
|
-
# settings.py
|
|
56
|
-
from config import config
|
|
57
|
-
|
|
58
|
-
# Settings are automatically generated by django-cfg orchestrator
|
|
59
|
-
# DJANGO_CFG_RPC settings will be available in Django settings
|
|
60
|
-
globals().update(config.get_all_settings())
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
**✨ Automatic Integration:**
|
|
64
|
-
- ✅ `DJANGO_CFG_RPC` settings are auto-generated
|
|
65
|
-
- ✅ Dashboard app auto-added to `INSTALLED_APPS`
|
|
66
|
-
- ✅ Dashboard URLs auto-registered at `/admin/rpc/`
|
|
67
|
-
- ✅ RPC tracked in `DJANGO_CFG_INTEGRATIONS` list
|
|
68
|
-
|
|
69
|
-
### Environment Variables
|
|
70
|
-
|
|
71
|
-
```bash
|
|
72
|
-
DJANGO_CFG_RPC__ENABLED=true
|
|
73
|
-
DJANGO_CFG_RPC__REDIS_URL=redis://localhost:6379/2
|
|
74
|
-
DJANGO_CFG_RPC__RPC_TIMEOUT=30
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
---
|
|
78
|
-
|
|
79
|
-
## 🚀 Usage
|
|
80
|
-
|
|
81
|
-
### With django-ipc Models (Type-Safe)
|
|
82
|
-
|
|
83
|
-
```python
|
|
84
|
-
# views.py
|
|
85
|
-
from django_cfg.modules.django_ipc_client import get_rpc_client
|
|
86
|
-
from django_ipc.models import NotificationRequest, NotificationResponse
|
|
87
|
-
|
|
88
|
-
rpc = get_rpc_client()
|
|
89
|
-
|
|
90
|
-
def notify_user(request, user_id):
|
|
91
|
-
"""Send notification to user via WebSocket."""
|
|
92
|
-
|
|
93
|
-
result: NotificationResponse = rpc.call(
|
|
94
|
-
method="send_notification",
|
|
95
|
-
params=NotificationRequest(
|
|
96
|
-
user_id=user_id,
|
|
97
|
-
type="order_update",
|
|
98
|
-
title="Order Confirmed",
|
|
99
|
-
message="Your order #12345 has been confirmed",
|
|
100
|
-
priority="high",
|
|
101
|
-
),
|
|
102
|
-
result_model=NotificationResponse,
|
|
103
|
-
timeout=10,
|
|
104
|
-
)
|
|
105
|
-
|
|
106
|
-
return JsonResponse({
|
|
107
|
-
"delivered": result.delivered,
|
|
108
|
-
"connections": result.connections,
|
|
109
|
-
})
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Without django-ipc (Dict-Based)
|
|
113
|
-
|
|
114
|
-
```python
|
|
115
|
-
from django_cfg.modules.django_ipc_client import get_rpc_client
|
|
116
|
-
|
|
117
|
-
rpc = get_rpc_client()
|
|
118
|
-
|
|
119
|
-
def notify_user(request, user_id):
|
|
120
|
-
"""Send notification using dict params."""
|
|
121
|
-
|
|
122
|
-
result = rpc.call_dict(
|
|
123
|
-
method="send_notification",
|
|
124
|
-
params={
|
|
125
|
-
"user_id": user_id,
|
|
126
|
-
"type": "order_update",
|
|
127
|
-
"title": "Order Confirmed",
|
|
128
|
-
"message": "Your order #12345 has been confirmed",
|
|
129
|
-
},
|
|
130
|
-
timeout=10,
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
return JsonResponse({
|
|
134
|
-
"delivered": result.get("delivered", False),
|
|
135
|
-
})
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Fire-and-Forget (No Response Wait)
|
|
139
|
-
|
|
140
|
-
```python
|
|
141
|
-
# For operations where you don't need the result
|
|
142
|
-
rpc.fire_and_forget(
|
|
143
|
-
method="log_event",
|
|
144
|
-
params={"event": "user_login", "user_id": "123"}
|
|
145
|
-
)
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## 🔧 API Reference
|
|
151
|
-
|
|
152
|
-
### `get_rpc_client(force_new=False)`
|
|
153
|
-
|
|
154
|
-
Get singleton RPC client instance.
|
|
155
|
-
|
|
156
|
-
**Args:**
|
|
157
|
-
- `force_new` (bool): Force create new instance (for testing)
|
|
158
|
-
|
|
159
|
-
**Returns:**
|
|
160
|
-
- `DjangoCfgRPCClient` instance
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
### `DjangoCfgRPCClient.call(method, params, result_model=None, timeout=None)`
|
|
165
|
-
|
|
166
|
-
Make synchronous RPC call.
|
|
167
|
-
|
|
168
|
-
**Args:**
|
|
169
|
-
- `method` (str): RPC method name
|
|
170
|
-
- `params` (BaseModel | dict): Parameters (Pydantic model or dict)
|
|
171
|
-
- `result_model` (Type[BaseModel], optional): Expected result model class
|
|
172
|
-
- `timeout` (int, optional): Timeout override in seconds
|
|
173
|
-
|
|
174
|
-
**Returns:**
|
|
175
|
-
- Pydantic model instance (if `result_model` provided) or dict
|
|
176
|
-
|
|
177
|
-
**Raises:**
|
|
178
|
-
- `RPCTimeoutError`: If timeout exceeded
|
|
179
|
-
- `RPCRemoteError`: If remote execution failed
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
### `DjangoCfgRPCClient.call_dict(method, params, timeout=None)`
|
|
184
|
-
|
|
185
|
-
Make RPC call with dict params (no Pydantic).
|
|
186
|
-
|
|
187
|
-
**Args:**
|
|
188
|
-
- `method` (str): RPC method name
|
|
189
|
-
- `params` (dict): Dictionary with parameters
|
|
190
|
-
- `timeout` (int, optional): Timeout override in seconds
|
|
191
|
-
|
|
192
|
-
**Returns:**
|
|
193
|
-
- Dictionary with result
|
|
194
|
-
|
|
195
|
-
---
|
|
196
|
-
|
|
197
|
-
### `DjangoCfgRPCClient.fire_and_forget(method, params)`
|
|
198
|
-
|
|
199
|
-
Send RPC request without waiting for response.
|
|
200
|
-
|
|
201
|
-
**Args:**
|
|
202
|
-
- `method` (str): RPC method name
|
|
203
|
-
- `params` (BaseModel | dict): Parameters
|
|
204
|
-
|
|
205
|
-
**Returns:**
|
|
206
|
-
- str: Message ID from Redis Stream
|
|
207
|
-
|
|
208
|
-
---
|
|
209
|
-
|
|
210
|
-
### `DjangoCfgRPCClient.health_check(timeout=5)`
|
|
211
|
-
|
|
212
|
-
Check if RPC system is healthy.
|
|
213
|
-
|
|
214
|
-
**Args:**
|
|
215
|
-
- `timeout` (int): Health check timeout in seconds
|
|
216
|
-
|
|
217
|
-
**Returns:**
|
|
218
|
-
- bool: True if healthy, False otherwise
|
|
219
|
-
|
|
220
|
-
---
|
|
221
|
-
|
|
222
|
-
## ⚠️ Error Handling
|
|
223
|
-
|
|
224
|
-
### Timeout Handling
|
|
225
|
-
|
|
226
|
-
```python
|
|
227
|
-
from django_cfg.modules.django_ipc_client import get_rpc_client, RPCTimeoutError
|
|
228
|
-
|
|
229
|
-
rpc = get_rpc_client()
|
|
230
|
-
|
|
231
|
-
try:
|
|
232
|
-
result = rpc.call(method="slow_operation", params={...}, timeout=5)
|
|
233
|
-
except RPCTimeoutError as e:
|
|
234
|
-
logger.warning(f"RPC timeout: {e.method} after {e.timeout_seconds}s")
|
|
235
|
-
# Handle timeout (retry, fallback, etc.)
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Remote Error Handling
|
|
239
|
-
|
|
240
|
-
```python
|
|
241
|
-
from django_cfg.modules.django_ipc_client import RPCRemoteError
|
|
242
|
-
|
|
243
|
-
try:
|
|
244
|
-
result = rpc.call(method="...", params={...})
|
|
245
|
-
except RPCRemoteError as e:
|
|
246
|
-
logger.error(f"Remote error [{e.error.code}]: {e.error.message}")
|
|
247
|
-
|
|
248
|
-
if e.is_retryable:
|
|
249
|
-
# Retry after delay
|
|
250
|
-
import time
|
|
251
|
-
time.sleep(e.retry_after or 5)
|
|
252
|
-
result = rpc.call(...) # Retry
|
|
253
|
-
else:
|
|
254
|
-
# Non-retryable error
|
|
255
|
-
raise
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
---
|
|
259
|
-
|
|
260
|
-
## 🏗️ Architecture
|
|
261
|
-
|
|
262
|
-
```
|
|
263
|
-
┌─────────────────────────────────────────────┐
|
|
264
|
-
│ Django Application (WSGI/Sync) │
|
|
265
|
-
│ ┌───────────────────────────────────────┐ │
|
|
266
|
-
│ │ django_ipc_client │ │
|
|
267
|
-
│ │ - DjangoCfgRPCClient (sync) │ │
|
|
268
|
-
│ │ - Redis Streams (requests) │ │
|
|
269
|
-
│ │ - Redis Lists (responses) │ │
|
|
270
|
-
│ └───────────────────────────────────────┘ │
|
|
271
|
-
└───────────────┬─────────────────────────────┘
|
|
272
|
-
│
|
|
273
|
-
│ Redis IPC
|
|
274
|
-
│ (stream:requests → list:response:{cid})
|
|
275
|
-
▼
|
|
276
|
-
┌─────────────────────────────────────────────┐
|
|
277
|
-
│ django-ipc Server (Async) │
|
|
278
|
-
│ - WebSocket Server │
|
|
279
|
-
│ - Connection Manager │
|
|
280
|
-
│ - RPC Handlers │
|
|
281
|
-
│ - Pydantic 2 Models │
|
|
282
|
-
└─────────────────────────────────────────────┘
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
---
|
|
286
|
-
|
|
287
|
-
## 🔗 Related
|
|
288
|
-
|
|
289
|
-
- **django-ipc** - WebSocket RPC server package
|
|
290
|
-
- **Old Module** - `django_rpc_old` (deprecated, kept for reference)
|
|
291
|
-
|
|
292
|
-
---
|
|
293
|
-
|
|
294
|
-
## 📝 Migration from django_rpc_old
|
|
295
|
-
|
|
296
|
-
```python
|
|
297
|
-
# Old (deprecated)
|
|
298
|
-
from django_cfg.modules.django_rpc import get_rpc_client
|
|
299
|
-
|
|
300
|
-
# New (current)
|
|
301
|
-
from django_cfg.modules.django_ipc_client import get_rpc_client
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
API remains mostly compatible. Main changes:
|
|
305
|
-
- Configuration key: `WEBSOCKET_RPC` → `DJANGO_CFG_RPC`
|
|
306
|
-
- Models now live in `django-ipc` package (optional dependency)
|
|
307
|
-
- Better error handling with specific exception types
|
|
308
|
-
|
|
309
|
-
---
|
|
310
|
-
|
|
311
|
-
**Status:** ✅ Production Ready
|
|
312
|
-
**Django-CFG Version:** 2.0+
|
|
313
|
-
**Python Version:** 3.10+
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
---
|
|
317
|
-
|
|
318
|
-
## 📊 RPC Dashboard (NEW!)
|
|
319
|
-
|
|
320
|
-
### Quick Start
|
|
321
|
-
|
|
322
|
-
Add dashboard to your Django URLs:
|
|
323
|
-
|
|
324
|
-
```python
|
|
325
|
-
# urls.py
|
|
326
|
-
from django.urls import path, include
|
|
327
|
-
|
|
328
|
-
urlpatterns = [
|
|
329
|
-
# ... other URLs
|
|
330
|
-
path('admin/rpc/', include('django_cfg.modules.django_ipc_client.dashboard.urls')),
|
|
331
|
-
]
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
Access at: **http://localhost:8000/admin/rpc/** (requires staff login)
|
|
335
|
-
|
|
336
|
-
### Features
|
|
337
|
-
|
|
338
|
-
- ✅ **Real-time monitoring** - Updates every 5 seconds
|
|
339
|
-
- ✅ **Request tracking** - View recent RPC calls
|
|
340
|
-
- ✅ **Notification stats** - Track sent notifications
|
|
341
|
-
- ✅ **Method analytics** - See which methods are called
|
|
342
|
-
- ✅ **Health checks** - Monitor Redis and streams
|
|
343
|
-
- ✅ **Beautiful UI** - Tailwind CSS dark mode
|
|
344
|
-
|
|
345
|
-
See [Dashboard README](./dashboard/README.md) for full documentation.
|
|
346
|
-
|
|
@@ -1,321 +0,0 @@
|
|
|
1
|
-
# RPC Logging & Analytics
|
|
2
|
-
|
|
3
|
-
**Track, monitor, and analyze all RPC calls between Django and WebSocket server.**
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 🎯 Overview
|
|
8
|
-
|
|
9
|
-
The IPC app now includes **automatic RPC logging** to database with:
|
|
10
|
-
- ✅ **Full request/response tracking**
|
|
11
|
-
- ✅ **Performance metrics** (duration, success rate)
|
|
12
|
-
- ✅ **User attribution** (who made the call)
|
|
13
|
-
- ✅ **Error details** (stack traces, error codes)
|
|
14
|
-
- ✅ **Beautiful admin interface** (Unfold Admin)
|
|
15
|
-
- ✅ **Analytics dashboard** (coming soon)
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
## 📊 What Gets Logged?
|
|
20
|
-
|
|
21
|
-
Every RPC call creates a `RPCLog` entry with:
|
|
22
|
-
|
|
23
|
-
```python
|
|
24
|
-
RPCLog:
|
|
25
|
-
id: UUID # Primary key
|
|
26
|
-
correlation_id: str # Matches RPC request
|
|
27
|
-
method: str # RPC method name
|
|
28
|
-
params: dict # Request parameters (JSON)
|
|
29
|
-
response: dict | None # Response data (JSON)
|
|
30
|
-
status: pending|success|failed|timeout
|
|
31
|
-
error_code: str | None # Error code if failed
|
|
32
|
-
error_message: str | None # Error message
|
|
33
|
-
duration_ms: int | None # Call duration in milliseconds
|
|
34
|
-
user: User | None # Django user who made the call
|
|
35
|
-
caller_ip: str | None # IP address
|
|
36
|
-
user_agent: str | None # User agent string
|
|
37
|
-
created_at: datetime # When call started
|
|
38
|
-
completed_at: datetime # When call finished
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## 🚀 Usage
|
|
44
|
-
|
|
45
|
-
### **Automatic Logging (Recommended)**
|
|
46
|
-
|
|
47
|
-
Logging happens automatically when you pass `user` to `rpc.call()`:
|
|
48
|
-
|
|
49
|
-
```python
|
|
50
|
-
from django_cfg.apps.ipc import get_rpc_client
|
|
51
|
-
|
|
52
|
-
def my_view(request):
|
|
53
|
-
rpc = get_rpc_client()
|
|
54
|
-
|
|
55
|
-
# RPC call with automatic logging
|
|
56
|
-
result = rpc.call(
|
|
57
|
-
method="send_notification",
|
|
58
|
-
params={"user_id": "123", "message": "Hello"},
|
|
59
|
-
user=request.user, # ✅ Logs this call
|
|
60
|
-
caller_ip=request.META.get('REMOTE_ADDR'),
|
|
61
|
-
user_agent=request.META.get('HTTP_USER_AGENT')
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
return JsonResponse({"sent": True})
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
**What gets logged:**
|
|
68
|
-
- ✅ Method name: `send_notification`
|
|
69
|
-
- ✅ Parameters: `{"user_id": "123", "message": "Hello"}`
|
|
70
|
-
- ✅ User: `request.user`
|
|
71
|
-
- ✅ IP: Client IP address
|
|
72
|
-
- ✅ Duration: Automatically calculated
|
|
73
|
-
- ✅ Status: success/failed/timeout
|
|
74
|
-
- ✅ Response data or error details
|
|
75
|
-
|
|
76
|
-
### **Manual Logging (Advanced)**
|
|
77
|
-
|
|
78
|
-
For more control, use `RPCLogger` directly:
|
|
79
|
-
|
|
80
|
-
```python
|
|
81
|
-
from django_cfg.apps.ipc.services.logging import RPCLogger
|
|
82
|
-
|
|
83
|
-
# Create log entry
|
|
84
|
-
log_entry = RPCLogger.create_log(
|
|
85
|
-
correlation_id="abc123",
|
|
86
|
-
method="my_method",
|
|
87
|
-
params={"key": "value"},
|
|
88
|
-
user=request.user
|
|
89
|
-
)
|
|
90
|
-
|
|
91
|
-
# ... make RPC call ...
|
|
92
|
-
|
|
93
|
-
# Mark as success
|
|
94
|
-
RPCLogger.mark_success(log_entry, response_data={"result": "ok"}, duration_ms=150)
|
|
95
|
-
|
|
96
|
-
# Or mark as failed
|
|
97
|
-
RPCLogger.mark_failed(log_entry, "network_error", "Connection timeout", duration_ms=30000)
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
### **Context Manager (Cleanest)**
|
|
101
|
-
|
|
102
|
-
```python
|
|
103
|
-
from django_cfg.apps.ipc.services.logging import RPCLogContext
|
|
104
|
-
|
|
105
|
-
with RPCLogContext(
|
|
106
|
-
correlation_id="abc123",
|
|
107
|
-
method="send_notification",
|
|
108
|
-
params={"user_id": "123"},
|
|
109
|
-
user=request.user
|
|
110
|
-
) as log_ctx:
|
|
111
|
-
result = rpc.call(...)
|
|
112
|
-
log_ctx.set_response(result)
|
|
113
|
-
# Automatically logged on exit
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
## 🎨 Admin Interface
|
|
119
|
-
|
|
120
|
-
**Access at:** `/admin/django_cfg_ipc/rpclog/`
|
|
121
|
-
|
|
122
|
-
### **List View Features:**
|
|
123
|
-
- ✅ **Color-coded status badges** (green=success, red=failed, orange=timeout)
|
|
124
|
-
- ✅ **Performance metrics** (duration color-coded by speed)
|
|
125
|
-
- ✅ **Search** by method, user, correlation ID
|
|
126
|
-
- ✅ **Filters** by status, method, date, user
|
|
127
|
-
- ✅ **Date hierarchy** for time-based navigation
|
|
128
|
-
|
|
129
|
-
### **Detail View Features:**
|
|
130
|
-
- ✅ **Formatted JSON** for params/response
|
|
131
|
-
- ✅ **Error details** with highlighted boxes
|
|
132
|
-
- ✅ **Timeline** (created_at → completed_at)
|
|
133
|
-
- ✅ **User info** with links to user admin
|
|
134
|
-
|
|
135
|
-
---
|
|
136
|
-
|
|
137
|
-
## 📈 Analytics Queries
|
|
138
|
-
|
|
139
|
-
### **Get stats by method:**
|
|
140
|
-
|
|
141
|
-
```python
|
|
142
|
-
from django_cfg.apps.ipc.models import RPCLog
|
|
143
|
-
|
|
144
|
-
stats = RPCLog.objects.stats_by_method()
|
|
145
|
-
for stat in stats:
|
|
146
|
-
print(f"{stat['method']}:")
|
|
147
|
-
print(f" Total calls: {stat['total_calls']}")
|
|
148
|
-
print(f" Avg duration: {stat['avg_duration_ms']}ms")
|
|
149
|
-
print(f" Success rate: {stat['success_count'] / stat['total_calls'] * 100}%")
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### **Get recent failures:**
|
|
153
|
-
|
|
154
|
-
```python
|
|
155
|
-
# Last 100 failed calls
|
|
156
|
-
failed_calls = RPCLog.objects.failed().order_by('-created_at')[:100]
|
|
157
|
-
|
|
158
|
-
for call in failed_calls:
|
|
159
|
-
print(f"{call.method}: {call.error_message}")
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### **Get slow calls:**
|
|
163
|
-
|
|
164
|
-
```python
|
|
165
|
-
# Calls slower than 1 second
|
|
166
|
-
slow_calls = RPCLog.objects.filter(
|
|
167
|
-
duration_ms__gt=1000,
|
|
168
|
-
status='success'
|
|
169
|
-
).order_by('-duration_ms')
|
|
170
|
-
|
|
171
|
-
for call in slow_calls:
|
|
172
|
-
print(f"{call.method}: {call.duration_ms}ms")
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### **User activity:**
|
|
176
|
-
|
|
177
|
-
```python
|
|
178
|
-
# RPC calls by specific user
|
|
179
|
-
user_calls = RPCLog.objects.filter(user=request.user).recent(hours=24)
|
|
180
|
-
print(f"User made {user_calls.count()} RPC calls in last 24h")
|
|
181
|
-
```
|
|
182
|
-
|
|
183
|
-
---
|
|
184
|
-
|
|
185
|
-
## ⚙️ Configuration
|
|
186
|
-
|
|
187
|
-
### **Enable/Disable Logging**
|
|
188
|
-
|
|
189
|
-
```python
|
|
190
|
-
# config.py
|
|
191
|
-
from django_cfg import DjangoConfig
|
|
192
|
-
|
|
193
|
-
class MyConfig(DjangoConfig):
|
|
194
|
-
django_ipc = DjangoCfgRPCConfig(
|
|
195
|
-
enabled=True,
|
|
196
|
-
redis_url="redis://localhost:6379/2",
|
|
197
|
-
enable_logging=True, # ✅ Enable RPC logging (default: True)
|
|
198
|
-
)
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
Or via environment variable:
|
|
202
|
-
|
|
203
|
-
```bash
|
|
204
|
-
DJANGO_CFG_RPC__ENABLE_LOGGING=true
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### **Log Retention**
|
|
208
|
-
|
|
209
|
-
To prevent database bloat, set up a periodic cleanup task:
|
|
210
|
-
|
|
211
|
-
```python
|
|
212
|
-
# tasks/cleanup.py
|
|
213
|
-
from django.utils import timezone
|
|
214
|
-
from datetime import timedelta
|
|
215
|
-
from django_cfg.apps.ipc.models import RPCLog
|
|
216
|
-
|
|
217
|
-
def cleanup_old_rpc_logs(days=30):
|
|
218
|
-
"""Delete RPC logs older than N days."""
|
|
219
|
-
cutoff = timezone.now() - timedelta(days=days)
|
|
220
|
-
deleted_count = RPCLog.objects.filter(created_at__lt=cutoff).delete()[0]
|
|
221
|
-
print(f"Deleted {deleted_count} old RPC logs")
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
Add to crontab or django-dramatiq:
|
|
225
|
-
|
|
226
|
-
```python
|
|
227
|
-
# Schedule daily cleanup
|
|
228
|
-
@dramatiq.actor
|
|
229
|
-
def daily_cleanup():
|
|
230
|
-
cleanup_old_rpc_logs(days=30)
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
---
|
|
234
|
-
|
|
235
|
-
## 📊 Performance Impact
|
|
236
|
-
|
|
237
|
-
**Logging overhead:**
|
|
238
|
-
- ✅ **Async-safe** - uses synchronous Django ORM
|
|
239
|
-
- ✅ **Non-blocking** - doesn't delay RPC calls
|
|
240
|
-
- ✅ **Error-tolerant** - logging failures don't break RPC
|
|
241
|
-
- ✅ **Indexed** - fast queries on common fields
|
|
242
|
-
|
|
243
|
-
**Benchmarks:**
|
|
244
|
-
- Create log entry: **~2-5ms**
|
|
245
|
-
- Update status: **~1-3ms**
|
|
246
|
-
- Total overhead per RPC call: **~3-8ms**
|
|
247
|
-
|
|
248
|
-
For 1000 RPC calls/min, expect **~5-10K log entries/day**.
|
|
249
|
-
|
|
250
|
-
---
|
|
251
|
-
|
|
252
|
-
## 🔍 Troubleshooting
|
|
253
|
-
|
|
254
|
-
### **Logging not working?**
|
|
255
|
-
|
|
256
|
-
1. **Check if IPC app is installed:**
|
|
257
|
-
```python
|
|
258
|
-
'django_cfg.apps.ipc' in settings.INSTALLED_APPS
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
2. **Run migrations:**
|
|
262
|
-
```bash
|
|
263
|
-
python manage.py migrate django_cfg_ipc
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
3. **Check logging settings:**
|
|
267
|
-
```python
|
|
268
|
-
settings.DJANGO_CFG_RPC.get('ENABLE_LOGGING') # Should be True
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### **Too many logs?**
|
|
272
|
-
|
|
273
|
-
1. **Disable logging temporarily:**
|
|
274
|
-
```python
|
|
275
|
-
DJANGO_CFG_RPC__ENABLE_LOGGING=false
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
2. **Set up log rotation:**
|
|
279
|
-
```python
|
|
280
|
-
# Keep only last 7 days
|
|
281
|
-
cleanup_old_rpc_logs(days=7)
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
3. **Use log sampling** (advanced):
|
|
285
|
-
```python
|
|
286
|
-
# Log only 10% of calls
|
|
287
|
-
import random
|
|
288
|
-
if random.random() < 0.1:
|
|
289
|
-
rpc.call(..., user=request.user) # Logged
|
|
290
|
-
else:
|
|
291
|
-
rpc.call(...) # Not logged
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
---
|
|
295
|
-
|
|
296
|
-
## 🎯 Best Practices
|
|
297
|
-
|
|
298
|
-
1. **✅ Always pass `user`** when possible for attribution
|
|
299
|
-
2. **✅ Set up log retention** to prevent DB bloat
|
|
300
|
-
3. **✅ Monitor slow calls** (duration > 1s)
|
|
301
|
-
4. **✅ Alert on high failure rates** (>5%)
|
|
302
|
-
5. **✅ Use correlation_id** for debugging request chains
|
|
303
|
-
6. **⚠️ Don't log sensitive data** in params (passwords, tokens)
|
|
304
|
-
|
|
305
|
-
---
|
|
306
|
-
|
|
307
|
-
## 🚀 Future Enhancements
|
|
308
|
-
|
|
309
|
-
Coming soon:
|
|
310
|
-
- [ ] Real-time analytics dashboard
|
|
311
|
-
- [ ] Grafana integration (metrics export)
|
|
312
|
-
- [ ] Webhook notifications on failures
|
|
313
|
-
- [ ] Automatic slow query detection
|
|
314
|
-
- [ ] Rate limiting based on logs
|
|
315
|
-
- [ ] Cost tracking (API usage billing)
|
|
316
|
-
|
|
317
|
-
---
|
|
318
|
-
|
|
319
|
-
**Status:** ✅ Production Ready
|
|
320
|
-
**Django-CFG Version:** 2.0+
|
|
321
|
-
**Python Version:** 3.10+
|