django-cfg 1.4.106__py3-none-any.whl → 1.4.108__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 (137) hide show
  1. django_cfg/__init__.py +1 -1
  2. django_cfg/apps/accounts/views/profile.py +19 -9
  3. django_cfg/apps/centrifugo/views/admin_api.py +4 -7
  4. django_cfg/apps/centrifugo/views/monitoring.py +3 -6
  5. django_cfg/apps/centrifugo/views/testing_api.py +3 -6
  6. django_cfg/apps/dashboard/services/system_health_service.py +16 -11
  7. django_cfg/apps/dashboard/views/activity_views.py +3 -5
  8. django_cfg/apps/dashboard/views/apizones_views.py +4 -5
  9. django_cfg/apps/dashboard/views/charts_views.py +4 -5
  10. django_cfg/apps/dashboard/views/overview_views.py +4 -5
  11. django_cfg/apps/dashboard/views/statistics_views.py +4 -5
  12. django_cfg/apps/dashboard/views/system_views.py +4 -5
  13. django_cfg/apps/knowbase/__init__.py +2 -2
  14. django_cfg/apps/knowbase/apps.py +2 -8
  15. django_cfg/apps/knowbase/views/base.py +9 -4
  16. django_cfg/apps/support/views/api.py +16 -7
  17. django_cfg/apps/tasks/__init__.py +61 -2
  18. django_cfg/apps/tasks/admin/__init__.py +3 -10
  19. django_cfg/apps/tasks/admin/config.py +98 -0
  20. django_cfg/apps/tasks/admin/task_log.py +265 -0
  21. django_cfg/apps/tasks/apps.py +7 -9
  22. django_cfg/apps/tasks/filters/__init__.py +10 -0
  23. django_cfg/apps/tasks/filters/task_log.py +121 -0
  24. django_cfg/apps/tasks/migrations/0001_initial.py +196 -0
  25. django_cfg/apps/tasks/models/__init__.py +4 -0
  26. django_cfg/apps/tasks/models/task_log.py +246 -0
  27. django_cfg/apps/tasks/serializers/__init__.py +28 -0
  28. django_cfg/apps/tasks/serializers/task_log.py +249 -0
  29. django_cfg/apps/tasks/services/__init__.py +10 -0
  30. django_cfg/apps/tasks/services/client/__init__.py +7 -0
  31. django_cfg/apps/tasks/services/client/client.py +234 -0
  32. django_cfg/apps/tasks/services/config_helper.py +63 -0
  33. django_cfg/apps/tasks/services/sync.py +204 -0
  34. django_cfg/apps/tasks/urls.py +7 -13
  35. django_cfg/apps/tasks/views/__init__.py +4 -10
  36. django_cfg/apps/tasks/views/task_log.py +41 -0
  37. django_cfg/apps/tasks/views/task_log_base.py +41 -0
  38. django_cfg/apps/tasks/views/task_log_overview.py +100 -0
  39. django_cfg/apps/tasks/views/task_log_related.py +41 -0
  40. django_cfg/apps/tasks/views/task_log_stats.py +91 -0
  41. django_cfg/apps/tasks/views/task_log_timeline.py +81 -0
  42. django_cfg/apps/urls.py +0 -1
  43. django_cfg/cli/commands/info.py +1 -1
  44. django_cfg/cli/utils.py +1 -1
  45. django_cfg/core/base/config_model.py +1 -1
  46. django_cfg/core/builders/apps_builder.py +1 -1
  47. django_cfg/core/generation/integration_generators/__init__.py +1 -1
  48. django_cfg/core/generation/integration_generators/tasks.py +14 -18
  49. django_cfg/core/generation/security_generators/crypto_fields.py +2 -1
  50. django_cfg/core/integration/display/startup.py +1 -1
  51. django_cfg/mixins/__init__.py +12 -0
  52. django_cfg/mixins/admin_api.py +37 -0
  53. django_cfg/mixins/client_api.py +39 -0
  54. django_cfg/models/django/constance.py +2 -8
  55. django_cfg/models/django/crypto_fields.py +13 -48
  56. django_cfg/models/tasks/__init__.py +8 -10
  57. django_cfg/models/tasks/backends.py +76 -207
  58. django_cfg/models/tasks/config.py +20 -127
  59. django_cfg/models/tasks/utils.py +17 -29
  60. django_cfg/modules/django_admin/RESOURCE_CONFIG_ENHANCEMENT.md +350 -0
  61. django_cfg/modules/django_admin/__init__.py +4 -0
  62. django_cfg/modules/django_admin/base/pydantic_admin.py +70 -15
  63. django_cfg/modules/django_admin/config/__init__.py +4 -0
  64. django_cfg/modules/django_admin/config/admin_config.py +13 -1
  65. django_cfg/modules/django_admin/config/background_task_config.py +76 -0
  66. django_cfg/modules/django_admin/config/resource_config.py +129 -0
  67. django_cfg/modules/django_client/management/commands/generate_client.py +13 -1
  68. django_cfg/modules/django_unfold/navigation.py +121 -22
  69. django_cfg/pyproject.toml +2 -2
  70. django_cfg/registry/core.py +1 -1
  71. django_cfg/static/frontend/admin.zip +0 -0
  72. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/METADATA +5 -3
  73. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/RECORD +77 -111
  74. django_cfg/apps/tasks/admin/actions.py +0 -29
  75. django_cfg/apps/tasks/admin/tasks_admin.py +0 -154
  76. django_cfg/apps/tasks/api/serializers.py +0 -82
  77. django_cfg/apps/tasks/api/views.py +0 -571
  78. django_cfg/apps/tasks/serializers.py +0 -82
  79. django_cfg/apps/tasks/static/tasks/css/dashboard-alpine.css +0 -299
  80. django_cfg/apps/tasks/static/tasks/css/dashboard.css +0 -120
  81. django_cfg/apps/tasks/static/tasks/js/alpine/README.md +0 -47
  82. django_cfg/apps/tasks/static/tasks/js/alpine/actions/index.js +0 -8
  83. django_cfg/apps/tasks/static/tasks/js/alpine/actions/management.js +0 -123
  84. django_cfg/apps/tasks/static/tasks/js/alpine/actions/pagination.js +0 -21
  85. django_cfg/apps/tasks/static/tasks/js/alpine/actions/tasks.js +0 -101
  86. django_cfg/apps/tasks/static/tasks/js/alpine/actions/workers.js +0 -59
  87. django_cfg/apps/tasks/static/tasks/js/alpine/computed.js +0 -35
  88. django_cfg/apps/tasks/static/tasks/js/alpine/index.js +0 -148
  89. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/index.js +0 -36
  90. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/overview.js +0 -37
  91. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/queues.js +0 -27
  92. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/tasks.js +0 -32
  93. django_cfg/apps/tasks/static/tasks/js/alpine/loaders/workers.js +0 -21
  94. django_cfg/apps/tasks/static/tasks/js/alpine/state.js +0 -36
  95. django_cfg/apps/tasks/static/tasks/js/alpine/utils/formatters.js +0 -42
  96. django_cfg/apps/tasks/static/tasks/js/alpine/utils/helpers.js +0 -68
  97. django_cfg/apps/tasks/static/tasks/js/dashboard-alpine.js +0 -725
  98. django_cfg/apps/tasks/tasks/__init__.py +0 -10
  99. django_cfg/apps/tasks/tasks/demo_tasks.py +0 -127
  100. django_cfg/apps/tasks/templates/tasks/components/management_actions.html +0 -71
  101. django_cfg/apps/tasks/templates/tasks/components/overview_content.html +0 -94
  102. django_cfg/apps/tasks/templates/tasks/components/queues_content.html +0 -44
  103. django_cfg/apps/tasks/templates/tasks/components/tab_navigation.html +0 -45
  104. django_cfg/apps/tasks/templates/tasks/components/task_details_modal.html +0 -151
  105. django_cfg/apps/tasks/templates/tasks/components/tasks_content.html +0 -61
  106. django_cfg/apps/tasks/templates/tasks/components/tasks_mjs_integration.html +0 -269
  107. django_cfg/apps/tasks/templates/tasks/components/workers_content.html +0 -60
  108. django_cfg/apps/tasks/templates/tasks/layout/base.html +0 -20
  109. django_cfg/apps/tasks/templates/tasks/pages/dashboard-improved.html +0 -168
  110. django_cfg/apps/tasks/templates/tasks/pages/dashboard.html +0 -77
  111. django_cfg/apps/tasks/templates/tasks/partials/task_row_template.html +0 -40
  112. django_cfg/apps/tasks/templates/tasks/widgets/task_filters.html +0 -40
  113. django_cfg/apps/tasks/templates/tasks/widgets/task_footer.html +0 -86
  114. django_cfg/apps/tasks/templates/tasks/widgets/task_table.html +0 -90
  115. django_cfg/apps/tasks/urls_admin.py +0 -15
  116. django_cfg/apps/tasks/utils/__init__.py +0 -1
  117. django_cfg/apps/tasks/utils/simulator.py +0 -353
  118. django_cfg/apps/tasks/views/api.py +0 -571
  119. django_cfg/apps/tasks/views/dashboard.py +0 -89
  120. django_cfg/management/commands/rundramatiq.py +0 -24
  121. django_cfg/management/commands/rundramatiq_simulator.py +0 -22
  122. django_cfg/management/commands/task_clear.py +0 -25
  123. django_cfg/management/commands/task_status.py +0 -24
  124. django_cfg/modules/django_tasks/__init__.py +0 -29
  125. django_cfg/modules/django_tasks/dramatiq_setup.py +0 -20
  126. django_cfg/modules/django_tasks/factory.py +0 -127
  127. django_cfg/modules/django_tasks/management/commands/__init__.py +0 -0
  128. django_cfg/modules/django_tasks/management/commands/rundramatiq.py +0 -253
  129. django_cfg/modules/django_tasks/management/commands/rundramatiq_simulator.py +0 -436
  130. django_cfg/modules/django_tasks/management/commands/task_clear.py +0 -226
  131. django_cfg/modules/django_tasks/management/commands/task_status.py +0 -257
  132. django_cfg/modules/django_tasks/service.py +0 -281
  133. django_cfg/modules/django_tasks/settings.py +0 -107
  134. /django_cfg/{modules/django_tasks/management → apps/tasks/migrations}/__init__.py +0 -0
  135. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/WHEEL +0 -0
  136. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/entry_points.txt +0 -0
  137. {django_cfg-1.4.106.dist-info → django_cfg-1.4.108.dist-info}/licenses/LICENSE +0 -0
