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.

Files changed (181) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/services/otp_service.py +3 -14
  3. django_cfg/apps/centrifugo/__init__.py +57 -0
  4. django_cfg/apps/centrifugo/admin/__init__.py +13 -0
  5. django_cfg/apps/centrifugo/admin/centrifugo_log.py +249 -0
  6. django_cfg/apps/centrifugo/admin/config.py +82 -0
  7. django_cfg/apps/centrifugo/apps.py +31 -0
  8. django_cfg/apps/centrifugo/codegen/IMPLEMENTATION_SUMMARY.md +475 -0
  9. django_cfg/apps/centrifugo/codegen/README.md +242 -0
  10. django_cfg/apps/centrifugo/codegen/USAGE.md +616 -0
  11. django_cfg/apps/centrifugo/codegen/__init__.py +19 -0
  12. django_cfg/apps/centrifugo/codegen/discovery.py +246 -0
  13. django_cfg/apps/centrifugo/codegen/generators/go_thin/__init__.py +5 -0
  14. django_cfg/apps/centrifugo/codegen/generators/go_thin/generator.py +174 -0
  15. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/README.md.j2 +182 -0
  16. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/client.go.j2 +64 -0
  17. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/go.mod.j2 +10 -0
  18. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2 +300 -0
  19. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/rpc_client.go.j2.old +267 -0
  20. django_cfg/apps/centrifugo/codegen/generators/go_thin/templates/types.go.j2 +16 -0
  21. django_cfg/apps/centrifugo/codegen/generators/python_thin/__init__.py +7 -0
  22. django_cfg/apps/centrifugo/codegen/generators/python_thin/generator.py +241 -0
  23. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/README.md.j2 +128 -0
  24. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/__init__.py.j2 +22 -0
  25. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/client.py.j2 +73 -0
  26. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/models.py.j2 +19 -0
  27. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/requirements.txt.j2 +8 -0
  28. django_cfg/apps/centrifugo/codegen/generators/python_thin/templates/rpc_client.py.j2 +193 -0
  29. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/__init__.py +5 -0
  30. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/generator.py +124 -0
  31. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/README.md.j2 +38 -0
  32. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/client.ts.j2 +25 -0
  33. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/index.ts.j2 +12 -0
  34. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/package.json.j2 +13 -0
  35. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/rpc-client.ts.j2 +137 -0
  36. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/tsconfig.json.j2 +14 -0
  37. django_cfg/apps/centrifugo/codegen/generators/typescript_thin/templates/types.ts.j2 +9 -0
  38. django_cfg/apps/centrifugo/codegen/utils/__init__.py +37 -0
  39. django_cfg/apps/centrifugo/codegen/utils/naming.py +155 -0
  40. django_cfg/apps/centrifugo/codegen/utils/type_converter.py +349 -0
  41. django_cfg/apps/centrifugo/decorators.py +137 -0
  42. django_cfg/apps/centrifugo/management/__init__.py +1 -0
  43. django_cfg/apps/centrifugo/management/commands/__init__.py +1 -0
  44. django_cfg/apps/centrifugo/management/commands/generate_centrifugo_clients.py +254 -0
  45. django_cfg/apps/centrifugo/managers/__init__.py +12 -0
  46. django_cfg/apps/centrifugo/managers/centrifugo_log.py +264 -0
  47. django_cfg/apps/centrifugo/migrations/0001_initial.py +164 -0
  48. django_cfg/apps/centrifugo/migrations/__init__.py +3 -0
  49. django_cfg/apps/centrifugo/models/__init__.py +11 -0
  50. django_cfg/apps/centrifugo/models/centrifugo_log.py +210 -0
  51. django_cfg/apps/centrifugo/registry.py +106 -0
  52. django_cfg/apps/centrifugo/router.py +125 -0
  53. django_cfg/apps/centrifugo/serializers/__init__.py +40 -0
  54. django_cfg/apps/centrifugo/serializers/admin_api.py +264 -0
  55. django_cfg/apps/centrifugo/serializers/channels.py +26 -0
  56. django_cfg/apps/centrifugo/serializers/health.py +17 -0
  57. django_cfg/apps/centrifugo/serializers/publishes.py +16 -0
  58. django_cfg/apps/centrifugo/serializers/stats.py +21 -0
  59. django_cfg/apps/centrifugo/services/__init__.py +12 -0
  60. django_cfg/apps/centrifugo/services/client/__init__.py +29 -0
  61. django_cfg/apps/centrifugo/services/client/client.py +582 -0
  62. django_cfg/apps/centrifugo/services/client/config.py +236 -0
  63. django_cfg/apps/centrifugo/services/client/exceptions.py +212 -0
  64. django_cfg/apps/centrifugo/services/config_helper.py +63 -0
  65. django_cfg/apps/centrifugo/services/dashboard_notifier.py +157 -0
  66. django_cfg/apps/centrifugo/services/logging.py +677 -0
  67. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/css/dashboard.css +260 -0
  68. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_channels.mjs +313 -0
  69. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/live_testing.mjs +803 -0
  70. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/main.mjs +333 -0
  71. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/overview.mjs +432 -0
  72. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/testing.mjs +33 -0
  73. django_cfg/apps/centrifugo/static/django_cfg_centrifugo/js/dashboard/websocket.mjs +210 -0
  74. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/channels_content.html +46 -0
  75. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/live_channels_content.html +123 -0
  76. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/overview_content.html +45 -0
  77. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/publishes_content.html +84 -0
  78. django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/stat_cards.html +23 -20
  79. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/system_status.html +91 -0
  80. django_cfg/apps/{ipc/templates/django_cfg_ipc → centrifugo/templates/django_cfg_centrifugo}/components/tab_navigation.html +15 -15
  81. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/components/testing_tools.html +415 -0
  82. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/layout/base.html +61 -0
  83. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/pages/dashboard.html +58 -0
  84. django_cfg/apps/centrifugo/templates/django_cfg_centrifugo/tags/connection_script.html +48 -0
  85. django_cfg/apps/centrifugo/templatetags/__init__.py +1 -0
  86. django_cfg/apps/centrifugo/templatetags/centrifugo_tags.py +81 -0
  87. django_cfg/apps/centrifugo/urls.py +31 -0
  88. django_cfg/apps/{ipc → centrifugo}/urls_admin.py +4 -4
  89. django_cfg/apps/centrifugo/views/__init__.py +15 -0
  90. django_cfg/apps/centrifugo/views/admin_api.py +380 -0
  91. django_cfg/apps/centrifugo/views/dashboard.py +15 -0
  92. django_cfg/apps/centrifugo/views/monitoring.py +286 -0
  93. django_cfg/apps/centrifugo/views/testing_api.py +422 -0
  94. django_cfg/apps/support/utils/support_email_service.py +5 -18
  95. django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -2
  96. django_cfg/apps/urls.py +5 -5
  97. django_cfg/core/base/config_model.py +4 -44
  98. django_cfg/core/builders/apps_builder.py +2 -2
  99. django_cfg/core/generation/integration_generators/third_party.py +8 -8
  100. django_cfg/core/utils/__init__.py +5 -0
  101. django_cfg/core/utils/url_helpers.py +73 -0
  102. django_cfg/modules/base.py +7 -7
  103. django_cfg/modules/django_client/core/__init__.py +2 -1
  104. django_cfg/modules/django_client/core/config/config.py +8 -0
  105. django_cfg/modules/django_client/core/generator/__init__.py +42 -2
  106. django_cfg/modules/django_client/core/generator/go/__init__.py +14 -0
  107. django_cfg/modules/django_client/core/generator/go/client_generator.py +124 -0
  108. django_cfg/modules/django_client/core/generator/go/files_generator.py +133 -0
  109. django_cfg/modules/django_client/core/generator/go/generator.py +203 -0
  110. django_cfg/modules/django_client/core/generator/go/models_generator.py +304 -0
  111. django_cfg/modules/django_client/core/generator/go/naming.py +193 -0
  112. django_cfg/modules/django_client/core/generator/go/operations_generator.py +134 -0
  113. django_cfg/modules/django_client/core/generator/go/templates/Makefile.j2 +38 -0
  114. django_cfg/modules/django_client/core/generator/go/templates/README.md.j2 +55 -0
  115. django_cfg/modules/django_client/core/generator/go/templates/client.go.j2 +122 -0
  116. django_cfg/modules/django_client/core/generator/go/templates/enums.go.j2 +49 -0
  117. django_cfg/modules/django_client/core/generator/go/templates/errors.go.j2 +182 -0
  118. django_cfg/modules/django_client/core/generator/go/templates/go.mod.j2 +6 -0
  119. django_cfg/modules/django_client/core/generator/go/templates/main_client.go.j2 +60 -0
  120. django_cfg/modules/django_client/core/generator/go/templates/middleware.go.j2 +388 -0
  121. django_cfg/modules/django_client/core/generator/go/templates/models.go.j2 +28 -0
  122. django_cfg/modules/django_client/core/generator/go/templates/operations_client.go.j2 +142 -0
  123. django_cfg/modules/django_client/core/generator/go/templates/validation.go.j2 +217 -0
  124. django_cfg/modules/django_client/core/generator/go/type_mapper.py +380 -0
  125. django_cfg/modules/django_client/management/commands/generate_client.py +53 -3
  126. django_cfg/modules/django_client/system/generate_mjs_clients.py +3 -1
  127. django_cfg/modules/django_client/system/schema_parser.py +5 -1
  128. django_cfg/modules/django_tailwind/templates/django_tailwind/base.html +1 -0
  129. django_cfg/modules/django_twilio/sendgrid_service.py +7 -4
  130. django_cfg/modules/django_unfold/dashboard.py +25 -19
  131. django_cfg/pyproject.toml +1 -1
  132. django_cfg/registry/core.py +2 -0
  133. django_cfg/registry/modules.py +2 -2
  134. django_cfg/static/js/api/centrifugo/client.mjs +164 -0
  135. django_cfg/static/js/api/centrifugo/index.mjs +13 -0
  136. django_cfg/static/js/api/index.mjs +5 -5
  137. django_cfg/static/js/api/types.mjs +89 -26
  138. {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/METADATA +1 -1
  139. {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/RECORD +142 -70
  140. django_cfg/apps/ipc/README.md +0 -346
  141. django_cfg/apps/ipc/RPC_LOGGING.md +0 -321
  142. django_cfg/apps/ipc/TESTING.md +0 -539
  143. django_cfg/apps/ipc/__init__.py +0 -60
  144. django_cfg/apps/ipc/admin.py +0 -232
  145. django_cfg/apps/ipc/apps.py +0 -98
  146. django_cfg/apps/ipc/migrations/0001_initial.py +0 -137
  147. django_cfg/apps/ipc/migrations/0002_rpclog_is_event.py +0 -23
  148. django_cfg/apps/ipc/migrations/__init__.py +0 -0
  149. django_cfg/apps/ipc/models.py +0 -229
  150. django_cfg/apps/ipc/serializers/__init__.py +0 -29
  151. django_cfg/apps/ipc/serializers/serializers.py +0 -343
  152. django_cfg/apps/ipc/services/__init__.py +0 -7
  153. django_cfg/apps/ipc/services/client/__init__.py +0 -23
  154. django_cfg/apps/ipc/services/client/client.py +0 -621
  155. django_cfg/apps/ipc/services/client/config.py +0 -214
  156. django_cfg/apps/ipc/services/client/exceptions.py +0 -201
  157. django_cfg/apps/ipc/services/logging.py +0 -239
  158. django_cfg/apps/ipc/services/monitor.py +0 -466
  159. django_cfg/apps/ipc/services/rpc_log_consumer.py +0 -330
  160. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/main.mjs +0 -269
  161. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/overview.mjs +0 -259
  162. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard/testing.mjs +0 -375
  163. django_cfg/apps/ipc/static/django_cfg_ipc/js/dashboard.mjs.old +0 -441
  164. django_cfg/apps/ipc/templates/django_cfg_ipc/components/methods_content.html +0 -22
  165. django_cfg/apps/ipc/templates/django_cfg_ipc/components/notifications_content.html +0 -9
  166. django_cfg/apps/ipc/templates/django_cfg_ipc/components/overview_content.html +0 -9
  167. django_cfg/apps/ipc/templates/django_cfg_ipc/components/requests_content.html +0 -23
  168. django_cfg/apps/ipc/templates/django_cfg_ipc/components/system_status.html +0 -47
  169. django_cfg/apps/ipc/templates/django_cfg_ipc/components/testing_tools.html +0 -184
  170. django_cfg/apps/ipc/templates/django_cfg_ipc/layout/base.html +0 -71
  171. django_cfg/apps/ipc/templates/django_cfg_ipc/pages/dashboard.html +0 -56
  172. django_cfg/apps/ipc/urls.py +0 -23
  173. django_cfg/apps/ipc/views/__init__.py +0 -13
  174. django_cfg/apps/ipc/views/dashboard.py +0 -15
  175. django_cfg/apps/ipc/views/monitoring.py +0 -251
  176. django_cfg/apps/ipc/views/testing.py +0 -285
  177. django_cfg/static/js/api/ipc/client.mjs +0 -114
  178. django_cfg/static/js/api/ipc/index.mjs +0 -13
  179. {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/WHEEL +0 -0
  180. {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/entry_points.txt +0 -0
  181. {django_cfg-1.4.62.dist-info → django_cfg-1.4.64.dist-info}/licenses/LICENSE +0 -0
@@ -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+