django-cfg 1.5.20__py3-none-any.whl → 1.5.29__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 (88) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/integrations/centrifugo/__init__.py +2 -0
  3. django_cfg/apps/integrations/centrifugo/services/client/client.py +1 -1
  4. django_cfg/apps/integrations/centrifugo/services/logging.py +47 -0
  5. django_cfg/apps/integrations/centrifugo/views/admin_api.py +29 -32
  6. django_cfg/apps/integrations/centrifugo/views/testing_api.py +31 -37
  7. django_cfg/apps/integrations/centrifugo/views/wrapper.py +25 -23
  8. django_cfg/apps/integrations/grpc/auth/api_key_auth.py +11 -10
  9. django_cfg/apps/integrations/grpc/management/commands/generate_protos.py +1 -1
  10. django_cfg/apps/integrations/grpc/management/commands/rungrpc.py +21 -36
  11. django_cfg/apps/integrations/grpc/managers/grpc_request_log.py +84 -0
  12. django_cfg/apps/integrations/grpc/managers/grpc_server_status.py +126 -3
  13. django_cfg/apps/integrations/grpc/models/grpc_api_key.py +7 -1
  14. django_cfg/apps/integrations/grpc/models/grpc_server_status.py +22 -3
  15. django_cfg/apps/integrations/grpc/services/__init__.py +102 -17
  16. django_cfg/apps/integrations/grpc/services/centrifugo/bridge.py +469 -0
  17. django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/demo.py +1 -1
  18. django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/test_publish.py +4 -4
  19. django_cfg/apps/integrations/grpc/services/client/__init__.py +26 -0
  20. django_cfg/apps/integrations/grpc/services/commands/IMPLEMENTATION.md +456 -0
  21. django_cfg/apps/integrations/grpc/services/commands/README.md +252 -0
  22. django_cfg/apps/integrations/grpc/services/commands/__init__.py +93 -0
  23. django_cfg/apps/integrations/grpc/services/commands/base.py +243 -0
  24. django_cfg/apps/integrations/grpc/services/commands/examples/__init__.py +22 -0
  25. django_cfg/apps/integrations/grpc/services/commands/examples/base_client.py +228 -0
  26. django_cfg/apps/integrations/grpc/services/commands/examples/client.py +272 -0
  27. django_cfg/apps/integrations/grpc/services/commands/examples/config.py +177 -0
  28. django_cfg/apps/integrations/grpc/services/commands/examples/start.py +125 -0
  29. django_cfg/apps/integrations/grpc/services/commands/examples/stop.py +101 -0
  30. django_cfg/apps/integrations/grpc/services/commands/registry.py +170 -0
  31. django_cfg/apps/integrations/grpc/services/discovery/__init__.py +39 -0
  32. django_cfg/apps/integrations/grpc/services/{discovery.py → discovery/discovery.py} +62 -55
  33. django_cfg/apps/integrations/grpc/services/{service_registry.py → discovery/registry.py} +215 -5
  34. django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/metrics.py +3 -3
  35. django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/request_logger.py +10 -13
  36. django_cfg/apps/integrations/grpc/services/management/__init__.py +37 -0
  37. django_cfg/apps/integrations/grpc/services/monitoring/__init__.py +38 -0
  38. django_cfg/apps/integrations/grpc/services/{monitoring_service.py → monitoring/monitoring.py} +2 -2
  39. django_cfg/apps/integrations/grpc/services/{testing_service.py → monitoring/testing.py} +5 -5
  40. django_cfg/apps/integrations/grpc/services/rendering/__init__.py +27 -0
  41. django_cfg/apps/integrations/grpc/services/{chart_generator.py → rendering/charts.py} +1 -1
  42. django_cfg/apps/integrations/grpc/services/routing/__init__.py +59 -0
  43. django_cfg/apps/integrations/grpc/services/routing/config.py +76 -0
  44. django_cfg/apps/integrations/grpc/services/routing/router.py +430 -0
  45. django_cfg/apps/integrations/grpc/services/streaming/__init__.py +117 -0
  46. django_cfg/apps/integrations/grpc/services/streaming/config.py +451 -0
  47. django_cfg/apps/integrations/grpc/services/streaming/service.py +651 -0
  48. django_cfg/apps/integrations/grpc/services/streaming/types.py +367 -0
  49. django_cfg/apps/integrations/grpc/utils/__init__.py +58 -1
  50. django_cfg/apps/integrations/grpc/utils/converters.py +565 -0
  51. django_cfg/apps/integrations/grpc/utils/handlers.py +242 -0
  52. django_cfg/apps/integrations/grpc/utils/proto_gen.py +1 -1
  53. django_cfg/apps/integrations/grpc/utils/streaming_logger.py +55 -8
  54. django_cfg/apps/integrations/grpc/views/charts.py +1 -1
  55. django_cfg/apps/integrations/grpc/views/config.py +1 -1
  56. django_cfg/core/base/config_model.py +11 -0
  57. django_cfg/core/builders/middleware_builder.py +5 -0
  58. django_cfg/management/commands/pool_status.py +153 -0
  59. django_cfg/middleware/pool_cleanup.py +261 -0
  60. django_cfg/models/api/grpc/config.py +2 -2
  61. django_cfg/models/infrastructure/database/config.py +16 -0
  62. django_cfg/models/infrastructure/database/converters.py +2 -0
  63. django_cfg/modules/django_admin/utils/html/composition.py +57 -13
  64. django_cfg/modules/django_admin/utils/html_builder.py +1 -0
  65. django_cfg/modules/django_client/core/groups/manager.py +25 -18
  66. django_cfg/modules/django_client/management/commands/generate_client.py +9 -5
  67. django_cfg/modules/django_logging/django_logger.py +58 -19
  68. django_cfg/pyproject.toml +3 -3
  69. django_cfg/static/frontend/admin.zip +0 -0
  70. django_cfg/templates/admin/index.html +0 -39
  71. django_cfg/utils/pool_monitor.py +320 -0
  72. django_cfg/utils/smart_defaults.py +233 -7
  73. {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/METADATA +75 -5
  74. {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/RECORD +87 -59
  75. django_cfg/apps/integrations/grpc/centrifugo/bridge.py +0 -277
  76. /django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/__init__.py +0 -0
  77. /django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/config.py +0 -0
  78. /django_cfg/apps/integrations/grpc/{centrifugo → services/centrifugo}/transformers.py +0 -0
  79. /django_cfg/apps/integrations/grpc/services/{grpc_client.py → client/client.py} +0 -0
  80. /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/__init__.py +0 -0
  81. /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/centrifugo.py +0 -0
  82. /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/errors.py +0 -0
  83. /django_cfg/apps/integrations/grpc/{interceptors → services/interceptors}/logging.py +0 -0
  84. /django_cfg/apps/integrations/grpc/services/{config_helper.py → management/config_helper.py} +0 -0
  85. /django_cfg/apps/integrations/grpc/services/{proto_files_manager.py → management/proto_manager.py} +0 -0
  86. {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/WHEEL +0 -0
  87. {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/entry_points.txt +0 -0
  88. {django_cfg-1.5.20.dist-info → django_cfg-1.5.29.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,451 @@
1
+ """
2
+ Pydantic v2 configuration models for gRPC bidirectional streaming.
3
+
4
+ This module provides type-safe, validated configuration for bidirectional streaming services.
5
+ All models are frozen and use strict validation to prevent runtime errors.
6
+
7
+ **Design Principles**:
8
+ - 100% Pydantic v2 (no raw dicts)
9
+ - Frozen models (immutable)
10
+ - Strict validation with Field constraints
11
+ - extra='forbid' to catch typos
12
+ - Comprehensive documentation
13
+
14
+ **Usage Example**:
15
+ ```python
16
+ config = BidirectionalStreamingConfig(
17
+ ping_interval=5.0,
18
+ ping_timeout=30.0,
19
+ enable_sleep_zero=True,
20
+ max_queue_size=1000
21
+ )
22
+
23
+ service = BidirectionalStreamingService(
24
+ config=config,
25
+ message_processor=process_messages,
26
+ ...
27
+ )
28
+ ```
29
+
30
+ Created: 2025-11-07
31
+ Status: %%PRODUCTION%%
32
+ Phase: Phase 1 - Universal Components
33
+ """
34
+
35
+ from enum import Enum
36
+ from typing import Optional, Any
37
+ from pydantic import BaseModel, Field, field_validator, model_validator
38
+
39
+
40
+ # ============================================================================
41
+ # Enumerations
42
+ # ============================================================================
43
+
44
+ class StreamingMode(str, Enum):
45
+ """
46
+ Streaming iteration modes for handling bidirectional streams.
47
+
48
+ **Modes**:
49
+ ASYNC_FOR: Use `async for message in stream` (simpler, automatic iteration)
50
+ ANEXT: Use `await anext(stream)` (manual control, better error handling)
51
+
52
+ **Comparison**:
53
+
54
+ | Feature | ASYNC_FOR | ANEXT |
55
+ |-----------------------|-----------|-------|
56
+ | Simplicity | ✅ Simple | ⚠️ Manual |
57
+ | Error Control | ⚠️ Limited | ✅ Full |
58
+ | Timeout Control | ⚠️ Limited | ✅ Full |
59
+ | Early Exit | ⚠️ Limited | ✅ Easy |
60
+
61
+ **Usage**:
62
+ ```python
63
+ # ASYNC_FOR mode
64
+ config = BidirectionalStreamingConfig(streaming_mode=StreamingMode.ASYNC_FOR)
65
+ # Implementation: async for message in stream: ...
66
+
67
+ # ANEXT mode
68
+ config = BidirectionalStreamingConfig(streaming_mode=StreamingMode.ANEXT)
69
+ # Implementation: message = await anext(stream)
70
+ ```
71
+
72
+ **Recommendation**:
73
+ - Use ASYNC_FOR for simple services
74
+ - Use ANEXT for services requiring fine-grained control
75
+ """
76
+
77
+ ASYNC_FOR = "async_for"
78
+ """Use async for iteration (automatic, simpler)"""
79
+
80
+ ANEXT = "anext"
81
+ """Use anext() calls (manual, more control)"""
82
+
83
+
84
+ class PingStrategy(str, Enum):
85
+ """
86
+ Strategies for sending ping/keepalive messages.
87
+
88
+ **Strategies**:
89
+ INTERVAL: Send ping every N seconds (time-based)
90
+ ON_IDLE: Send ping only when no messages sent recently (activity-based)
91
+ DISABLED: Don't send automatic pings (manual control)
92
+
93
+ **Comparison**:
94
+
95
+ | Strategy | Network Usage | Responsiveness | Use Case |
96
+ |-----------|---------------|----------------|----------|
97
+ | INTERVAL | ⚠️ Higher | ✅ Predictable | Critical services |
98
+ | ON_IDLE | ✅ Lower | ⚠️ Variable | Normal services |
99
+ | DISABLED | ✅ Minimal | ❌ Manual | Testing/debug |
100
+
101
+ **Usage**:
102
+ ```python
103
+ # Send ping every 5 seconds
104
+ config = BidirectionalStreamingConfig(
105
+ ping_strategy=PingStrategy.INTERVAL,
106
+ ping_interval=5.0
107
+ )
108
+
109
+ # Send ping only after 10 seconds of inactivity
110
+ config = BidirectionalStreamingConfig(
111
+ ping_strategy=PingStrategy.ON_IDLE,
112
+ ping_interval=10.0
113
+ )
114
+
115
+ # No automatic pings
116
+ config = BidirectionalStreamingConfig(
117
+ ping_strategy=PingStrategy.DISABLED
118
+ )
119
+ ```
120
+ """
121
+
122
+ INTERVAL = "interval"
123
+ """Send ping every N seconds regardless of activity"""
124
+
125
+ ON_IDLE = "on_idle"
126
+ """Send ping only after N seconds of inactivity"""
127
+
128
+ DISABLED = "disabled"
129
+ """Don't send automatic pings"""
130
+
131
+
132
+ # ============================================================================
133
+ # Configuration Models
134
+ # ============================================================================
135
+
136
+ class BidirectionalStreamingConfig(BaseModel):
137
+ """
138
+ Configuration for bidirectional gRPC streaming services.
139
+
140
+ This model provides type-safe configuration with validation for all streaming parameters.
141
+ All fields have sensible defaults based on production experience.
142
+
143
+ **Core Parameters**:
144
+ streaming_mode: How to iterate over input stream (ASYNC_FOR vs ANEXT)
145
+ ping_strategy: When to send keepalive pings (INTERVAL vs ON_IDLE)
146
+ ping_interval: Seconds between pings (must be > 0)
147
+ ping_timeout: Max seconds to wait for ping response (must be >= ping_interval)
148
+
149
+ **Queue Parameters**:
150
+ max_queue_size: Max items in output queue before blocking (must be > 0)
151
+ queue_timeout: Max seconds to wait when enqueuing to full queue
152
+
153
+ **Advanced Parameters**:
154
+ enable_sleep_zero: Enable `await asyncio.sleep(0)` for event loop yielding
155
+ enable_centrifugo: Auto-publish to Centrifugo WebSocket channels
156
+ enable_logging: Enable structured logging for stream events
157
+
158
+ **Validation Rules**:
159
+ - ping_timeout >= ping_interval (can't timeout before ping)
160
+ - ping_interval > 0 (must be positive)
161
+ - max_queue_size > 0 (must have capacity)
162
+ - All timeouts must be positive
163
+
164
+ **Example - Production Config**:
165
+ ```python
166
+ config = BidirectionalStreamingConfig(
167
+ streaming_mode=StreamingMode.ANEXT,
168
+ ping_strategy=PingStrategy.INTERVAL,
169
+ ping_interval=5.0,
170
+ ping_timeout=30.0,
171
+ max_queue_size=1000,
172
+ enable_sleep_zero=True,
173
+ enable_centrifugo=True,
174
+ enable_logging=True
175
+ )
176
+ ```
177
+
178
+ **Example - Development Config**:
179
+ ```python
180
+ config = BidirectionalStreamingConfig(
181
+ streaming_mode=StreamingMode.ASYNC_FOR,
182
+ ping_strategy=PingStrategy.ON_IDLE,
183
+ ping_interval=10.0,
184
+ enable_centrifugo=False,
185
+ enable_logging=True
186
+ )
187
+ ```
188
+ """
189
+
190
+ # ------------------------------------------------------------------------
191
+ # Streaming Parameters
192
+ # ------------------------------------------------------------------------
193
+
194
+ streaming_mode: StreamingMode = Field(
195
+ default=StreamingMode.ANEXT,
196
+ description="How to iterate over input stream (ASYNC_FOR vs ANEXT)",
197
+ )
198
+
199
+ # ------------------------------------------------------------------------
200
+ # Ping/Keepalive Parameters
201
+ # ------------------------------------------------------------------------
202
+
203
+ ping_strategy: PingStrategy = Field(
204
+ default=PingStrategy.INTERVAL,
205
+ description="When to send keepalive pings (INTERVAL vs ON_IDLE vs DISABLED)",
206
+ )
207
+
208
+ ping_interval: float = Field(
209
+ default=5.0,
210
+ gt=0.0,
211
+ le=300.0, # Max 5 minutes
212
+ description="Seconds between pings (must be > 0, max 300)",
213
+ )
214
+
215
+ ping_timeout: Optional[float] = Field(
216
+ default=None,
217
+ gt=0.0,
218
+ le=600.0, # Max 10 minutes
219
+ description="Max seconds to wait for ping response (None = 6x ping_interval)",
220
+ )
221
+
222
+ # ------------------------------------------------------------------------
223
+ # Queue Parameters
224
+ # ------------------------------------------------------------------------
225
+
226
+ max_queue_size: int = Field(
227
+ default=1000,
228
+ gt=0,
229
+ le=100000, # Max 100k items
230
+ description="Max items in output queue before blocking (must be > 0)",
231
+ )
232
+
233
+ queue_timeout: Optional[float] = Field(
234
+ default=10.0,
235
+ gt=0.0,
236
+ le=60.0, # Max 1 minute
237
+ description="Max seconds to wait when enqueuing to full queue (None = no timeout)",
238
+ )
239
+
240
+ # ------------------------------------------------------------------------
241
+ # Advanced Parameters
242
+ # ------------------------------------------------------------------------
243
+
244
+ enable_sleep_zero: bool = Field(
245
+ default=True,
246
+ description="Enable `await asyncio.sleep(0)` for event loop yielding (CRITICAL for responsiveness)",
247
+ )
248
+
249
+ enable_centrifugo: bool = Field(
250
+ default=True,
251
+ description="Auto-publish messages to Centrifugo WebSocket channels",
252
+ )
253
+
254
+ enable_logging: bool = Field(
255
+ default=True,
256
+ description="Enable structured logging for stream events",
257
+ )
258
+
259
+ logger_name: Optional[str] = Field(
260
+ default=None,
261
+ min_length=1,
262
+ max_length=100,
263
+ description="Logger name for auto-created logger (None = 'grpc_streaming')",
264
+ )
265
+
266
+ # ------------------------------------------------------------------------
267
+ # Connection Management
268
+ # ------------------------------------------------------------------------
269
+
270
+ connection_timeout: Optional[float] = Field(
271
+ default=None,
272
+ gt=0.0,
273
+ le=3600.0, # Max 1 hour
274
+ description="Max seconds for entire connection (None = unlimited)",
275
+ )
276
+
277
+ max_consecutive_errors: int = Field(
278
+ default=3,
279
+ ge=0,
280
+ le=100,
281
+ description="Max consecutive errors before disconnecting (0 = unlimited)",
282
+ )
283
+
284
+ # ------------------------------------------------------------------------
285
+ # Validators
286
+ # ------------------------------------------------------------------------
287
+
288
+ @field_validator('ping_timeout')
289
+ @classmethod
290
+ def set_default_ping_timeout(cls, v: Optional[float], info) -> float:
291
+ """
292
+ Set ping_timeout to 6x ping_interval if not provided.
293
+
294
+ This ensures reasonable timeout with safety margin.
295
+ """
296
+ if v is None:
297
+ ping_interval = info.data.get('ping_interval', 5.0)
298
+ return ping_interval * 6.0
299
+ return v
300
+
301
+ @model_validator(mode='after')
302
+ def validate_timeout_relationship(self) -> 'BidirectionalStreamingConfig':
303
+ """
304
+ Ensure ping_timeout >= ping_interval.
305
+
306
+ Can't timeout before next ping is due.
307
+ """
308
+ # ping_timeout is set by field_validator, so it should never be None here
309
+ if self.ping_timeout is not None and self.ping_timeout < self.ping_interval:
310
+ raise ValueError(
311
+ f"ping_timeout ({self.ping_timeout}s) must be >= ping_interval ({self.ping_interval}s)"
312
+ )
313
+ return self
314
+
315
+ @model_validator(mode='after')
316
+ def validate_ping_strategy_requirements(self) -> 'BidirectionalStreamingConfig':
317
+ """
318
+ Ensure ping_interval is meaningful when ping_strategy is not DISABLED.
319
+ """
320
+ if self.ping_strategy != PingStrategy.DISABLED:
321
+ if self.ping_interval > 60.0:
322
+ raise ValueError(
323
+ f"ping_interval ({self.ping_interval}s) should be <= 60s for {self.ping_strategy.value} strategy"
324
+ )
325
+ return self
326
+
327
+ # ------------------------------------------------------------------------
328
+ # Model Configuration
329
+ # ------------------------------------------------------------------------
330
+
331
+ model_config = {
332
+ 'extra': 'forbid', # Reject unknown fields (catch typos)
333
+ 'frozen': True, # Immutable (thread-safe)
334
+ 'validate_assignment': True, # Validate on attribute assignment
335
+ 'str_strip_whitespace': True, # Strip strings
336
+ 'use_enum_values': False, # Keep enum objects (not values)
337
+ }
338
+
339
+ # ------------------------------------------------------------------------
340
+ # Computed Properties
341
+ # ------------------------------------------------------------------------
342
+
343
+ def is_ping_enabled(self) -> bool:
344
+ """Check if ping is enabled."""
345
+ return self.ping_strategy != PingStrategy.DISABLED
346
+
347
+ def should_yield_event_loop(self) -> bool:
348
+ """Check if should call await asyncio.sleep(0)."""
349
+ return self.enable_sleep_zero
350
+
351
+ def get_effective_ping_timeout(self) -> float:
352
+ """Get ping_timeout with fallback to 6x ping_interval."""
353
+ return self.ping_timeout if self.ping_timeout is not None else self.ping_interval * 6.0
354
+
355
+
356
+ # ============================================================================
357
+ # Preset Configurations
358
+ # ============================================================================
359
+
360
+ class ConfigPresets:
361
+ """
362
+ Predefined configurations for common use cases.
363
+
364
+ **Available Presets**:
365
+ - PRODUCTION: High-reliability config for production
366
+ - DEVELOPMENT: Relaxed config for development
367
+ - TESTING: Minimal config for unit tests
368
+ - HIGH_THROUGHPUT: Optimized for high message volume
369
+ - LOW_LATENCY: Optimized for responsiveness
370
+ """
371
+
372
+ PRODUCTION = BidirectionalStreamingConfig(
373
+ streaming_mode=StreamingMode.ANEXT,
374
+ ping_strategy=PingStrategy.INTERVAL,
375
+ ping_interval=5.0,
376
+ ping_timeout=30.0,
377
+ max_queue_size=1000,
378
+ enable_sleep_zero=True,
379
+ enable_centrifugo=True,
380
+ enable_logging=True,
381
+ max_consecutive_errors=3,
382
+ )
383
+ """Production config: 5s pings, 30s timeout, full logging."""
384
+
385
+ DEVELOPMENT = BidirectionalStreamingConfig(
386
+ streaming_mode=StreamingMode.ASYNC_FOR,
387
+ ping_strategy=PingStrategy.ON_IDLE,
388
+ ping_interval=10.0,
389
+ ping_timeout=60.0,
390
+ max_queue_size=100,
391
+ enable_sleep_zero=True,
392
+ enable_centrifugo=False,
393
+ enable_logging=True,
394
+ max_consecutive_errors=10,
395
+ )
396
+ """Development config: Relaxed timeouts, no Centrifugo."""
397
+
398
+ TESTING = BidirectionalStreamingConfig(
399
+ streaming_mode=StreamingMode.ASYNC_FOR,
400
+ ping_strategy=PingStrategy.DISABLED,
401
+ ping_interval=1.0,
402
+ max_queue_size=10,
403
+ enable_sleep_zero=False,
404
+ enable_centrifugo=False,
405
+ enable_logging=False,
406
+ max_consecutive_errors=0,
407
+ )
408
+ """Testing config: No pings, minimal queues, no logging."""
409
+
410
+ HIGH_THROUGHPUT = BidirectionalStreamingConfig(
411
+ streaming_mode=StreamingMode.ASYNC_FOR,
412
+ ping_strategy=PingStrategy.ON_IDLE,
413
+ ping_interval=30.0,
414
+ ping_timeout=180.0,
415
+ max_queue_size=10000,
416
+ enable_sleep_zero=True,
417
+ enable_centrifugo=True,
418
+ enable_logging=False, # Reduce overhead
419
+ max_consecutive_errors=10,
420
+ )
421
+ """High throughput: Large queues, infrequent pings, no logging."""
422
+
423
+ LOW_LATENCY = BidirectionalStreamingConfig(
424
+ streaming_mode=StreamingMode.ANEXT,
425
+ ping_strategy=PingStrategy.INTERVAL,
426
+ ping_interval=1.0,
427
+ ping_timeout=5.0,
428
+ max_queue_size=100,
429
+ enable_sleep_zero=True,
430
+ enable_centrifugo=True,
431
+ enable_logging=True,
432
+ max_consecutive_errors=3,
433
+ )
434
+ """Low latency: Frequent pings, small queues, immediate responsiveness."""
435
+
436
+
437
+ # ============================================================================
438
+ # Exports
439
+ # ============================================================================
440
+
441
+ __all__ = [
442
+ # Enums
443
+ 'StreamingMode',
444
+ 'PingStrategy',
445
+
446
+ # Models
447
+ 'BidirectionalStreamingConfig',
448
+
449
+ # Presets
450
+ 'ConfigPresets',
451
+ ]