@@ -46,10 +46,18 @@ public final class PostgresJobQueue: JobQueueDriver, CancellableJobQueue, Resuma
46
46
47
47
public typealias JobID = UUID
48
48
/// what to do with failed/processing jobs from last time queue was handled
49
- public enum JobCleanup : Sendable {
50
- case doNothing
51
- case rerun
52
- case remove
49
+ public struct JobCleanup : Sendable , Codable {
50
+ enum RawValue : Codable {
51
+ case doNothing
52
+ case rerun
53
+ case remove( maxAge: Duration ? )
54
+ }
55
+ let rawValue : RawValue
56
+
57
+ public static var doNothing : Self { . init( rawValue: . doNothing) }
58
+ public static var rerun : Self { . init( rawValue: . rerun) }
59
+ public static var remove : Self { . init( rawValue: . remove( maxAge: nil ) ) }
60
+ public static func remove( maxAge: Duration ) -> Self { . init( rawValue: . remove( maxAge: maxAge) ) }
53
61
}
54
62
55
63
/// Job priority from lowest to highest
@@ -170,6 +178,18 @@ public final class PostgresJobQueue: JobQueueDriver, CancellableJobQueue, Resuma
170
178
self . isStopped = . init( false )
171
179
self . migrations = migrations
172
180
await migrations. add ( CreateSwiftJobsMigrations ( ) , skipDuplicates: true )
181
+ self . registerJob (
182
+ JobDefinition ( parameters: JobCleanupParameters . self, retryStrategy: . dontRetry) { parameters, context in
183
+ parameters. jobQueue. cleanup (
184
+ failedJobs: parameters. failedJobs,
185
+ processingJobs: . doNothing,
186
+ pendingJobs: . doNothing,
187
+ completedJobs: parameters. completedJobs,
188
+ cancelledJobs: parameters. cancelledJobs,
189
+ logger: logger
190
+ )
191
+ }
192
+ )
173
193
}
174
194
175
195
public func onInit( ) async throws {
@@ -232,53 +252,6 @@ public final class PostgresJobQueue: JobQueueDriver, CancellableJobQueue, Resuma
232
252
}
233
253
}
234
254
235
- /// Cleanup job queues
236
- ///
237
- /// This function is used to re-run or delete jobs in a certain state. Failed jobs can be
238
- /// pushed back into the pending queue to be re-run or removed. When called at startup in
239
- /// theory no job should be set to processing, or set to pending but not in the queue. but if
240
- /// your job server crashes these states are possible, so we also provide options to re-queue
241
- /// these jobs so they are run again.
242
- ///
243
- /// The job queue needs to be running when you call cleanup. You can call `cleanup` with
244
- /// `failedJobs`` set to whatever you like at any point to re-queue failed jobs. Moving processing
245
- /// or pending jobs should only be done if you are certain there is nothing else processing
246
- /// the job queue.
247
- ///
248
- /// - Parameters:
249
- /// - failedJobs: What to do with jobs tagged as failed
250
- /// - processingJobs: What to do with jobs tagged as processing
251
- /// - pendingJobs: What to do with jobs tagged as pending
252
- /// - Throws:
253
- public func cleanup(
254
- failedJobs: JobCleanup = . doNothing,
255
- processingJobs: JobCleanup = . doNothing,
256
- pendingJobs: JobCleanup = . doNothing
257
- ) async throws {
258
- do {
259
- /// wait for migrations to complete before running job queue cleanup
260
- try await self . migrations. waitUntilCompleted ( )
261
- _ = try await self . client. withConnection { connection in
262
- self . logger. info ( " Update Jobs " )
263
- try await self . updateJobsOnInit ( withStatus: . pending, onInit: pendingJobs, connection: connection)
264
- try await self . updateJobsOnInit (
265
- withStatus: . processing,
266
- onInit: processingJobs,
267
- connection: connection
268
- )
269
- try await self . updateJobsOnInit ( withStatus: . failed, onInit: failedJobs, connection: connection)
270
- }
271
- } catch let error as PSQLError {
272
- logger. error (
273
- " JobQueue initialization failed " ,
274
- metadata: [
275
- " Error " : " \( String ( reflecting: error) ) "
276
- ]
277
- )
278
- throw error
279
- }
280
- }
281
-
282
255
/// Register job
283
256
/// - Parameters:
284
257
/// - job: Job Definition
@@ -469,51 +442,6 @@ public final class PostgresJobQueue: JobQueueDriver, CancellableJobQueue, Resuma
469
442
)
470
443
}
471
444
472
- /// This menthod shall be called with the JobPruner after registration as follow
473
- /// someJobQueue.registerJobparameters: JobPruner.self) { _, _ in
474
- /// try await someJobQueue.processDataRetentionPolicy()
475
- /// }
476
- /// let jobScheddule = JobSchedule([ .init(job: JobPruner(), schedule: .everyHour()) ])
477
- public func processDataRetentionPolicy( ) async throws {
478
- try await self . client. withTransaction ( logger: logger) { tx in
479
- let now = Date . now. timeIntervalSince1970
480
- let retentionPolicy : RetentionPolicy = configuration. retentionPolicy
481
-
482
- if case let . retain( timeAmout) = retentionPolicy. cancelled. rawValue {
483
- try await tx. query (
484
- """
485
- DELETE FROM swift_jobs.jobs
486
- WHERE status = \( Status . cancelled)
487
- AND extract(epoch FROM last_modified)::int + \( timeAmout) < \( now)
488
- """ ,
489
- logger: self . logger
490
- )
491
- }
492
-
493
- if case let . retain( timeAmout) = retentionPolicy. completed. rawValue {
494
- try await tx. query (
495
- """
496
- DELETE FROM swift_jobs.jobs
497
- WHERE status = \( Status . completed)
498
- AND extract(epoch FROM last_modified)::int + \( timeAmout) < \( now)
499
- """ ,
500
- logger: self . logger
501
- )
502
- }
503
-
504
- if case let . retain( timeAmout) = retentionPolicy. failed. rawValue {
505
- try await tx. query (
506
- """
507
- DELETE FROM swift_jobs.jobs
508
- WHERE status = \( Status . failed)
509
- AND extract(epoch FROM last_modified)::int + \( timeAmout) < \( now)
510
- """ ,
511
- logger: self . logger
512
- )
513
- }
514
- }
515
- }
516
-
517
445
func updateJob( jobID: JobID , buffer: ByteBuffer , connection: PostgresConnection ) async throws {
518
446
try await connection. query (
519
447
"""
@@ -600,29 +528,6 @@ public final class PostgresJobQueue: JobQueueDriver, CancellableJobQueue, Resuma
600
528
return jobs
601
529
}
602
530
603
- func updateJobsOnInit( withStatus status: Status , onInit: JobCleanup , connection: PostgresConnection ) async throws {
604
- switch onInit {
605
- case . remove:
606
- try await connection. query (
607
- """
608
- DELETE FROM swift_jobs.jobs
609
- WHERE status = \( status) AND queue_name = \( configuration. queueName)
610
- """ ,
611
- logger: self . logger
612
- )
613
-
614
- case . rerun:
615
- let jobs = try await getJobs ( withStatus: status)
616
- self . logger. info ( " Moving \( jobs. count) jobs with status: \( status) to job queue " )
617
- for jobID in jobs {
618
- try await self . addToQueue ( jobID: jobID, queueName: configuration. queueName, options: . init( ) , connection: connection)
619
- }
620
-
621
- case . doNothing:
622
- break
623
- }
624
- }
625
-
626
531
let jobRegistry : JobRegistry
627
532
}
628
533
0 commit comments