django-cfg 1.4.107__py3-none-any.whl → 1.4.109__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/views/profile.py +19 -9
- django_cfg/apps/centrifugo/views/admin_api.py +4 -7
- django_cfg/apps/centrifugo/views/monitoring.py +3 -6
- django_cfg/apps/centrifugo/views/testing_api.py +3 -6
- django_cfg/apps/dashboard/services/system_health_service.py +16 -11
- django_cfg/apps/dashboard/views/activity_views.py +3 -5
- django_cfg/apps/dashboard/views/apizones_views.py +4 -5
- django_cfg/apps/dashboard/views/charts_views.py +4 -5
- django_cfg/apps/dashboard/views/overview_views.py +4 -5
- django_cfg/apps/dashboard/views/statistics_views.py +4 -5
- django_cfg/apps/dashboard/views/system_views.py +4 -5
- django_cfg/apps/knowbase/__init__.py +2 -2
- django_cfg/apps/knowbase/apps.py +2 -8
- django_cfg/apps/knowbase/views/base.py +9 -4
- django_cfg/apps/support/views/api.py +16 -7
- django_cfg/apps/tasks/__init__.py +61 -2
- django_cfg/apps/tasks/admin/__init__.py +3 -10
- django_cfg/apps/tasks/admin/config.py +98 -0
- django_cfg/apps/tasks/admin/task_log.py +265 -0
- django_cfg/apps/tasks/apps.py +7 -9
- django_cfg/apps/tasks/filters/__init__.py +10 -0
- django_cfg/apps/tasks/filters/task_log.py +121 -0
- django_cfg/apps/tasks/migrations/0001_initial.py +196 -0
- django_cfg/apps/tasks/models/__init__.py +4 -0
- django_cfg/apps/tasks/models/task_log.py +246 -0
- django_cfg/apps/tasks/serializers/__init__.py +28 -0
- django_cfg/apps/tasks/serializers/task_log.py +249 -0
- django_cfg/apps/tasks/services/__init__.py +10 -0
- django_cfg/apps/tasks/services/client/__init__.py +7 -0
- django_cfg/apps/tasks/services/client/client.py +234 -0
- django_cfg/apps/tasks/services/config_helper.py +63 -0
- django_cfg/apps/tasks/services/sync.py +204 -0
- django_cfg/apps/tasks/urls.py +7 -13
- django_cfg/apps/tasks/views/__init__.py +4 -10
- django_cfg/apps/tasks/views/task_log.py +41 -0
- django_cfg/apps/tasks/views/task_log_base.py +41 -0
- django_cfg/apps/tasks/views/task_log_overview.py +100 -0
- django_cfg/apps/tasks/views/task_log_related.py +41 -0
- django_cfg/apps/tasks/views/task_log_stats.py +91 -0
- django_cfg/apps/tasks/views/task_log_timeline.py +81 -0
- django_cfg/apps/urls.py +0 -1
- django_cfg/cli/commands/info.py +1 -1
- django_cfg/cli/utils.py +1 -1
- django_cfg/core/base/config_model.py +1 -1
- django_cfg/core/builders/apps_builder.py +1 -1
- django_cfg/core/generation/integration_generators/__init__.py +1 -1
- django_cfg/core/generation/integration_generators/tasks.py +14 -18
- django_cfg/core/generation/security_generators/crypto_fields.py +2 -1
- django_cfg/core/integration/display/startup.py +1 -1
- django_cfg/mixins/__init__.py +12 -0
- django_cfg/mixins/admin_api.py +37 -0
- django_cfg/mixins/client_api.py +39 -0
- django_cfg/models/django/constance.py +2 -8
- django_cfg/models/django/crypto_fields.py +13 -48
- django_cfg/models/tasks/__init__.py +8 -10
- django_cfg/models/tasks/backends.py +76 -207
- django_cfg/models/tasks/config.py +20 -127
- django_cfg/models/tasks/utils.py +17 -29
- django_cfg/modules/django_client/management/commands/generate_client.py +13 -1
- django_cfg/modules/django_unfold/navigation.py +121 -22
- django_cfg/pyproject.toml +2 -2
- django_cfg/registry/core.py +1 -1
- django_cfg/static/frontend/admin.zip +0 -0
- {django_cfg-1.4.107.dist-info → django_cfg-1.4.109.dist-info}/METADATA +3 -3
- {django_cfg-1.4.107.dist-info → django_cfg-1.4.109.dist-info}/RECORD +70 -117
- django_cfg/apps/tasks/admin/actions.py +0 -29
- django_cfg/apps/tasks/admin/tasks_admin.py +0 -154
- django_cfg/apps/tasks/api/serializers.py +0 -82
- django_cfg/apps/tasks/api/views.py +0 -571
- django_cfg/apps/tasks/serializers.py +0 -82
- django_cfg/apps/tasks/static/tasks/css/dashboard-alpine.css +0 -299
- django_cfg/apps/tasks/static/tasks/css/dashboard.css +0 -120
- django_cfg/apps/tasks/static/tasks/js/alpine/README.md +0 -47
- django_cfg/apps/tasks/static/tasks/js/alpine/actions/index.js +0 -8
- django_cfg/apps/tasks/static/tasks/js/alpine/actions/management.js +0 -123
- django_cfg/apps/tasks/static/tasks/js/alpine/actions/pagination.js +0 -21
- django_cfg/apps/tasks/static/tasks/js/alpine/actions/tasks.js +0 -101
- django_cfg/apps/tasks/static/tasks/js/alpine/actions/workers.js +0 -59
- django_cfg/apps/tasks/static/tasks/js/alpine/computed.js +0 -35
- django_cfg/apps/tasks/static/tasks/js/alpine/index.js +0 -148
- django_cfg/apps/tasks/static/tasks/js/alpine/loaders/index.js +0 -36
- django_cfg/apps/tasks/static/tasks/js/alpine/loaders/overview.js +0 -37
- django_cfg/apps/tasks/static/tasks/js/alpine/loaders/queues.js +0 -27
- django_cfg/apps/tasks/static/tasks/js/alpine/loaders/tasks.js +0 -32
- django_cfg/apps/tasks/static/tasks/js/alpine/loaders/workers.js +0 -21
- django_cfg/apps/tasks/static/tasks/js/alpine/state.js +0 -36
- django_cfg/apps/tasks/static/tasks/js/alpine/utils/formatters.js +0 -42
- django_cfg/apps/tasks/static/tasks/js/alpine/utils/helpers.js +0 -68
- django_cfg/apps/tasks/static/tasks/js/dashboard-alpine.js +0 -725
- django_cfg/apps/tasks/tasks/__init__.py +0 -10
- django_cfg/apps/tasks/tasks/demo_tasks.py +0 -127
- django_cfg/apps/tasks/templates/tasks/components/management_actions.html +0 -71
- django_cfg/apps/tasks/templates/tasks/components/overview_content.html +0 -94
- django_cfg/apps/tasks/templates/tasks/components/queues_content.html +0 -44
- django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +0 -45
- django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -151
- django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +0 -61
- django_cfg/apps/tasks/templates/tasks/components/tasks_mjs_integration.html +0 -269
- django_cfg/apps/tasks/templates/tasks/components/workers_content.html +0 -60
- django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -20
- django_cfg/apps/tasks/templates/tasks/pages/dashboard-improved.html +0 -168
- django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +0 -77
- django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +0 -40
- django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +0 -40
- django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +0 -86
- django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +0 -90
- django_cfg/apps/tasks/urls_admin.py +0 -15
- django_cfg/apps/tasks/utils/__init__.py +0 -1
- django_cfg/apps/tasks/utils/simulator.py +0 -353
- django_cfg/apps/tasks/views/api.py +0 -571
- django_cfg/apps/tasks/views/dashboard.py +0 -89
- django_cfg/management/commands/rundramatiq.py +0 -24
- django_cfg/management/commands/rundramatiq_simulator.py +0 -22
- django_cfg/management/commands/task_clear.py +0 -25
- django_cfg/management/commands/task_status.py +0 -24
- django_cfg/modules/django_client/system/__init__.py +0 -24
- django_cfg/modules/django_client/system/base_generator.py +0 -123
- django_cfg/modules/django_client/system/generate_mjs_clients.py +0 -176
- django_cfg/modules/django_client/system/mjs_generator.py +0 -219
- django_cfg/modules/django_client/system/schema_parser.py +0 -199
- django_cfg/modules/django_client/system/templates/api_client.js.j2 +0 -87
- django_cfg/modules/django_client/system/templates/app_index.js.j2 +0 -13
- django_cfg/modules/django_client/system/templates/base_client.js.j2 +0 -166
- django_cfg/modules/django_client/system/templates/main_index.js.j2 +0 -80
- django_cfg/modules/django_client/system/templates/types.js.j2 +0 -24
- django_cfg/modules/django_tasks/__init__.py +0 -29
- django_cfg/modules/django_tasks/dramatiq_setup.py +0 -20
- django_cfg/modules/django_tasks/factory.py +0 -127
- django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
- django_cfg/modules/django_tasks/management/commands/rundramatiq.py +0 -253
- django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +0 -436
- django_cfg/modules/django_tasks/management/commands/task_clear.py +0 -226
- django_cfg/modules/django_tasks/management/commands/task_status.py +0 -257
- django_cfg/modules/django_tasks/service.py +0 -281
- django_cfg/modules/django_tasks/settings.py +0 -107
- /django_cfg/{modules/django_tasks/management → apps/tasks/migrations}/__init__.py +0 -0
- {django_cfg-1.4.107.dist-info → django_cfg-1.4.109.dist-info}/WHEEL +0 -0
- {django_cfg-1.4.107.dist-info → django_cfg-1.4.109.dist-info}/entry_points.txt +0 -0
- {django_cfg-1.4.107.dist-info → django_cfg-1.4.109.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Task service factory and utilities.
|
|
3
|
-
|
|
4
|
-
Provides singleton instance and utility functions.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
import logging
|
|
8
|
-
from typing import Any, Dict
|
|
9
|
-
|
|
10
|
-
logger = logging.getLogger(__name__)
|
|
11
|
-
|
|
12
|
-
# Lazy import to avoid circular dependency
|
|
13
|
-
_task_service_instance = None
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def get_task_service():
|
|
17
|
-
"""Get the global task service instance."""
|
|
18
|
-
global _task_service_instance
|
|
19
|
-
|
|
20
|
-
if _task_service_instance is None:
|
|
21
|
-
from .service import DjangoTasks
|
|
22
|
-
_task_service_instance = DjangoTasks()
|
|
23
|
-
|
|
24
|
-
return _task_service_instance
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def reset_task_service():
|
|
28
|
-
"""Reset the global task service instance (useful for testing)."""
|
|
29
|
-
global _task_service_instance
|
|
30
|
-
_task_service_instance = None
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def is_task_system_available() -> bool:
|
|
34
|
-
"""Check if task system is available and properly configured."""
|
|
35
|
-
try:
|
|
36
|
-
service = get_task_service()
|
|
37
|
-
return service.is_enabled()
|
|
38
|
-
except Exception:
|
|
39
|
-
return False
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
def get_task_health() -> Dict[str, Any]:
|
|
43
|
-
"""Get task system health status."""
|
|
44
|
-
try:
|
|
45
|
-
service = get_task_service()
|
|
46
|
-
return service.get_health_status()
|
|
47
|
-
except Exception as e:
|
|
48
|
-
return {
|
|
49
|
-
"enabled": False,
|
|
50
|
-
"error": str(e),
|
|
51
|
-
"redis_connection": False,
|
|
52
|
-
"configuration_valid": False,
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def initialize_task_system():
|
|
57
|
-
"""
|
|
58
|
-
Initialize the task system during Django app startup.
|
|
59
|
-
This function is called from Django AppConfig.ready() method.
|
|
60
|
-
"""
|
|
61
|
-
try:
|
|
62
|
-
service = get_task_service()
|
|
63
|
-
|
|
64
|
-
# Force config reload to ensure we have fresh config
|
|
65
|
-
service._config = None
|
|
66
|
-
config = service.config
|
|
67
|
-
|
|
68
|
-
if config and config.enabled:
|
|
69
|
-
logger.info("🔧 Initializing Django-CFG task system...")
|
|
70
|
-
|
|
71
|
-
# Set up Dramatiq broker from Django settings
|
|
72
|
-
try:
|
|
73
|
-
import dramatiq
|
|
74
|
-
from django.conf import settings
|
|
75
|
-
|
|
76
|
-
# Django-dramatiq automatically configures the broker from DRAMATIQ_BROKER setting
|
|
77
|
-
if hasattr(settings, 'DRAMATIQ_BROKER'):
|
|
78
|
-
# Configure broker with middleware
|
|
79
|
-
broker_config = settings.DRAMATIQ_BROKER
|
|
80
|
-
middleware_list = getattr(settings, 'DRAMATIQ_MIDDLEWARE', [])
|
|
81
|
-
|
|
82
|
-
# Import and instantiate middleware
|
|
83
|
-
middleware_instances = []
|
|
84
|
-
for middleware_path in middleware_list:
|
|
85
|
-
try:
|
|
86
|
-
module_path, class_name = middleware_path.rsplit('.', 1)
|
|
87
|
-
module = __import__(module_path, fromlist=[class_name])
|
|
88
|
-
middleware_class = getattr(module, class_name)
|
|
89
|
-
middleware_instances.append(middleware_class())
|
|
90
|
-
except Exception as e:
|
|
91
|
-
logger.warning(f"Failed to load middleware {middleware_path}: {e}")
|
|
92
|
-
|
|
93
|
-
# Create broker with middleware
|
|
94
|
-
broker_class_path = broker_config['BROKER']
|
|
95
|
-
module_path, class_name = broker_class_path.rsplit('.', 1)
|
|
96
|
-
module = __import__(module_path, fromlist=[class_name])
|
|
97
|
-
broker_class = getattr(module, class_name)
|
|
98
|
-
|
|
99
|
-
broker_options = broker_config.get('OPTIONS', {})
|
|
100
|
-
broker = broker_class(middleware=middleware_instances, **broker_options)
|
|
101
|
-
|
|
102
|
-
# Set as default broker
|
|
103
|
-
dramatiq.set_broker(broker)
|
|
104
|
-
|
|
105
|
-
logger.debug(f"✅ Dramatiq broker configured with {len(middleware_instances)} middleware")
|
|
106
|
-
else:
|
|
107
|
-
logger.warning("DRAMATIQ_BROKER not found in Django settings")
|
|
108
|
-
|
|
109
|
-
except Exception as e:
|
|
110
|
-
logger.warning(f"Failed to configure Dramatiq: {e}")
|
|
111
|
-
|
|
112
|
-
logger.info("✅ Task system initialized successfully")
|
|
113
|
-
logger.info("💡 To start workers, run: python manage.py rundramatiq")
|
|
114
|
-
else:
|
|
115
|
-
logger.debug(f"Task system not enabled (config: {config}), skipping initialization")
|
|
116
|
-
|
|
117
|
-
except Exception as e:
|
|
118
|
-
logger.error(f"Failed to initialize task system: {e}")
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
__all__ = [
|
|
122
|
-
"get_task_service",
|
|
123
|
-
"reset_task_service",
|
|
124
|
-
"is_task_system_available",
|
|
125
|
-
"get_task_health",
|
|
126
|
-
"initialize_task_system",
|
|
127
|
-
]
|
|
File without changes
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Django management command for running Dramatiq workers.
|
|
3
|
-
|
|
4
|
-
Based on django_dramatiq.management.commands.rundramatiq with Django-CFG integration.
|
|
5
|
-
Simple, clean, and working approach.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
import argparse
|
|
9
|
-
import importlib
|
|
10
|
-
import multiprocessing
|
|
11
|
-
import os
|
|
12
|
-
import sys
|
|
13
|
-
|
|
14
|
-
from django.apps import apps
|
|
15
|
-
from django.conf import settings
|
|
16
|
-
from django.core.management.base import BaseCommand
|
|
17
|
-
from django.utils.module_loading import module_has_submodule
|
|
18
|
-
|
|
19
|
-
from django_cfg.modules.django_logging import get_logger
|
|
20
|
-
from django_cfg.modules.django_tasks import get_task_service
|
|
21
|
-
|
|
22
|
-
# Default values
|
|
23
|
-
NPROCS = multiprocessing.cpu_count()
|
|
24
|
-
NTHREADS = 8
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
logger = get_logger('rundramatiq')
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
class Command(BaseCommand):
|
|
31
|
-
# Web execution metadata
|
|
32
|
-
web_executable = False
|
|
33
|
-
requires_input = False
|
|
34
|
-
is_destructive = False
|
|
35
|
-
|
|
36
|
-
help = "Run Dramatiq workers with Django-CFG configuration."
|
|
37
|
-
|
|
38
|
-
def add_arguments(self, parser):
|
|
39
|
-
parser.formatter_class = argparse.ArgumentDefaultsHelpFormatter
|
|
40
|
-
|
|
41
|
-
parser.add_argument(
|
|
42
|
-
"--processes", "-p",
|
|
43
|
-
default=NPROCS,
|
|
44
|
-
type=int,
|
|
45
|
-
help="The number of processes to run",
|
|
46
|
-
)
|
|
47
|
-
parser.add_argument(
|
|
48
|
-
"--threads", "-t",
|
|
49
|
-
default=NTHREADS,
|
|
50
|
-
type=int,
|
|
51
|
-
help="The number of threads per process to use",
|
|
52
|
-
)
|
|
53
|
-
parser.add_argument(
|
|
54
|
-
"--queues", "-Q",
|
|
55
|
-
nargs="*",
|
|
56
|
-
type=str,
|
|
57
|
-
help="Listen to a subset of queues, or all when empty",
|
|
58
|
-
)
|
|
59
|
-
parser.add_argument(
|
|
60
|
-
"--watch",
|
|
61
|
-
dest="watch_dir",
|
|
62
|
-
help="Reload workers when changes are detected in the given directory",
|
|
63
|
-
)
|
|
64
|
-
parser.add_argument(
|
|
65
|
-
"--pid-file",
|
|
66
|
-
type=str,
|
|
67
|
-
help="Write the PID of the master process to this file",
|
|
68
|
-
)
|
|
69
|
-
parser.add_argument(
|
|
70
|
-
"--log-file",
|
|
71
|
-
type=str,
|
|
72
|
-
help="Write all logs to a file, or stderr when empty",
|
|
73
|
-
)
|
|
74
|
-
parser.add_argument(
|
|
75
|
-
"--worker-shutdown-timeout",
|
|
76
|
-
type=int,
|
|
77
|
-
default=600000,
|
|
78
|
-
help="Timeout for worker shutdown, in milliseconds"
|
|
79
|
-
)
|
|
80
|
-
parser.add_argument(
|
|
81
|
-
"--dry-run",
|
|
82
|
-
action="store_true",
|
|
83
|
-
help="Show configuration without starting workers",
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
def handle(self, watch_dir, processes, threads, verbosity, queues,
|
|
87
|
-
pid_file, log_file, worker_shutdown_timeout, dry_run, **options):
|
|
88
|
-
logger.info("Starting rundramatiq command")
|
|
89
|
-
|
|
90
|
-
# Get task service and validate
|
|
91
|
-
task_service = get_task_service()
|
|
92
|
-
if not task_service.is_enabled():
|
|
93
|
-
self.stdout.write(
|
|
94
|
-
self.style.ERROR("Task system is not enabled in Django-CFG configuration")
|
|
95
|
-
)
|
|
96
|
-
return
|
|
97
|
-
|
|
98
|
-
# Discover task modules
|
|
99
|
-
tasks_modules = self._discover_tasks_modules()
|
|
100
|
-
|
|
101
|
-
# Show configuration info
|
|
102
|
-
self.stdout.write(self.style.SUCCESS("Dramatiq Worker Configuration:"))
|
|
103
|
-
self.stdout.write(f"Processes: {processes}")
|
|
104
|
-
self.stdout.write(f"Threads: {threads}")
|
|
105
|
-
if queues:
|
|
106
|
-
self.stdout.write(f"Queues: {', '.join(queues)}")
|
|
107
|
-
else:
|
|
108
|
-
self.stdout.write("Queues: all")
|
|
109
|
-
|
|
110
|
-
self.stdout.write("\nDiscovered task modules:")
|
|
111
|
-
for module in tasks_modules:
|
|
112
|
-
self.stdout.write(f" - {module}")
|
|
113
|
-
|
|
114
|
-
# If dry run, show command and exit
|
|
115
|
-
if dry_run:
|
|
116
|
-
executable_name = "dramatiq"
|
|
117
|
-
|
|
118
|
-
process_args = [
|
|
119
|
-
executable_name,
|
|
120
|
-
"django_cfg.modules.django_tasks.dramatiq_setup", # Broker module
|
|
121
|
-
"--processes", str(processes),
|
|
122
|
-
"--threads", str(threads),
|
|
123
|
-
"--worker-shutdown-timeout", str(worker_shutdown_timeout),
|
|
124
|
-
]
|
|
125
|
-
|
|
126
|
-
if watch_dir:
|
|
127
|
-
process_args.extend(["--watch", watch_dir])
|
|
128
|
-
|
|
129
|
-
verbosity_args = ["-v"] * (verbosity - 1)
|
|
130
|
-
process_args.extend(verbosity_args)
|
|
131
|
-
|
|
132
|
-
if queues:
|
|
133
|
-
process_args.extend(["--queues"] + queues)
|
|
134
|
-
|
|
135
|
-
if pid_file:
|
|
136
|
-
process_args.extend(["--pid-file", pid_file])
|
|
137
|
-
|
|
138
|
-
if log_file:
|
|
139
|
-
process_args.extend(["--log-file", log_file])
|
|
140
|
-
|
|
141
|
-
# Add task modules (broker module is already first in tasks_modules)
|
|
142
|
-
process_args.extend(tasks_modules)
|
|
143
|
-
|
|
144
|
-
self.stdout.write("\nCommand that would be executed:")
|
|
145
|
-
self.stdout.write(f' {" ".join(process_args)}')
|
|
146
|
-
return
|
|
147
|
-
|
|
148
|
-
# Show startup info
|
|
149
|
-
self.stdout.write(self.style.SUCCESS("\nStarting Dramatiq workers..."))
|
|
150
|
-
|
|
151
|
-
# Build dramatiq command
|
|
152
|
-
executable_name = "dramatiq"
|
|
153
|
-
executable_path = self._resolve_executable(executable_name)
|
|
154
|
-
|
|
155
|
-
# Build process arguments exactly like django_dramatiq
|
|
156
|
-
process_args = [
|
|
157
|
-
executable_name,
|
|
158
|
-
"django_cfg.modules.django_tasks.dramatiq_setup", # Broker module
|
|
159
|
-
"--processes", str(processes),
|
|
160
|
-
"--threads", str(threads),
|
|
161
|
-
"--worker-shutdown-timeout", str(worker_shutdown_timeout),
|
|
162
|
-
]
|
|
163
|
-
|
|
164
|
-
# Add watch directory if specified
|
|
165
|
-
if watch_dir:
|
|
166
|
-
process_args.extend(["--watch", watch_dir])
|
|
167
|
-
|
|
168
|
-
# Add verbosity
|
|
169
|
-
verbosity_args = ["-v"] * (verbosity - 1)
|
|
170
|
-
process_args.extend(verbosity_args)
|
|
171
|
-
|
|
172
|
-
# Add queues if specified
|
|
173
|
-
if queues:
|
|
174
|
-
process_args.extend(["--queues"] + queues)
|
|
175
|
-
|
|
176
|
-
# Add PID file if specified
|
|
177
|
-
if pid_file:
|
|
178
|
-
process_args.extend(["--pid-file", pid_file])
|
|
179
|
-
|
|
180
|
-
# Add log file if specified
|
|
181
|
-
if log_file:
|
|
182
|
-
process_args.extend(["--log-file", log_file])
|
|
183
|
-
|
|
184
|
-
# Add task modules (broker module is already first in tasks_modules)
|
|
185
|
-
process_args.extend(tasks_modules)
|
|
186
|
-
|
|
187
|
-
self.stdout.write(f'Running dramatiq: "{" ".join(process_args)}"\n')
|
|
188
|
-
|
|
189
|
-
# Ensure DJANGO_SETTINGS_MODULE is set for worker processes
|
|
190
|
-
if not os.environ.get('DJANGO_SETTINGS_MODULE'):
|
|
191
|
-
if hasattr(settings, 'SETTINGS_MODULE'):
|
|
192
|
-
os.environ['DJANGO_SETTINGS_MODULE'] = settings.SETTINGS_MODULE
|
|
193
|
-
else:
|
|
194
|
-
# Try to detect from manage.py or current settings
|
|
195
|
-
from django.conf import settings as django_settings
|
|
196
|
-
if hasattr(django_settings, '_wrapped') and hasattr(django_settings._wrapped, '__module__'):
|
|
197
|
-
module_name = django_settings._wrapped.__module__
|
|
198
|
-
os.environ['DJANGO_SETTINGS_MODULE'] = module_name
|
|
199
|
-
else:
|
|
200
|
-
self.stdout.write(
|
|
201
|
-
self.style.WARNING("Could not detect DJANGO_SETTINGS_MODULE")
|
|
202
|
-
)
|
|
203
|
-
|
|
204
|
-
# Use os.execvp like django_dramatiq to preserve environment
|
|
205
|
-
if sys.platform == "win32":
|
|
206
|
-
import subprocess
|
|
207
|
-
command = [executable_path] + process_args[1:]
|
|
208
|
-
sys.exit(subprocess.run(command))
|
|
209
|
-
|
|
210
|
-
os.execvp(executable_path, process_args)
|
|
211
|
-
|
|
212
|
-
def _discover_tasks_modules(self):
|
|
213
|
-
"""Discover task modules like django_dramatiq does."""
|
|
214
|
-
# Always include our broker setup module first
|
|
215
|
-
tasks_modules = ["django_cfg.modules.django_tasks.dramatiq_setup"]
|
|
216
|
-
|
|
217
|
-
# Get task service for configuration
|
|
218
|
-
task_service = get_task_service()
|
|
219
|
-
|
|
220
|
-
# Try to get task modules from Django-CFG config
|
|
221
|
-
if task_service.config and task_service.config.auto_discover_tasks:
|
|
222
|
-
discovered = task_service.discover_tasks()
|
|
223
|
-
for module_name in discovered:
|
|
224
|
-
self.stdout.write(f"Discovered tasks module: '{module_name}'")
|
|
225
|
-
tasks_modules.append(module_name)
|
|
226
|
-
|
|
227
|
-
# Fallback: use django_dramatiq discovery logic
|
|
228
|
-
if len(tasks_modules) == 1: # Only broker module found
|
|
229
|
-
task_module_names = getattr(settings, "DRAMATIQ_AUTODISCOVER_MODULES", ("tasks",))
|
|
230
|
-
|
|
231
|
-
for app_config in apps.get_app_configs():
|
|
232
|
-
for task_module in task_module_names:
|
|
233
|
-
if module_has_submodule(app_config.module, task_module):
|
|
234
|
-
module_name = f"{app_config.name}.{task_module}"
|
|
235
|
-
try:
|
|
236
|
-
importlib.import_module(module_name)
|
|
237
|
-
self.stdout.write(f"Discovered tasks module: '{module_name}'")
|
|
238
|
-
tasks_modules.append(module_name)
|
|
239
|
-
except ImportError:
|
|
240
|
-
# Module exists but has import errors, skip it
|
|
241
|
-
pass
|
|
242
|
-
|
|
243
|
-
return tasks_modules
|
|
244
|
-
|
|
245
|
-
def _resolve_executable(self, exec_name):
|
|
246
|
-
"""Resolve executable path like django_dramatiq does."""
|
|
247
|
-
bin_dir = os.path.dirname(sys.executable)
|
|
248
|
-
if bin_dir:
|
|
249
|
-
for d in [bin_dir, os.path.join(bin_dir, "Scripts")]:
|
|
250
|
-
exec_path = os.path.join(d, exec_name)
|
|
251
|
-
if os.path.isfile(exec_path):
|
|
252
|
-
return exec_path
|
|
253
|
-
return exec_name
|