django-cfg 1.1.61__py3-none-any.whl → 1.1.63__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.
Files changed (28) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/management/commands/rundramatiq.py +174 -202
  3. django_cfg/modules/django_tasks.py +54 -428
  4. django_cfg/modules/dramatiq_setup.py +16 -0
  5. {django_cfg-1.1.61.dist-info → django_cfg-1.1.63.dist-info}/METADATA +145 -4
  6. {django_cfg-1.1.61.dist-info → django_cfg-1.1.63.dist-info}/RECORD +9 -27
  7. django_cfg/apps/accounts/tests/__init__.py +0 -1
  8. django_cfg/apps/accounts/tests/test_models.py +0 -412
  9. django_cfg/apps/accounts/tests/test_otp_views.py +0 -143
  10. django_cfg/apps/accounts/tests/test_serializers.py +0 -331
  11. django_cfg/apps/accounts/tests/test_services.py +0 -401
  12. django_cfg/apps/accounts/tests/test_signals.py +0 -110
  13. django_cfg/apps/accounts/tests/test_views.py +0 -255
  14. django_cfg/apps/newsletter/tests/__init__.py +0 -1
  15. django_cfg/apps/newsletter/tests/run_tests.py +0 -47
  16. django_cfg/apps/newsletter/tests/test_email_integration.py +0 -256
  17. django_cfg/apps/newsletter/tests/test_email_tracking.py +0 -332
  18. django_cfg/apps/newsletter/tests/test_newsletter_manager.py +0 -83
  19. django_cfg/apps/newsletter/tests/test_newsletter_models.py +0 -157
  20. django_cfg/apps/support/tests/__init__.py +0 -0
  21. django_cfg/apps/support/tests/test_models.py +0 -106
  22. django_cfg/apps/tasks/@docs/CONFIGURATION.md +0 -663
  23. django_cfg/apps/tasks/@docs/README.md +0 -195
  24. django_cfg/apps/tasks/@docs/TASKS_QUEUES.md +0 -423
  25. django_cfg/apps/tasks/@docs/TROUBLESHOOTING.md +0 -506
  26. {django_cfg-1.1.61.dist-info → django_cfg-1.1.63.dist-info}/WHEEL +0 -0
  27. {django_cfg-1.1.61.dist-info → django_cfg-1.1.63.dist-info}/entry_points.txt +0 -0
  28. {django_cfg-1.1.61.dist-info → django_cfg-1.1.63.dist-info}/licenses/LICENSE +0 -0
@@ -1,18 +1,16 @@
1
1
  """
2
2
  Django-CFG Task Service Module.
3
3
 
4
- This module provides the service layer for background task processing with Dramatiq,
5
- including task management, worker control, monitoring, and Django integration.
4
+ Simplified and focused task service for Dramatiq integration.
5
+ Provides essential functionality without unnecessary complexity.
6
6
  """
7
7
 
8
- from typing import Optional, Dict, Any, List, Union
8
+ from typing import Optional, Dict, Any, List
9
9
  import logging
10
- import subprocess
11
- import time
12
10
  from urllib.parse import urlparse
13
11
 
14
12
  from django_cfg.modules.base import BaseModule
15
- from django_cfg.models.tasks import TaskConfig, DramatiqConfig, validate_task_config
13
+ from django_cfg.models.tasks import TaskConfig, validate_task_config
16
14
  from django_cfg.models.constance import ConstanceField
17
15
 
18
16
  # Django imports (will be available when Django is configured)
@@ -26,15 +24,8 @@ except ImportError:
26
24
  # Optional imports
27
25
  try:
28
26
  import dramatiq
29
- from dramatiq.brokers.redis import RedisBroker
30
27
  except ImportError:
31
28
  dramatiq = None
32
- RedisBroker = None
33
-
34
- try:
35
- import django_dramatiq
36
- except ImportError:
37
- django_dramatiq = None
38
29
 