@@ -1,253 +1,122 @@
1
1
  """
2
2
  Backend-specific configurations.
3
3
 
4
- Contains Dramatiq and Worker configuration models.
5
- Size: ~200 lines (focused on backend settings)
4
+ Contains ReArq configuration model.
5
+ Size: ~100 lines (focused on backend settings)
6
6
  """
7
7
 
8
8
  import logging
9
- import os
10
- from typing import List, Literal, Optional
9
+ from typing import Any, Dict
11
10
 
12
11
  from pydantic import BaseModel, Field, field_validator
13
12
 
14
13
  logger = logging.getLogger(__name__)
15
14
 
16
15
 
17
- class DramatiqConfig(BaseModel):
16
+ class RearqConfig(BaseModel):
18
17
  """
19
- Dramatiq-specific configuration with production-ready defaults.
18
+ ReArq-specific configuration with production-ready defaults.
20
19
 
21
- This model provides comprehensive configuration for Dramatiq background
20
+ This model provides comprehensive configuration for ReArq async background
22
21
  task processing, including Redis settings, worker configuration,
23
- middleware stack, and monitoring options.
22
+ and job retry policies.
24
23
 
25
24
  Example:
26
25
  ```python
27
- from django_cfg.models.tasks import DramatiqConfig
26
+ from django_cfg.models.tasks import RearqConfig
28
27
 
29
- dramatiq = DramatiqConfig(
30
- redis_db=1,
31
- processes=4,
32
- threads=8,
28
+ rearq = RearqConfig(
29
+ redis_url="redis://localhost:6379/0",
30
+ db_url="sqlite://./rearq.db",
31
+ max_jobs=10,
32
+ job_timeout=300,
33
33
  )
34
34
  ```
35
35
  """
