@@ -9,10 +9,30 @@ def initialize(cutoff_age_in_days)
9
9
end
10
10
11
11
def perform
12
- old_pollable_jobs = PollableJobModel . where ( Sequel . lit ( "created_at < CURRENT_TIMESTAMP - INTERVAL '?' DAY" , cutoff_age_in_days ) )
13
12
logger = Steno . logger ( 'cc.background.pollable-job-cleanup' )
13
+ cutoff_condition = Sequel . lit ( "created_at < CURRENT_TIMESTAMP - INTERVAL '?' DAY" , cutoff_age_in_days )
14
+
15
+ old_pollable_jobs = PollableJobModel . where ( cutoff_condition )
14
16
logger . info ( "Cleaning up #{ old_pollable_jobs . count } Jobs rows" )
15
17
old_pollable_jobs . delete
18
+
19
+ # Job warnings have to be deleted explicitly, because
20
+ # - we don't have a foreign key constraint and thus cannot use DELETE CASCADE, and
21
+ # - we don't delete/destroy pollable job model objects one by one and thus cannot use hooks defined by the
22
+ # 'destroy' association dependency between PollableJobModel and JobWarningModel.
23
+ # Instead, we delete all expired jobs with a single SQL statement.
24
+ #
25
+ # By using the same cutoff condition based on 'created_at' for pollable jobs and job warnings, we ensure that
26
+ # only job warnings are deleted where it is guaranteed that also the associated pollable job already has been
27
+ # removed. This is due to the fact that job warnings are created after their associated pollable job, i.e.
28
+ # pollable_job.created_at <= job_warning.created_at.
29
+ #
30
+ # On the other hand, it is not guaranteed that all associated job warnings are deleted for all pollable jobs
31
+ # that have been removed during an execution of this cleanup job. But these leftovers will simply be removed
32
+ # during the next job execution.
33
+ old_job_warnings = JobWarningModel . where ( cutoff_condition )
34
+ logger . info ( "Cleaning up #{ old_job_warnings . count } Job Warnings rows" )
35
+ old_job_warnings . delete
16
36
end
17
37
18
38
def job_name_in_configuration
0 commit comments