39
30
  try:
40
31
  import redis
@@ -44,294 +35,121 @@ except ImportError:
44
35
  logger = logging.getLogger(__name__)
45
36
 
46
37
 
47
- class TaskManager:
48
- """
49
- Task management and worker control.
50
-
51
- Provides high-level interface for managing Dramatiq workers,
52
- monitoring task queues, and controlling task execution.
53
- """
54
-
55
- def __init__(self, config: DramatiqConfig):
56
- self.config = config
57
- self._broker = None
58
- self._workers = []
59
-
60
- @property
61
- def broker(self):
62
- """Get Dramatiq broker instance (lazy-loaded)."""
63
- if self._broker is None:
64
- if dramatiq is None:
65
- logger.error("Dramatiq not available")
66
- return None
67
-
68
- try:
69
- # This will be configured by Django settings
70
- self._broker = dramatiq.get_broker()
71
- except Exception as e:
72
- logger.error(f"Failed to get Dramatiq broker: {e}")
73
- return None
74
-
75
- return self._broker
76
-
77
- def get_queue_stats(self) -> List[Dict[str, Any]]:
78
- """Get statistics for all configured queues."""
79
- if not self.broker:
80
- return []
81
-
82
- stats = []
83
- for queue_name in self.config.dramatiq.queues:
84
- try:
85
- # Get queue statistics from broker
86
- queue_stats = {
87
- "name": queue_name,
88
- "pending": 0, # Will be populated by actual broker stats
89
- "running": 0,
90
- "completed": 0,
91
- "failed": 0,
92
- }
93
-
94
- # TODO: Implement actual queue statistics retrieval
95
- # This depends on the specific broker implementation
96
-
97
- stats.append(queue_stats)
98
- except Exception as e:
99
- logger.error(f"Failed to get stats for queue {queue_name}: {e}")
100
-
101
- return stats
102
-
103
- def get_worker_stats(self) -> List[Dict[str, Any]]:
104
- """Get statistics for all active workers."""
105
- # TODO: Implement worker statistics retrieval
106
- # This would typically involve checking process status,
107
- # memory usage, and current task information
108
-
109
- return []
110
-
111
- def clear_queue(self, queue_name: str) -> bool:
112
- """Clear all messages from a specific queue."""
113
- if not self.broker:
114
- return False
115
-
116
- try:
117
- # TODO: Implement queue clearing
118
- logger.info(f"Cleared queue: {queue_name}")
119
- return True
120
- except Exception as e:
121
- logger.error(f"Failed to clear queue {queue_name}: {e}")
122
- return False
123
-
124
- def retry_failed_tasks(self, queue_name: Optional[str] = None) -> int:
125
- """Retry failed tasks in specified queue or all queues."""
126
- if not self.broker:
127
- return 0
128
-
129
- try:
130
- # TODO: Implement failed task retry logic
131
- retried_count = 0
132
- logger.info(f"Retried {retried_count} failed tasks")
133
- return retried_count
134
- except Exception as e:
135
- logger.error(f"Failed to retry tasks: {e}")
136
- return 0
137
-
138
-
139
38
  class DjangoTasks(BaseModule):
140
39
  """
141
- Main Django-CFG task service.
40
+ Simplified Django-CFG task service.
142
41
 
143
- Provides the primary interface for task system integration,
144
- configuration management, and service coordination.
42
+ Focuses on essential functionality:
43
+ - Configuration management
44
+ - Task discovery
45
+ - Health checks
46
+ - Constance integration
145
47
  """
146
48
 
147
49
  def __init__(self):
148
50
  super().__init__()
149
51
  self._config: Optional[TaskConfig] = None
150
- self._manager: Optional[TaskManager] = None
151
52
  self._redis_url: Optional[str] = None
152
53
 
153
54
  @property
154
55
  def config(self) -> Optional[TaskConfig]:
155
56
  """Get task configuration (lazy-loaded)."""
156
- # Always try to get fresh config to avoid stale cache issues
157
- try:
158
- # First try the base class method
159
- django_config = self.get_config() # This returns full DjangoConfig
160
- if django_config and hasattr(django_config, 'tasks'):
161
- task_config = django_config.tasks
162
- if task_config and isinstance(task_config, TaskConfig):
163
- # Update cache with fresh config
164
- self._config = task_config
165
- logger.debug(f"Loaded TaskConfig: enabled={task_config.enabled}")
166
- return self._config
167
- elif task_config is None:
168
- logger.debug("Tasks configuration is None in Django config")
169
- else:
170
- logger.error(f"Expected TaskConfig, got {type(task_config)}")
171
- else:
172
- logger.debug("No tasks attribute found in Django config")
173
-
174
- # Fallback: try to import config directly
57
+ if self._config is None:
175
58
  try:
176
- from api.config import config as api_config
177
- if hasattr(api_config, 'tasks') and api_config.tasks:
178
- task_config = api_config.tasks
179
- if isinstance(task_config, TaskConfig):
180
- self._config = task_config
181
- logger.debug(f"Loaded TaskConfig from api.config: enabled={task_config.enabled}")
182
- return self._config
183
- except ImportError:
184
- logger.debug("Could not import api.config")
185
-
186
- return None
187
- except Exception as e:
188
- logger.warning(f"Failed to get task config: {e}")
189
- # Fallback to cached version if available
190
- return self._config
191
-
192
- @property
193
- def manager(self) -> Optional[TaskManager]:
194
- """Get task manager (lazy-loaded)."""
195
- if self._manager is None and self.config:
196
- try:
197
- self._manager = TaskManager(self.config.dramatiq)
59
+ # Get config from django-cfg
60
+ django_config = self.get_config()
61
+ if django_config and hasattr(django_config, 'tasks'):
62
+ self._config = django_config.tasks
63
+ logger.debug(f"Loaded TaskConfig: enabled={self._config.enabled if self._config else False}")
64
+ else:
65
+ # Fallback: try direct import
66
+ try:
67
+ from api.config import config as api_config
68
+ if hasattr(api_config, 'tasks') and api_config.tasks:
69
+ self._config = api_config.tasks
70
+ logger.debug(f"Loaded TaskConfig from api.config: enabled={self._config.enabled}")
71
+ except ImportError:
72
+ logger.debug("Could not import api.config")
198
73
  except Exception as e:
199
- logger.error(f"Failed to create task manager: {e}")
200
- return None
201
- return self._manager
74
+ logger.warning(f"Failed to get task config: {e}")
75
+
76
+ return self._config
202
77
 
203
78
  def is_enabled(self) -> bool:
204
79
  """Check if task system is enabled and properly configured."""
205
- if not self.config:
206
- return False
207
-
208
- if not self.config.enabled:
80
+ if not self.config or not self.config.enabled:
209
81
  return False
210
82
 
211
83
  # Check if required dependencies are available
212
- if dramatiq is None or django_dramatiq is None:
213
- logger.warning("Dramatiq dependencies not available")
84
+ if dramatiq is None:
85
+ logger.warning("Dramatiq not available")
214
86
  return False
215
87
 
216
88
  return True
217
89
 
218
90
  def get_redis_url(self) -> Optional[str]:
219
91
  """Get Redis URL from Django-CFG cache configuration."""
220
- # Always try to get the URL if not cached
221
92
  if self._redis_url is None:
222
93
  try:
223
- # Use get_current_config from django_cfg.core.config
224
94
  from django_cfg.core.config import get_current_config
225
95
  django_config = get_current_config()
226
96
 
227
- # If that fails, try to import directly from api.config
228
97
  if not django_config:
229
98
  try:
230
99
  from api.config import config
231
100
  django_config = config