36
36
 
37
- # === Redis Configuration ===
38
- redis_db: int = Field(
39
- default=1,
40
- ge=0,
41
- le=15,
42
- description="Redis database number for tasks (separate from cache)"
37
+ # === Core Settings ===
38
+ redis_url: str = Field(
39
+ default="redis://localhost:6379/0",
40
+ description="Redis connection URL for task queue"
43
41
  )
44
- redis_key_prefix: str = Field(
45
- default="dramatiq",
46
- description="Redis key prefix for task data"
42
+ db_url: str = Field(
43
+ default="sqlite://./rearq.db",
44
+ description="Database URL for job persistence (Tortoise ORM)"
47
45
  )
48
46
 
49
- # === Task Configuration ===
50
- max_retries: int = Field(
51
- default=3,
52
- ge=0,
53
- le=10,
54
- description="Default maximum retry count for failed tasks"
55
- )
56
- default_priority: int = Field(
57
- default=5,
58
- ge=0,
59
- le=10,
60
- description="Default task priority (0=highest, 10=lowest)"
61
- )
62
- max_age_seconds: int = Field(
63
- default=3600,
64
- ge=60,
65
- description="Maximum age for tasks before they expire"
47
+ # === Worker Settings ===
48
+ max_jobs: int = Field(
49
+ default=10,
50
+ ge=1,
51
+ le=100,
52
+ description="Maximum concurrent jobs per worker"
66
53
  )
67
- time_limit_seconds: int = Field(
68
- default=600,
54
+ job_timeout: int = Field(
55
+ default=300,
69
56
  ge=30,
70
- description="Maximum execution time per task"
57
+ le=3600,
58
+ description="Default job timeout in seconds"
71
59
  )
72
-
73
- # === Worker Configuration ===
74
- processes: int = Field(
75
- default=4,
76
- ge=1,
77
- le=32,
78
- description="Number of worker processes"
60
+ job_retry: int = Field(
61
+ default=3,
62
+ ge=0,
63
+ le=10,
64
+ description="Default number of retries for failed jobs"
79
65
  )
80
- threads: int = Field(
81
- default=8,
66
+ job_retry_after: int = Field(
67
+ default=60,
82
68
  ge=1,
83
- le=64,
84
- description="Number of threads per worker process"
85
- )
86
- queues: List[str] = Field(
87
- default=["default", "high", "low"],
88
- description="Available task queues"
89
- )
90
-
91
- # === Middleware Stack ===
92
- middleware: List[str] = Field(
93
- default=[
94
- "dramatiq.middleware.AgeLimit",
95
- "dramatiq.middleware.TimeLimit",
96
- "dramatiq.middleware.Callbacks",
97
- "dramatiq.middleware.Retries",
98
- # NOTE: Results middleware requires backend configuration
99
- # "dramatiq.results.middleware.Results",
100
- "dramatiq.middleware.Prometheus",
101
- "django_dramatiq.middleware.AdminMiddleware",
102
- "django_dramatiq.middleware.DbConnectionsMiddleware",
103
- ],
104
- description="Middleware stack for task processing"
69
+ description="Delay in seconds before retrying failed job"
105
70
  )
106
71
 
107
- # === Monitoring & Admin ===
108
- prometheus_enabled: bool = Field(
109
- default=True,
110
- description="Enable Prometheus metrics collection"
111
- )
112
- admin_enabled: bool = Field(
113
- default=True,
114
- description="Enable Django admin interface integration"
115
- )
116
-
117
- # === Performance Tuning ===
118
- prefetch_multiplier: int = Field(
119
- default=2,
72
+ # === Cleanup Settings ===
73
+ keep_job_days: int | None = Field(
74
+ default=7,
120
75
  ge=1,
121
- le=10,
122
- description="Message prefetch multiplier for workers"
123
- )
124
- max_memory_mb: Optional[int] = Field(
125
- default=512,
126
- ge=128,
127
- description="Maximum memory usage per worker (MB)"
76
+ description="Days to keep job history (None = forever)"
128
77
  )
129
78
 
130
- @field_validator("processes")
79
+ @field_validator("redis_url")
131
80
  @classmethod
132
- def validate_processes(cls, v: int) -> int:
133
- """Ensure reasonable process count based on CPU cores."""
134
- cpu_count = os.cpu_count() or 4
135
- max_recommended = cpu_count * 2
136
-
137
- if v > max_recommended:
138
- logger.warning(
139
- f"Process count ({v}) exceeds recommended maximum ({max_recommended}). "
140
- f"Consider reducing to avoid resource contention."
141
- )
142
-
81
+ def validate_redis_url(cls, v: str) -> str:
82
+ """Validate Redis URL format."""
83
+ if not v.startswith(("redis://", "rediss://")):
84
+ raise ValueError("Redis URL must start with redis:// or rediss://")
143
85
  return v
144
86
 
145
- @field_validator("queues")
87
+ @field_validator("db_url")
146
88
  @classmethod
147
- def validate_queues(cls, v: List[str]) -> List[str]:
148
- """Ensure queue names are valid and include default."""
149
- if not v:
150
- raise ValueError("At least one queue must be specified")
151
-
152
- # Ensure 'default' queue exists
153
- if "default" not in v:
154
- v.append("default")
155
-
156
- # Validate queue names (alphanumeric + underscore/hyphen)
157
- import re
158
- pattern = re.compile(r'^[a-zA-Z0-9_-]+$')
159
-
160
- for queue in v:
161
- if not pattern.match(queue):
162
- raise ValueError(f"Invalid queue name: {queue}. Use only alphanumeric, underscore, and hyphen.")
163
-
89
+ def validate_db_url(cls, v: str) -> str:
90
+ """Validate database URL format."""
91
+ valid_schemes = ("sqlite://", "postgres://", "postgresql://", "mysql://")
92
+ if not v.startswith(valid_schemes):
93
+ raise ValueError(f"Database URL must start with one of: {valid_schemes}")
164
94
  return v
165
95
 
166
- @field_validator("middleware")
167
- @classmethod
168
- def validate_middleware(cls, v: List[str]) -> List[str]:
169
- """Ensure essential middleware is included."""
170
- essential_middleware = [
171
- "dramatiq.middleware.Retries",
172
- "django_dramatiq.middleware.DbConnectionsMiddleware",
173
- ]
174
-
175
- for middleware in essential_middleware:
176
- if middleware not in v:
177
- logger.warning(f"Adding essential middleware: {middleware}")
178
- v.append(middleware)
179
-
180
- return v
181
-
182
-
183
- class WorkerConfig(BaseModel):
184
- """
185
- Worker process and resource configuration.
186
-
187
- Provides fine-grained control over worker behavior, resource limits,
188
- and health monitoring settings.
189
-
190
- Example:
191
- ```python
192
- from django_cfg.models.tasks import WorkerConfig
193
-
194
- worker = WorkerConfig(
195
- shutdown_timeout=30,
196
- max_memory_mb=512,
197
- health_check_enabled=True,
198
- )
199
- ```
200
- """
201
-
202
- # === Process Management ===
203
- shutdown_timeout: int = Field(
204
- default=30,
205
- ge=5,
206
- le=300,
207
- description="Graceful shutdown timeout in seconds"
208
- )
209
- heartbeat_interval: int = Field(
210
- default=5,
211
- ge=1,
212
- le=60,
213
- description="Worker heartbeat interval in seconds"
214
- )
215
-
216
- # === Resource Limits ===
217
- max_memory_mb: Optional[int] = Field(
218
- default=512,
219
- ge=128,
220
- description="Maximum memory per worker process (MB)"
221
- )
222
- max_cpu_percent: Optional[float] = Field(
223
- default=80.0,
224
- ge=10.0,
225
- le=100.0,
226
- description="Maximum CPU usage per worker (%)"
227
- )
228
-
229
- # === Health Monitoring ===
230
- health_check_enabled: bool = Field(
231
- default=True,
232
- description="Enable worker health monitoring"
233
- )
234
- restart_on_memory_limit: bool = Field(
235
- default=True,
236
- description="Restart worker if memory limit exceeded"
237
- )
238
-
239
- # === Logging ===
240
- log_level: Literal["DEBUG", "INFO", "WARNING", "ERROR"] = Field(
241
- default="INFO",
242
- description="Worker log level"
243
- )
244
- log_format: str = Field(
245
- default="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
246
- description="Log message format"
247
- )
96
+ def to_django_settings(self) -> Dict[str, Any]:
97
+ """
98
+ Generate Django settings dictionary.
99
+
100
+ Returns:
101
+ Dictionary with ReArq configuration for Django settings
102
+
103
+ Example:
104
+ >>> config = RearqConfig()
105
+ >>> settings = config.to_django_settings()
106
+ >>> "REARQ_REDIS_URL" in settings
107
+ True
108
+ """
109
+ return {
110
+ "REARQ_REDIS_URL": self.redis_url,
111
+ "REARQ_DB_URL": self.db_url,
112
+ "REARQ_MAX_JOBS": self.max_jobs,
113
+ "REARQ_JOB_TIMEOUT": self.job_timeout,
114
+ "REARQ_JOB_RETRY": self.job_retry,
115
+ "REARQ_JOB_RETRY_AFTER": self.job_retry_after,
116
+ "REARQ_KEEP_JOB_DAYS": self.keep_job_days,
117
+ }
248
118
 
249
119
 
250
120
  __all__ = [
251
- "DramatiqConfig",
252
- "WorkerConfig",
121
+ "RearqConfig",
253
122
  ]
@@ -19,8 +19,7 @@ logger = logging.getLogger(__name__)
19
19
 
20
20
  class TaskBackend(str, Enum):
21
21
  """Supported task backends."""
22
- DRAMATIQ = "dramatiq"
23
- # Future: CELERY = "celery"
22
+ REARQ = "rearq"
24
23
 
25
24
 
26
25
  class QueuePriority(str, Enum):
@@ -56,7 +55,7 @@ class TaskConfig(BaseModel, BaseCfgAutoModule):
56
55
  description="Enable background task processing"
57
56
  )
58
57
  backend: TaskBackend = Field(
59
- default=TaskBackend.DRAMATIQ,
58
+ default=TaskBackend.REARQ,
60
59
  description="Task processing backend"
61
60
  )
62
61
 
@@ -67,23 +66,16 @@ class TaskConfig(BaseModel, BaseCfgAutoModule):
67
66
  self._config = None
68
67
 
69
68
  # === Backend-Specific Configuration ===
70
- dramatiq: 'DramatiqConfig' = Field(
69
+ rearq: 'RearqConfig' = Field(
71
70
  default_factory=lambda: None,
72
- description="Dramatiq-specific configuration"
73
- )
74
- worker: 'WorkerConfig' = Field(
75
- default_factory=lambda: None,
76
- description="Worker configuration"
71
+ description="ReArq-specific configuration"
77
72
  )
78
73
 
79
74
  def model_post_init(self, __context: Any) -> None:
80
75
  """Initialize backend configs with defaults after model creation."""
81
- if self.dramatiq is None:
82
- from .backends import DramatiqConfig
83
- self.dramatiq = DramatiqConfig()
84
- if self.worker is None:
85
- from .backends import WorkerConfig
86
- self.worker = WorkerConfig()
76
+ if self.rearq is None:
77
+ from .backends import RearqConfig
78
+ self.rearq = RearqConfig()
87
79
 
88
80
  # === Environment-Specific Overrides ===
89
81
  dev_processes: Optional[int] = Field(
@@ -120,124 +112,26 @@ class TaskConfig(BaseModel, BaseCfgAutoModule):
120
112
 
121
113
  return v
122
114
 
123
- def get_effective_processes(self, debug: bool = False) -> int:
124
- """
125
- Get effective number of processes based on environment.
126
-
127
- Args:
128
- debug: Whether in debug mode
129
-
130
- Returns:
131
- Number of worker processes to use
132
-
133
- Example:
134
- >>> config = TaskConfig()
135
- >>> config.get_effective_processes(debug=True)
136
- 2
137
- """
138
- if debug and self.dev_processes is not None:
139
- return self.dev_processes
140
- elif not debug and self.prod_processes is not None:
141
- return self.prod_processes
142
- else:
143
- return self.dramatiq.processes
144
-
145
- def get_effective_queues(self) -> List[str]:
146
- """
147
- Get effective queue configuration.
148
-
149
- Returns:
150
- List of queue names
151
-
152
- Example:
153
- >>> config = TaskConfig()
154
- >>> config.get_effective_queues()
155
- ['default', 'high', 'low']
156
- """
157
- return self.dramatiq.queues
158
-
159
- def get_redis_config(self, redis_url: str) -> Dict[str, Any]:
115
+ def to_django_settings(self) -> Dict[str, Any]:
160
116
  """
161
- Generate Redis configuration for Dramatiq.
162
-
163
- Args:
164
- redis_url: Redis connection URL
117
+ Generate Django settings for task system.
165
118
 
166
119
  Returns:
167
- Dictionary with Redis connection parameters
120
+ Dictionary with task configuration for Django settings
168
121
 
169
122
  Example:
170
123
  >>> config = TaskConfig()
171
- >>> config.get_redis_config("redis://localhost:6379/1")
172
- {'host': 'localhost', 'port': 6379, 'db': 1, 'password': None}
173
- """
174
- from urllib.parse import urlparse
175
-
176
- # Parse Redis URL
177
- parsed = urlparse(redis_url)
178
-
179
- # Build Redis config
180
- config = {
181
- "host": parsed.hostname or "localhost",
182
- "port": parsed.port or 6379,
183
- "db": self.dramatiq.redis_db,
184
- "password": parsed.password,
185
- }
186
-
187
- # Add SSL if specified
188
- if parsed.scheme == "rediss":
189
- config["ssl"] = True
190
-
191
- return config
192
-
193
- def get_dramatiq_settings(self, redis_url: str) -> Dict[str, Any]:
124
+ >>> settings = config.to_django_settings()
125
+ >>> "REARQ_REDIS_URL" in settings
126
+ True
194
127
  """
195
- Generate complete Dramatiq settings for Django.
128
+ if not self.enabled:
129
+ return {}
196
130
 
197
- Args:
198
- redis_url: Redis connection URL
199
-
200
- Returns:
201
- Dictionary with complete Dramatiq configuration
131
+ if self.backend == TaskBackend.REARQ:
132
+ return self.rearq.to_django_settings()
202
133
 
203
- Example:
204
- >>> config = TaskConfig()
205
- >>> settings = config.get_dramatiq_settings("redis://localhost:6379/1")
206
- >>> "DRAMATIQ_BROKER" in settings
207
- True
208
- """
209
- from urllib.parse import urlparse
210
-
211
- redis_config = self.get_redis_config(redis_url)
212
- parsed = urlparse(redis_url)
213
-
214
- # Build Redis URL with correct database
215
- redis_url_with_db = redis_url
216
- if parsed.path and parsed.path != "/":
217
- # Replace existing database in URL
218
- redis_url_with_db = redis_url.replace(parsed.path, f"/{self.dramatiq.redis_db}")
219
- else:
220
- # Add database to URL
221
- redis_url_with_db = f"{redis_url.rstrip('/')}/{self.dramatiq.redis_db}"
222
-
223
- return {
224
- "DRAMATIQ_BROKER": {
225
- "BROKER": "dramatiq.brokers.redis.RedisBroker",
226
- "OPTIONS": {
227
- "url": redis_url_with_db,
228
- **redis_config
229
- },
230
- },
231
- "DRAMATIQ_RESULT_BACKEND": {
232
- "BACKEND": "dramatiq.results.backends.redis.RedisBackend",
233
- "BACKEND_OPTIONS": {
234
- "url": redis_url_with_db,
235
- **redis_config
236
- },
237
- },
238
- "DRAMATIQ_MIDDLEWARE": self.dramatiq.middleware,
239
- "DRAMATIQ_QUEUES": self.dramatiq.queues,
240
- }
134
+ return {}
241
135
 
242
136
  def get_smart_defaults(self):
243
137
  """
@@ -303,7 +197,7 @@ class TaskConfig(BaseModel, BaseCfgAutoModule):
303
197
 
304
198
 
305
199
  # Resolve forward references for Pydantic v2
306
- from .backends import DramatiqConfig, WorkerConfig
200
+ from .backends import RearqConfig
307
201
 
308
202
  TaskConfig.model_rebuild()
309
203
 
@@ -311,6 +205,5 @@ __all__ = [
311
205
  "TaskConfig",
312
206
  "TaskBackend",
313
207
  "QueuePriority",
314
- "DramatiqConfig",
315
- "WorkerConfig",
208
+ "RearqConfig",
316
209
  ]
@@ -84,41 +84,30 @@ def get_default_task_config(debug: bool = False) -> 'TaskConfig':
84
84
 
85
85
  Example:
86
86
  >>> config = get_default_task_config(debug=True)
87
- >>> config.dramatiq.processes
88
- 2
87
+ >>> config.rearq.max_jobs
88
+ 10
89
89
  """
90
- from .backends import DramatiqConfig, WorkerConfig
90
+ from .backends import RearqConfig
91
91
  from .config import TaskConfig
92
92
 
93
- smart_queues = get_smart_queues(debug)
94
-
95
93
  if debug:
96
94
  # Development defaults
97
95
  return TaskConfig(
98
- dramatiq=DramatiqConfig(
99
- processes=2,
100
- threads=4,
101
- prometheus_enabled=False,
102
- queues=smart_queues,
103
- ),
104
- worker=WorkerConfig(
105
- log_level="DEBUG",
106
- health_check_enabled=False,
96
+ rearq=RearqConfig(
97
+ redis_url="redis://localhost:6379/0",
98
+ db_url="sqlite://./rearq.db",
99
+ max_jobs=5,
100
+ job_timeout=300,
107
101
  )
108
102
  )
109
103
  else:
110
104
  # Production defaults
111
105
  return TaskConfig(
112
- dramatiq=DramatiqConfig(
113
- processes=8,
114
- threads=16,
115
- prometheus_enabled=True,
116
- queues=smart_queues,
117
- ),
118
- worker=WorkerConfig(
119
- log_level="INFO",
120
- health_check_enabled=True,
121
- restart_on_memory_limit=True,
106
+ rearq=RearqConfig(
107
+ redis_url="redis://localhost:6379/0",
108
+ db_url="postgresql://localhost/rearq",
109
+ max_jobs=20,
110
+ job_timeout=600,
122
111
  )
123
112
  )
124
113
 
@@ -138,7 +127,7 @@ def validate_task_config(config: 'TaskConfig', redis_url: Optional[str] = None)
138
127
 
139
128
  Example:
140
129
  >>> config = get_default_task_config()
141
- >>> validate_task_config(config, "redis://localhost:6379/1")
130
+ >>> validate_task_config(config, "redis://localhost:6379/0")
142
131
  True
143
132
  """
144
133
  if not config.enabled:
@@ -156,12 +145,11 @@ def validate_task_config(config: 'TaskConfig', redis_url: Optional[str] = None)
156
145
  logger.error(f"Invalid Redis URL: {e}")
157
146
  return False
158
147
 
159
- # Check if Dramatiq is available
148
+ # Check if ReArq is available
160
149
  try:
161
- import django_dramatiq
162
- import dramatiq
150
+ import rearq
163
151
  except ImportError as e:
164
- logger.error(f"Dramatiq dependencies not available: {e}")
152
+ logger.error(f"ReArq dependencies not available: {e}")
165
153
  return False
166
154
 
167
155
  return True