@@ -8,15 +8,17 @@ public struct FluentQueue: AsyncQueue, Sendable {
8
8
// See `Queue.context`.
9
9
public let context : QueueContext
10
10
11
- let sqlDb : any SQLDatabase
12
-
11
+ let sqlDB : any SQLDatabase
12
+ let preservesCompletedJobs : Bool
13
+ let jobsTable : SQLQualifiedTable
14
+
13
15
let _sqlLockingClause : NIOLockedValueBox < ( any SQLExpression ) ? > = . init( nil ) // needs a lock for the queue to be `Sendable`
14
16
15
17
// See `Queue.get(_:)`.
16
18
public func get( _ id: JobIdentifier ) async throws -> JobData {
17
- guard let job = try await self . sqlDb . select ( )
19
+ guard let job = try await self . sqlDB . select ( )
18
20
. columns ( " payload " , " max_retry_count " , " queue_name " , " state " , " job_name " , " delay_until " , " queued_at " , " attempts " , " updated_at " )
19
- . from ( JobModel . schema )
21
+ . from ( self . jobsTable )
20
22
. where ( " id " , . equal, id)
21
23
. first ( decoding: JobModel . self, keyDecodingStrategy: . convertFromSnakeCase)
22
24
else {
@@ -28,7 +30,7 @@ public struct FluentQueue: AsyncQueue, Sendable {
28
30
29
31
// See `Queue.set(_:to:)`.
30
32
public func set( _ id: JobIdentifier , to jobStorage: JobData ) async throws {
31
- try await self . sqlDb . insert ( into: JobModel . schema )
33
+ try await self . sqlDB . insert ( into: self . jobsTable )
32
34
. columns ( " id " , " queue_name " , " job_name " , " queued_at " , " delay_until " , " state " , " max_retry_count " , " attempts " , " payload " , " updated_at " )
33
35
. values (
34
36
. bind( id) ,
@@ -48,14 +50,21 @@ public struct FluentQueue: AsyncQueue, Sendable {
48
50
49
51
// See `Queue.clear(_:)`.
50
52
public func clear( _ id: JobIdentifier ) async throws {
51
- try await self . sqlDb. delete ( from: JobModel . schema)
52
- . where ( " id " , . equal, id)
53
- . run ( )
53
+ if self . preservesCompletedJobs {
54
+ try await self . sqlDB. update ( self . jobsTable)
55
+ . set ( " state " , to: . literal( StoredJobState . completed) )
56
+ . where ( " id " , . equal, id)
57
+ . run ( )
58
+ } else {
59
+ try await self . sqlDB. delete ( from: self . jobsTable)
60
+ . where ( " id " , . equal, id)
61
+ . run ( )
62
+ }
54
63
}
55
64
56
65
// See `Queue.push(_:)`.
57
66
public func push( _ id: JobIdentifier ) async throws {
58
- try await self . sqlDb . update ( JobModel . schema )
67
+ try await self . sqlDB . update ( self . jobsTable )
59
68
. set ( " state " , to: . literal( StoredJobState . pending) )
60
69
. set ( " updated_at " , to: . now( ) )
61
70
. where ( " id " , . equal, id)
@@ -69,9 +78,9 @@ public struct FluentQueue: AsyncQueue, Sendable {
69
78
// is purely synchronous, and `SQLDatabase.version` is not implemented in MySQLKit at the time
70
79
// of this writing.
71
80
if self . _sqlLockingClause. withLockedValue ( { $0 } ) == nil {
72
- switch self . sqlDb . dialect. name {
81
+ switch self . sqlDB . dialect. name {
73
82
case " mysql " :
74
- let version = try await self . sqlDb . select ( )
83
+ let version = try await self . sqlDB . select ( )
75
84
. column ( . function( " version " ) , as: " version " )
76
85
. first ( decodingColumn: " version " , as: String . self) ! // always returns one row
77
86
// This is a really lazy check and it knows it; we know MySQLNIO doesn't support versions older than 5.x.
@@ -87,7 +96,7 @@ public struct FluentQueue: AsyncQueue, Sendable {
87
96
88
97
let select = SQLSubquery . select { $0
89
98
. column ( " id " )
90
- . from ( JobModel . schema )
99
+ . from ( self . jobsTable )
91
100
. where ( " state " , . equal, . literal( StoredJobState . pending) )
92
101
. where ( " queue_name " , . equal, self . queueName)
93
102
. where ( . dateValue( . function( " coalesce " , . column( " delay_until " ) , SQLNow ( ) ) ) , . lessThanOrEqual, . now( ) )
@@ -97,24 +106,24 @@ public struct FluentQueue: AsyncQueue, Sendable {
97
106
. lockingClause ( self . _sqlLockingClause. withLockedValue { $0! } ) // we've always set it by the time we get here
98
107
}
99
108
100
- if self . sqlDb . dialect. supportsReturning {
101
- return try await self . sqlDb . update ( JobModel . schema )
109
+ if self . sqlDB . dialect. supportsReturning {
110
+ return try await self . sqlDB . update ( self . jobsTable )
102
111
. set ( " state " , to: . literal( StoredJobState . processing) )
103
112
. set ( " updated_at " , to: . now( ) )
104
113
. where ( " id " , . equal, select)
105
114
. returning ( " id " )
106
115
. first ( decodingColumn: " id " , as: String . self)
107
116
. map ( JobIdentifier . init ( string: ) )
108
117
} else {
109
- return try await self . sqlDb . transaction { transaction in
118
+ return try await self . sqlDB . transaction { transaction in
110
119
guard let id = try await transaction. raw ( " \( select) " ) // using raw() to make sure we run on the transaction connection
111
120
. first ( decodingColumn: " id " , as: String . self)
112
121
else {
113
122
return nil
114
123
}
115
124
116
125
try await transaction
117
- . update ( JobModel . schema )
126
+ . update ( self . jobsTable )
118
127
. set ( " state " , to: . literal( StoredJobState . processing) )
119
128
. set ( " updated_at " , to: . now( ) )
120
129
. where ( " id " , . equal, id)
0 commit comments