232
- logger.debug("Got Django config from direct import")
233
101
  except ImportError:
234
102
  logger.warning("Could not import config from api.config")
235
103
 
236
- logger.debug(f"Django config type: {type(django_config)}")
237
- logger.debug(f"Has cache_default: {hasattr(django_config, 'cache_default') if django_config else False}")
238
-
239
104
  if django_config and hasattr(django_config, 'cache_default') and django_config.cache_default:
240
105
  cache_config = django_config.cache_default
241
- logger.debug(f"Cache config type: {type(cache_config)}")
242
- logger.debug(f"Cache config redis_url: {getattr(cache_config, 'redis_url', 'NOT_FOUND')}")
243
-
244
106
  if hasattr(cache_config, 'redis_url') and cache_config.redis_url:
245
107
  self._redis_url = cache_config.redis_url
246
108
  logger.debug(f"Got Redis URL: {self._redis_url}")
247
109
  elif hasattr(cache_config, 'location') and cache_config.location:
248
110
  self._redis_url = cache_config.location
249
111
  logger.debug(f"Got Redis URL from location: {self._redis_url}")
250
- else:
251
- logger.warning("Cache config exists but no redis_url or location found")
252
- else:
253
- logger.warning("No cache_default configuration found")
254
112
  except Exception as e:
255
113
  logger.warning(f"Failed to get Redis URL: {e}")
256
- import traceback
257
- logger.warning(f"Traceback: {traceback.format_exc()}")
258
114
 
259
115
  return self._redis_url
260
116
 
261
- def check_redis_connection(self) -> bool:
262
- """Check if Redis connection is available."""
263
- redis_url = self.get_redis_url()
264
- if not redis_url:
265
- return False
266
-
267
- if redis is None:
268
- logger.error("Redis library not available")
269
- return False
270
-
271
- try:
272
- parsed = urlparse(redis_url)
273
- r = redis.Redis(
274
- host=parsed.hostname or 'localhost',
275
- port=parsed.port or 6379,
276
- db=self.config.dramatiq.redis_db if self.config else 1,
277
- password=parsed.password,
278
- socket_timeout=5
279
- )
280
-
281
- # Test connection
282
- r.ping()
283
- return True
284
- except Exception as e:
285
- logger.error(f"Redis connection failed: {e}")
286
- return False
287
-
288
117
  def get_redis_client(self):
289
118
  """Get Redis client instance."""
290
119
  redis_url = self.get_redis_url()
291
- if not redis_url:
292
- logger.warning("No Redis URL available for client")
293
- return None
294
-
295
- if redis is None:
296
- logger.error("Redis library not available")
120
+ if not redis_url or redis is None:
297
121
  return None
298
122
 
299
123
  try:
300
124
  parsed = urlparse(redis_url)
