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
@@ -0,0 +1,196 @@
1
+ # Generated by Django 5.2.7 on 2025-10-30 11:15
2
+
3
+ import django.db.models.deletion
4
+ from django.conf import settings
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+ initial = True
10
+
11
+ dependencies = [
12
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
13
+ ]
14
+
15
+ operations = [
16
+ migrations.CreateModel(
17
+ name="TaskLog",
18
+ fields=[
19
+ (
20
+ "id",
21
+ models.BigAutoField(
22
+ auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
23
+ ),
24
+ ),
25
+ (
26
+ "job_id",
27
+ models.CharField(
28
+ db_index=True,
29
+ help_text="Unique job identifier from ReArq",
30
+ max_length=100,
31
+ unique=True,
32
+ ),
33
+ ),
34
+ (
35
+ "task_name",
36
+ models.CharField(
37
+ db_index=True, help_text="Name of the task function", max_length=200
38
+ ),
39
+ ),
40
+ (
41
+ "queue_name",
42
+ models.CharField(
43
+ db_index=True, help_text="Queue where task was executed", max_length=100
44
+ ),
45
+ ),
46
+ (
47
+ "args",
48
+ models.JSONField(default=list, help_text="Positional arguments passed to task"),
49
+ ),
50
+ (
51
+ "kwargs",
52
+ models.JSONField(default=dict, help_text="Keyword arguments passed to task"),
53
+ ),
54
+ (
55
+ "status",
56
+ models.CharField(
57
+ choices=[
58
+ ("deferred", "Deferred"),
59
+ ("queued", "Queued"),
60
+ ("in_progress", "In Progress"),
61
+ ("success", "Success"),
62
+ ("failed", "Failed"),
63
+ ("expired", "Expired"),
64
+ ("canceled", "Canceled"),
65
+ ],
66
+ db_index=True,
67
+ default="queued",
68
+ help_text="Current task status",
69
+ max_length=20,
70
+ ),
71
+ ),
72
+ (
73
+ "duration_ms",
74
+ models.IntegerField(
75
+ blank=True, help_text="Task execution duration in milliseconds", null=True
76
+ ),
77
+ ),
78
+ (
79
+ "job_retry",
80
+ models.IntegerField(
81
+ default=0,
82
+ help_text="Maximum number of retries allowed (from task definition)",
83
+ ),
84
+ ),
85
+ (
86
+ "job_retries",
87
+ models.IntegerField(default=0, help_text="Number of retries performed so far"),
88
+ ),
89
+ (
90
+ "job_retry_after",
91
+ models.IntegerField(default=60, help_text="Seconds to wait before retry"),
92
+ ),
93
+ (
94
+ "success",
95
+ models.BooleanField(
96
+ blank=True,
97
+ help_text="Whether task completed successfully (null = not finished)",
98
+ null=True,
99
+ ),
100
+ ),
101
+ (
102
+ "result",
103
+ models.TextField(blank=True, help_text="Task result (JSON string)", null=True),
104
+ ),
105
+ (
106
+ "error_message",
107
+ models.TextField(
108
+ blank=True, help_text="Error message if task failed", null=True
109
+ ),
110
+ ),
111
+ (
112
+ "worker_id",
113
+ models.CharField(
114
+ blank=True,
115
+ help_text="ID of worker that processed the task",
116
+ max_length=100,
117
+ null=True,
118
+ ),
119
+ ),
120
+ (
121
+ "enqueue_time",
122
+ models.DateTimeField(
123
+ db_index=True,
124
+ help_text="When job was enqueued to ReArq (from Job.enqueue_time)",
125
+ ),
126
+ ),
127
+ (
128
+ "expire_time",
129
+ models.DateTimeField(
130
+ blank=True,
131
+ help_text="When job will expire (from Job.expire_time)",
132
+ null=True,
133
+ ),
134
+ ),
135
+ (
136
+ "start_time",
137
+ models.DateTimeField(
138
+ blank=True,
139
+ help_text="When task execution started (from JobResult.start_time)",
140
+ null=True,
141
+ ),
142
+ ),
143
+ (
144
+ "finish_time",
145
+ models.DateTimeField(
146
+ blank=True,
147
+ help_text="When task execution finished (from JobResult.finish_time)",
148
+ null=True,
149
+ ),
150
+ ),
151
+ (
152
+ "created_at",
153
+ models.DateTimeField(
154
+ auto_now_add=True, help_text="When TaskLog record was created in Django DB"
155
+ ),
156
+ ),
157
+ (
158
+ "updated_at",
159
+ models.DateTimeField(
160
+ auto_now=True, help_text="When TaskLog record was last updated"
161
+ ),
162
+ ),
163
+ (
164
+ "user",
165
+ models.ForeignKey(
166
+ blank=True,
167
+ help_text="User who triggered the task (if applicable)",
168
+ null=True,
169
+ on_delete=django.db.models.deletion.SET_NULL,
170
+ to=settings.AUTH_USER_MODEL,
171
+ ),
172
+ ),
173
+ ],
174
+ options={
175
+ "verbose_name": "Task Log",
176
+ "verbose_name_plural": "Task Logs",
177
+ "db_table": "django_cfg_task_log",
178
+ "ordering": ["-enqueue_time"],
179
+ "indexes": [
180
+ models.Index(
181
+ fields=["task_name", "-enqueue_time"], name="django_cfg__task_na_e84031_idx"
182
+ ),
183
+ models.Index(
184
+ fields=["status", "-enqueue_time"], name="django_cfg__status_a59726_idx"
185
+ ),
186
+ models.Index(
187
+ fields=["queue_name", "status"], name="django_cfg__queue_n_b8a67b_idx"
188
+ ),
189
+ models.Index(
190
+ fields=["success", "-enqueue_time"], name="django_cfg__success_85e48e_idx"
191
+ ),
192
+ models.Index(fields=["-created_at"], name="django_cfg__created_4eea05_idx"),
193
+ ],
194
+ },
195
+ ),
196
+ ]
@@ -0,0 +1,4 @@
1
+ """Task models."""
2
+ from .task_log import TaskLog
3
+
4
+ __all__ = ["TaskLog"]
@@ -0,0 +1,246 @@
1
+ """
2
+ Task execution log model.
3
+
4
+ Stores history of task executions for monitoring and debugging.
5
+ """
6
+ from django.conf import settings
7
+ from django.db import models
8
+ from django.utils import timezone
9
+
10
+
11
+ class TaskLog(models.Model):
12
+ """
13
+ Log of task executions.
14
+
15
+ Stores execution history from ReArq task queue.
16
+ Status values match ReArq's JobStatus enum.
17
+ """
18
+
19
+ class StatusChoices(models.TextChoices):
20
+ """Task status matching ReArq JobStatus enum."""
21
+ DEFERRED = "deferred", "Deferred"
22
+ QUEUED = "queued", "Queued"
23
+ IN_PROGRESS = "in_progress", "In Progress"
24
+ SUCCESS = "success", "Success"
25
+ FAILED = "failed", "Failed"
26
+ EXPIRED = "expired", "Expired"
27
+ CANCELED = "canceled", "Canceled"
28
+
29
+ # Task identification
30
+ job_id = models.CharField(
31
+ max_length=100,
32
+ unique=True,
33
+ db_index=True,
34
+ help_text="Unique job identifier from ReArq"
35
+ )
36
+ task_name = models.CharField(
37
+ max_length=200,
38
+ db_index=True,
39
+ help_text="Name of the task function"
40
+ )
41
+ queue_name = models.CharField(
42
+ max_length=100,
43
+ db_index=True,
44
+ help_text="Queue where task was executed"
45
+ )
46
+
47
+ # Arguments
48
+ args = models.JSONField(
49
+ default=list,
50
+ help_text="Positional arguments passed to task"
51
+ )
52
+ kwargs = models.JSONField(
53
+ default=dict,
54
+ help_text="Keyword arguments passed to task"
55
+ )
56
+
57
+ # Status tracking
58
+ status = models.CharField(
59
+ max_length=20,
60
+ choices=StatusChoices.choices,
61
+ default=StatusChoices.QUEUED,
62
+ db_index=True,
63
+ help_text="Current task status"
64
+ )
65
+
66
+ # Performance metrics
67
+ duration_ms = models.IntegerField(
68
+ null=True,
69
+ blank=True,
70
+ help_text="Task execution duration in milliseconds"
71
+ )
72
+
73
+ # Retry configuration (from ReArq Job)
74
+ job_retry = models.IntegerField(
75
+ default=0,
76
+ help_text="Maximum number of retries allowed (from task definition)"
77
+ )
78
+ job_retries = models.IntegerField(
79
+ default=0,
80
+ help_text="Number of retries performed so far"
81
+ )
82
+ job_retry_after = models.IntegerField(
83
+ default=60,
84
+ help_text="Seconds to wait before retry"
85
+ )
86
+
87
+ # Result tracking
88
+ success = models.BooleanField(
89
+ null=True,
90
+ blank=True,
91
+ help_text="Whether task completed successfully (null = not finished)"
92
+ )
93
+ result = models.TextField(
94
+ null=True,
95
+ blank=True,
96
+ help_text="Task result (JSON string)"
97
+ )
98
+ error_message = models.TextField(
99
+ null=True,
100
+ blank=True,
101
+ help_text="Error message if task failed"
102
+ )
103
+
104
+ # Worker information
105
+ worker_id = models.CharField(
106
+ max_length=100,
107
+ null=True,
108
+ blank=True,
109
+ help_text="ID of worker that processed the task"
110
+ )
111
+
112
+ # Timestamps (matching ReArq Job fields)
113
+ enqueue_time = models.DateTimeField(
114
+ db_index=True,
115
+ help_text="When job was enqueued to ReArq (from Job.enqueue_time)"
116
+ )
117
+ expire_time = models.DateTimeField(
118
+ null=True,
119
+ blank=True,
120
+ help_text="When job will expire (from Job.expire_time)"
121
+ )
122
+ start_time = models.DateTimeField(
123
+ null=True,
124
+ blank=True,
125
+ help_text="When task execution started (from JobResult.start_time)"
126
+ )
127
+ finish_time = models.DateTimeField(
128
+ null=True,
129
+ blank=True,
130
+ help_text="When task execution finished (from JobResult.finish_time)"
131
+ )
132
+
133
+ # Django-specific timestamps
134
+ created_at = models.DateTimeField(
135
+ auto_now_add=True,
136
+ help_text="When TaskLog record was created in Django DB"
137
+ )
138
+ updated_at = models.DateTimeField(
139
+ auto_now=True,
140
+ help_text="When TaskLog record was last updated"
141
+ )
142
+
143
+ # User tracking (optional)
144
+ user = models.ForeignKey(
145
+ settings.AUTH_USER_MODEL,
146
+ on_delete=models.SET_NULL,
147
+ null=True,
148
+ blank=True,
149
+ help_text="User who triggered the task (if applicable)"
150
+ )
151
+
152
+ class Meta:
153
+ # app_label is derived from apps.py: django_cfg.apps.tasks -> last segment = "tasks"
154
+ # To get "django_cfg_tasks" for consistent admin URLs, we explicitly set it:
155
+ app_label = "django_cfg_tasks"
156
+ db_table = "django_cfg_task_log"
157
+ ordering = ["-enqueue_time"]
158
+ indexes = [
159
+ models.Index(fields=["task_name", "-enqueue_time"]),
160
+ models.Index(fields=["status", "-enqueue_time"]),
161
+ models.Index(fields=["queue_name", "status"]),
162
+ models.Index(fields=["success", "-enqueue_time"]),
163
+ models.Index(fields=["-created_at"]), # For Django admin
164
+ ]
165
+ verbose_name = "Task Log"
166
+ verbose_name_plural = "Task Logs"
167
+
168
+ def __str__(self) -> str:
169
+ return f"{self.task_name} ({self.status})"
170
+
171
+ @property
172
+ def is_completed(self) -> bool:
173
+ """Check if task is in a terminal state."""
174
+ return self.status in [
175
+ self.StatusChoices.SUCCESS,
176
+ self.StatusChoices.FAILED,
177
+ self.StatusChoices.EXPIRED,
178
+ self.StatusChoices.CANCELED,
179
+ ]
180
+
181
+ @property
182
+ def is_successful(self) -> bool:
183
+ """Check if task completed successfully."""
184
+ return self.status == self.StatusChoices.SUCCESS and self.success is True
185
+
186
+ @property
187
+ def is_failed(self) -> bool:
188
+ """Check if task failed."""
189
+ return self.status in [
190
+ self.StatusChoices.FAILED,
191
+ self.StatusChoices.EXPIRED,
192
+ ] or self.success is False
193
+
194
+ def mark_started(self, worker_id: str = None, start_time=None):
195
+ """Mark task as started (from ReArq JobResult)."""
196
+ self.status = self.StatusChoices.IN_PROGRESS
197
+ self.start_time = start_time or timezone.now()
198
+ if worker_id:
199
+ self.worker_id = worker_id
200
+ self.save(update_fields=["status", "start_time", "worker_id", "updated_at"])
201
+
202
+ def mark_completed(self, result: str = None, finish_time=None):
203
+ """Mark task as completed successfully (from ReArq JobResult)."""
204
+ self.status = self.StatusChoices.SUCCESS
205
+ self.success = True
206
+ self.finish_time = finish_time or timezone.now()
207
+ if result is not None:
208
+ self.result = result
209
+
210
+ # Calculate duration
211
+ if self.start_time and self.finish_time:
212
+ delta = self.finish_time - self.start_time
213
+ self.duration_ms = int(delta.total_seconds() * 1000)
214
+
215
+ self.save(update_fields=["status", "success", "finish_time", "result", "duration_ms", "updated_at"])
216
+
217
+ def mark_failed(self, error_message: str, finish_time=None):
218
+ """Mark task as failed with error message (from ReArq JobResult)."""
219
+ self.status = self.StatusChoices.FAILED
220
+ self.success = False
221
+ self.error_message = error_message
222
+ self.finish_time = finish_time or timezone.now()
223
+
224
+ # Calculate duration
225
+ if self.start_time and self.finish_time:
226
+ delta = self.finish_time - self.start_time
227
+ self.duration_ms = int(delta.total_seconds() * 1000)
228
+
229
+ self.save(update_fields=["status", "success", "error_message", "finish_time", "duration_ms", "updated_at"])
230
+
231
+ def mark_expired(self):
232
+ """Mark task as expired (from ReArq Job.status)."""
233
+ self.status = self.StatusChoices.EXPIRED
234
+ self.success = False
235
+ self.save(update_fields=["status", "success", "updated_at"])
236
+
237
+ def mark_canceled(self):
238
+ """Mark task as canceled (from ReArq Job.status)."""
239
+ self.status = self.StatusChoices.CANCELED
240
+ self.success = False
241
+ self.save(update_fields=["status", "success", "updated_at"])
242
+
243
+ def increment_retry(self):
244
+ """Increment retry counter (from ReArq Job.job_retries)."""
245
+ self.job_retries += 1
246
+ self.save(update_fields=["job_retries", "updated_at"])
@@ -0,0 +1,28 @@
1
+ """
2
+ ReArq Tasks API Serializers.
3
+
4
+ DRF serializers for TaskLog model and ReArq operations.
5
+ """
6
+ from .task_log import (
7
+ TaskLogSerializer,
8
+ TaskLogListSerializer,
9
+ TaskLogDetailSerializer,
10
+ TaskLogStatsSerializer,
11
+ TasksByQueueSerializer,
12
+ TasksByStatusSerializer,
13
+ TaskLogOverviewSerializer,
14
+ TaskLogTimelineItemSerializer,
15
+ TaskLogTimelineSerializer,
16
+ )
17
+
18
+ __all__ = [
19
+ "TaskLogSerializer",
20
+ "TaskLogListSerializer",
21
+ "TaskLogDetailSerializer",
22
+ "TaskLogStatsSerializer",
23
+ "TasksByQueueSerializer",
24
+ "TasksByStatusSerializer",
25
+ "TaskLogOverviewSerializer",
26
+ "TaskLogTimelineItemSerializer",
27
+ "TaskLogTimelineSerializer",
28
+ ]