@@ -61,24 +61,26 @@ class Meta:
61
61
def __str__ (self ):
62
62
return f"{ self .job_class } [{ self .uuid } ]"
63
63
64
- def convert_to_job (self ):
64
+ def convert_to_job (self , * , worker_uuid = None ):
65
65
"""
66
66
JobRequests are the pending jobs that are waiting to be executed.
67
67
We immediately convert them to JobResults when they are picked up.
68
68
"""
69
- result = Job .objects .create (
70
- job_request_uuid = self .uuid ,
71
- job_class = self .job_class ,
72
- parameters = self .parameters ,
73
- priority = self .priority ,
74
- source = self .source ,
75
- retries = self .retries ,
76
- retry_attempt = self .retry_attempt ,
77
- unique_key = self .unique_key ,
78
- )
69
+ with transaction .atomic ():
70
+ result = Job .objects .create (
71
+ job_request_uuid = self .uuid ,
72
+ job_class = self .job_class ,
73
+ parameters = self .parameters ,
74
+ priority = self .priority ,
75
+ source = self .source ,
76
+ retries = self .retries ,
77
+ retry_attempt = self .retry_attempt ,
78
+ unique_key = self .unique_key ,
79
+ worker_uuid = worker_uuid ,
80
+ )
79
81
80
- # Delete the pending JobRequest now
81
- self .delete ()
82
+ # Delete the pending JobRequest now
83
+ self .delete ()
82
84
83
85
return result
84
86
@@ -110,6 +112,9 @@ class Job(models.Model):
110
112
created_at = models .DateTimeField (auto_now_add = True , db_index = True )
111
113
started_at = models .DateTimeField (blank = True , null = True , db_index = True )
112
114
115
+ # To associate with a worker
116
+ worker_uuid = models .UUIDField (blank = True , null = True , db_index = True )
117
+
113
118
# From the JobRequest
114
119
job_request_uuid = models .UUIDField (db_index = True )
115
120
job_class = models .CharField (max_length = 255 , db_index = True )
@@ -152,26 +157,29 @@ def convert_to_result(self, *, status, error=""):
152
157
"""
153
158
Convert this Job to a JobResult.
154
159
"""
155
- result = JobResult .objects .create (
156
- ended_at = timezone .now (),
157
- error = error ,
158
- status = status ,
159
- # From the Job
160
- job_uuid = self .uuid ,
161
- started_at = self .started_at ,
162
- # From the JobRequest
163
- job_request_uuid = self .job_request_uuid ,
164
- job_class = self .job_class ,
165
- parameters = self .parameters ,
166
- priority = self .priority ,
167
- source = self .source ,
168
- retries = self .retries ,
169
- retry_attempt = self .retry_attempt ,
170
- unique_key = self .unique_key ,
171
- )
160
+ with transaction .atomic ():
161
+ result = JobResult .objects .create (
162
+ ended_at = timezone .now (),
163
+ error = error ,
164
+ status = status ,
165
+ # From the worker
166
+ worker_uuid = self .worker_uuid ,
167
+ # From the Job
168
+ job_uuid = self .uuid ,
169
+ started_at = self .started_at ,
170
+ # From the JobRequest
171
+ job_request_uuid = self .job_request_uuid ,
172
+ job_class = self .job_class ,
173
+ parameters = self .parameters ,
174
+ priority = self .priority ,
175
+ source = self .source ,
176
+ retries = self .retries ,
177
+ retry_attempt = self .retry_attempt ,
178
+ unique_key = self .unique_key ,
179
+ )
172
180
173
- # Delete the Job now
174
- self .delete ()
181
+ # Delete the Job now
182
+ self .delete ()
175
183
176
184
return result
177
185
@@ -180,6 +188,9 @@ class JobResultQuerySet(models.QuerySet):
180
188
def successful (self ):
181
189
return self .filter (status = JobResultStatuses .SUCCESSFUL )
182
190
191
+ def cancelled (self ):
192
+ return self .filter (status = JobResultStatuses .CANCELLED )
193
+
183
194
def lost (self ):
184
195
return self .filter (status = JobResultStatuses .LOST )
185
196
@@ -192,19 +203,31 @@ def retried(self):
192
203
| models .Q (retry_attempt__gt = 0 )
193
204
)
194
205
195
- def retry_failed_jobs (self ):
196
- for result in self .filter (
197
- status__in = [JobResultStatuses .ERRORED , JobResultStatuses .LOST ],
206
+ def failed (self ):
207
+ return self .filter (
208
+ status__in = [
209
+ JobResultStatuses .ERRORED ,
210
+ JobResultStatuses .LOST ,
211
+ JobResultStatuses .CANCELLED ,
212
+ ]
213
+ )
214
+
215
+ def retryable (self ):
216
+ return self .failed ().filter (
198
217
retry_job_request_uuid__isnull = True ,
199
218
retries__gt = 0 ,
200
219
retry_attempt__lt = models .F ("retries" ),
201
- ):
220
+ )
221
+
222
+ def retry_failed_jobs (self ):
223
+ for result in self .retryable ():
202
224
result .retry_job ()
203
225
204
226
205
227
class JobResultStatuses (models .TextChoices ):
206
228
SUCCESSFUL = "SUCCESSFUL" , "Successful"
207
229
ERRORED = "ERRORED" , "Errored" # Threw an error
230
+ CANCELLED = "CANCELLED" , "Cancelled" # Cancelled (probably by deploy)
208
231
LOST = (
209
232
"LOST" ,
210
233
"Lost" ,
@@ -219,6 +242,9 @@ class JobResult(models.Model):
219
242
uuid = models .UUIDField (default = uuid .uuid4 , editable = False , unique = True )
220
243
created_at = models .DateTimeField (auto_now_add = True , db_index = True )
221
244
245
+ # To associate with a worker
246
+ worker_uuid = models .UUIDField (blank = True , null = True , db_index = True )
247
+
222
248
# From the Job
223
249
job_uuid = models .UUIDField (db_index = True )
224
250
started_at = models .DateTimeField (blank = True , null = True , db_index = True )
0 commit comments