301
- # Get redis_db from config, with fallback
302
- redis_db = 1 # default
303
- try:
304
- task_config = self.config # This should return TaskConfig
305
- if task_config:
306
- logger.debug(f"TaskConfig type: {type(task_config)}")
307
- if hasattr(task_config, 'dramatiq') and task_config.dramatiq:
308
- redis_db = task_config.dramatiq.redis_db
309
- logger.debug(f"Using redis_db: {redis_db}")
310
- else:
311
- logger.warning("No dramatiq config found in TaskConfig")
312
- else:
313
- logger.warning("No TaskConfig available")
314
- except Exception as e:
315
- logger.error(f"Error getting redis_db: {e}")
316
-
317
- client = redis.Redis(
125
+ return redis.Redis(
318
126
  host=parsed.hostname or 'localhost',
319
127
  port=parsed.port or 6379,
320
- db=redis_db,
128
+ db=self.config.dramatiq.redis_db if self.config else 1,
321
129
  password=parsed.password,
322
130
  socket_timeout=5
323
131
  )
324
-
325
- logger.debug(f"Created Redis client: host={parsed.hostname}, port={parsed.port}, db={redis_db}")
326
- return client
327
-
328
132
  except Exception as e:
329
133
  logger.error(f"Failed to create Redis client: {e}")
330
134
  return None
331
135
 
332
- def _get_current_timestamp(self) -> int:
333
- """Get current timestamp."""
334
- return int(time.time())
136
+ def _get_current_timestamp(self) -> str:
137
+ """Get current timestamp in ISO format."""
138
+ from datetime import datetime
139
+ return datetime.now().isoformat()
140
+
141
+ def check_redis_connection(self) -> bool:
142
+ """Check if Redis connection is available."""
143
+ redis_client = self.get_redis_client()
144
+ if not redis_client:
145
+ return False
146
+
147
+ try:
148
+ redis_client.ping()
149
+ return True
150
+ except Exception as e:
151
+ logger.error(f"Redis connection failed: {e}")
152
+ return False
335
153
 
336
154
  def validate_configuration(self) -> bool:
337
155
  """Validate complete task system configuration."""
@@ -346,38 +164,6 @@ class DjangoTasks(BaseModule):
346
164
 
347
165
  return validate_task_config(self.config, redis_url)
348
166
 
349
- def get_dramatiq_settings(self) -> Dict[str, Any]:
350
- """Generate Django settings for Dramatiq integration."""
351
- if not self.config or not self.is_enabled():
352
- return {}
353
-
354
- redis_url = self.get_redis_url()
355
- if not redis_url:
356
- logger.error("Cannot generate Dramatiq settings: Redis URL not available")
357
- return {}
358
-
359
- try:
360
- return self.config.get_dramatiq_settings(redis_url)
361
- except Exception as e:
362
- logger.error(f"Failed to generate Dramatiq settings: {e}")
363
- return {}
364
-
365
-
366
- def get_installed_apps(self) -> List[str]:
367
- """Get Django apps required for task system."""
368
- if not self.is_enabled():
369
- return []
370
-
371
- apps = ["django_dramatiq"]
372
-
373
- # Add optional apps based on configuration
374
- if self.config and self.config.dramatiq.admin_enabled:
375
- # Admin integration is included in django_dramatiq
376
- # Add our custom tasks app for enhanced admin interface
377
- apps.append("django_cfg.apps.tasks")
378
-
379
- return apps
380
-
381
167
  def discover_tasks(self) -> List[str]:
382
168
  """Discover task modules in Django apps."""
383
169
  if not self.config or not self.config.auto_discover_tasks:
@@ -402,19 +188,13 @@ class DjangoTasks(BaseModule):
402
188
  pass
403
189
  except Exception as e:
404
190
  logger.warning(f"Error importing task module {module_path}: {e}")
405
-
406
191
  except Exception as e:
407
192
  logger.error(f"Task discovery failed: {e}")
408
193
 
409
194
  return discovered
410
195
 
411
196
  def get_constance_fields(self) -> List[ConstanceField]:
412
- """
413
- Get Constance fields for Dramatiq configuration.
414
-
415
- Returns:
416
- List of ConstanceField objects for dynamic task configuration
417
- """
197
+ """Get Constance fields for Dramatiq configuration."""
418
198
  if not self.is_enabled():
419
199
  return []
420
200
 
@@ -460,84 +240,18 @@ class DjangoTasks(BaseModule):
460
240
  logger.debug(f"Generated {len(fields)} Constance fields for Dramatiq")
461
241
  return fields
462
242
 
463
- def start_workers(self, processes: Optional[int] = None, queues: Optional[List[str]] = None) -> bool:
464
- """Start Dramatiq workers programmatically."""
465
- logger.warning("Auto-start workers functionality has been removed. Please start workers manually using: python manage.py rundramatiq")
466
- return False
467
-
468
- def stop_workers(self, graceful: bool = True) -> bool:
469
- """Stop all Dramatiq workers."""
470
- try:
471
- timeout = self.config.dramatiq.worker.shutdown_timeout if self.config else 30
472
- logger.info(f"Stopping workers (graceful={graceful}, timeout={timeout}s)")
473
-
474
- # Find and kill Dramatiq worker processes
475
- try:
476
- # Find worker processes
477
- result = subprocess.run(
478
- ["pgrep", "-f", "rundramatiq"],
479
- capture_output=True,
480
- text=True
481
- )
482
-
483
- if result.returncode == 0:
484
- pids = result.stdout.strip().split('\n')
485
- pids = [pid.strip() for pid in pids if pid.strip()]
486
-
487
- if pids:
488
- logger.info(f"Found {len(pids)} worker processes: {pids}")
489
-
490
- # Send appropriate signal
491
- signal = "TERM" if graceful else "KILL"
492
-
493
- for pid in pids:
494
- try:
495
- subprocess.run(["kill", f"-{signal}", pid], check=True)
496
- logger.info(f"Sent {signal} signal to worker process {pid}")
497
- except subprocess.CalledProcessError:
498
- logger.warning(f"Failed to send {signal} signal to process {pid}")
499
-
500
- # Wait for graceful shutdown if requested
501
- if graceful:
502
- logger.info(f"Waiting up to {timeout}s for graceful shutdown...")
503
- # TODO: Could implement actual waiting logic here
504
-
505
- logger.info("✅ Dramatiq workers stopped successfully")
506
- return True
507
- else:
508
- logger.info("No worker processes found")
509
- return True
510
- else:
511
- logger.info("No worker processes found")
512
- return True
513
-
514
- except Exception as e:
515
- logger.error(f"Failed to find/stop worker processes: {e}")
516
- return False
517
-
518
- except Exception as e:
519
- logger.error(f"Failed to stop workers: {e}")
520
- return False
521
-
522
243
  def get_health_status(self) -> Dict[str, Any]:
523
244
  """Get comprehensive health status of task system."""
524
245
  status = {
525
246
  "enabled": self.is_enabled(),
526
247
  "redis_connection": False,
527
248
  "configuration_valid": False,
528
- "workers": [],
529
- "queues": [],
530
249
  "discovered_modules": [],
531
250
  }
532
251
 
533
252
  if self.is_enabled():
534
253
  status["redis_connection"] = self.check_redis_connection()
535
254
  status["configuration_valid"] = self.validate_configuration()
536
-
537
- if self.manager:
538
- status["workers"] = self.manager.get_worker_stats()
539
- status["queues"] = self.manager.get_queue_stats()
540
-
541
255
  status["discovered_modules"] = self.discover_tasks()
542
256
 
543
257
  return status
@@ -549,12 +263,7 @@ _task_service_instance: Optional[DjangoTasks] = None
549
263
 
550
264
 
551
265
  def get_task_service() -> DjangoTasks:
552
- """
553
- Get the global task service instance.
554
-
555
- Returns:
556
- DjangoTasks: The singleton task service instance
557
- """
266
+ """Get the global task service instance."""
558
267
  global _task_service_instance
559
268
 
560
269
  if _task_service_instance is None:
@@ -594,79 +303,6 @@ def get_task_health() -> Dict[str, Any]:
594
303
  }
595
304
 
596
305
 
597
- def enqueue_task(actor_name: str, *args, queue_name: str = "default", **kwargs) -> bool:
598
- """
599
- Enqueue a task for processing.
600
-
601
- Args:
602
- actor_name: Name of the Dramatiq actor
603
- *args: Task arguments
604
- queue_name: Queue to send task to
605
- **kwargs: Task keyword arguments
606
-
607
- Returns:
608
- bool: True if task was successfully enqueued
609
- """
610
- try:
611
- service = get_task_service()
612
- if not service.is_enabled():
613
- logger.error("Task system not enabled")
614
- return False
615
-
616
- # TODO: Implement actual task enqueueing
617
- # This would involve getting the actor and calling send()
618
-
619
- logger.info(f"Enqueued task {actor_name} to queue {queue_name}")
620
- return True
621
- except Exception as e:
622
- logger.error(f"Failed to enqueue task {actor_name}: {e}")
623
- return False
624
-
625
-
626
- def clear_dramatiq_queues() -> bool:
627
- """
628
- Clear all Dramatiq queues on startup.
629
-
630
- Returns:
631
- bool: True if queues were cleared successfully
632
- """
633
- try:
634
- service = get_task_service()
635
- if not service.is_enabled():
636
- logger.debug("Task system not enabled, skipping queue clearing")
637
- return True
638
-
639
- # Get broker and clear all queues
640
- if hasattr(service, 'manager') and service.manager and service.manager.broker:
641
- broker = service.manager.broker
642
- queue_names = service.config.dramatiq.queues
643
-
644
- for queue_name in queue_names:
645
- try:
646
- # Clear the queue
647
- if hasattr(broker, 'flush'):
648
- broker.flush(queue_name)
649
- logger.info(f"Cleared Dramatiq queue: {queue_name}")
650
- elif hasattr(broker, 'client'):
651
- # For Redis broker, clear using Redis client
652
- redis_client = broker.client
653
- queue_key = f"dramatiq:queue:{queue_name}"
654
- redis_client.delete(queue_key)
655
- logger.info(f"Cleared Redis queue: {queue_name}")
656
- except Exception as e:
657
- logger.warning(f"Failed to clear queue {queue_name}: {e}")
658
-
659
- logger.info("✅ Dramatiq queues cleared on startup")
660
- return True
661
- else:
662
- logger.debug("Broker not available, skipping queue clearing")
663
- return True
664
-
665
- except Exception as e:
666
- logger.error(f"Failed to clear Dramatiq queues: {e}")
667
- return False
668
-
669
-
670
306
  def initialize_task_system():
671
307
  """
672
308
  Initialize the task system during Django app startup.
@@ -708,9 +344,6 @@ def initialize_task_system():
708
344
  def extend_constance_config_with_tasks():
709
345
  """
710
346
  Extend Constance configuration with Dramatiq task fields if tasks are enabled.
711
-
712
- This function should be called during Django configuration setup to automatically
713
- add task-related Constance fields when the task system is enabled.
714
347
  """
715
348
  try:
716
349
  service = get_task_service()
@@ -727,21 +360,14 @@ def extend_constance_config_with_tasks():
727
360
  return []
728
361
 
729
362
 
730
- # === Broker Creation (Simplified) ===
731
- # Note: We now use django-dramatiq.setup() instead of custom broker creation
732
-
733
-
734
363
  # === Exports ===
735
364
 
736
365
  __all__ = [
737
366
  "DjangoTasks",
738
- "TaskManager",
739
367
  "get_task_service",
740
368
  "reset_task_service",
741
369
  "is_task_system_available",
742
370
  "get_task_health",
743
- "enqueue_task",
744
371
  "extend_constance_config_with_tasks",
745
372
  "initialize_task_system",
746
- "clear_dramatiq_queues",
747
- ]
373
+ ]
@@ -0,0 +1,16 @@
1
+ """
2
+ Dramatiq broker module for django-cfg CLI integration.
3
+
4
+ This module provides the broker instance required by Dramatiq CLI.
5
+ It's a thin wrapper around django_dramatiq.setup with broker export.
6
+
7
+ Usage:
8
+ dramatiq django_cfg.modules.dramatiq_setup [task_modules...]
9
+ """
10
+
11
+ # Import django_dramatiq setup (handles Django initialization)
12
+ import django_dramatiq.setup
13
+
14
+ # Re-export the broker for Dramatiq CLI
15
+ import dramatiq
16
+ broker = dramatiq.get_broker()