1
- use std:: { sync:: Arc , time:: Duration } ;
1
+ use std:: { marker :: PhantomData , num :: NonZeroUsize , sync:: Arc , time:: Duration } ;
2
2
3
3
use omniqueue:: {
4
- backends:: InMemoryBackend , Delivery , DynConsumer , DynScheduledProducer , QueueConsumer ,
5
- ScheduledQueueProducer ,
4
+ backends:: InMemoryBackend , Delivery , DynConsumer , QueueConsumer , ScheduledQueueProducer ,
6
5
} ;
7
- use serde:: { Deserialize , Serialize } ;
6
+ use serde:: { de :: DeserializeOwned , Deserialize , Serialize } ;
8
7
9
8
use crate :: {
10
9
cfg:: { Configuration , QueueBackend } ,
@@ -24,6 +23,8 @@ const RETRY_SCHEDULE: &[Duration] = &[
24
23
Duration :: from_millis ( 40 ) ,
25
24
] ;
26
25
26
+ pub type TaskQueueDelivery = SvixOmniDelivery < QueueTask > ;
27
+
27
28
fn should_retry ( err : & Error ) -> bool {
28
29
matches ! ( err. typ, ErrorType :: Queue ( _) )
29
30
}
@@ -139,19 +140,34 @@ impl QueueTask {
139
140
}
140
141
}
141
142
142
- #[ derive( Clone ) ]
143
- pub struct TaskQueueProducer {
144
- inner : Arc < DynScheduledProducer > ,
143
+ pub type TaskQueueProducer = SvixOmniProducer < QueueTask > ;
144
+ pub type TaskQueueConsumer = SvixOmniConsumer < QueueTask > ;
145
+
146
+ pub struct SvixOmniProducer < T : OmniMessage > {
147
+ inner : Arc < omniqueue:: DynScheduledProducer > ,
148
+ _phantom : PhantomData < T > ,
149
+ }
150
+
151
+ // Manual impl to avoid adding 'Clone' bound on T
152
+ impl < T : OmniMessage > Clone for SvixOmniProducer < T > {
153
+ fn clone ( & self ) -> Self {
154
+ Self {
155
+ inner : self . inner . clone ( ) ,
156
+ _phantom : PhantomData ,
157
+ }
158
+ }
145
159
}
146
160
147
- impl TaskQueueProducer {
148
- pub fn new ( inner : impl ScheduledQueueProducer + ' static ) -> Self {
161
+ impl < T : OmniMessage > SvixOmniProducer < T > {
162
+ pub ( super ) fn new ( inner : impl ScheduledQueueProducer + ' static ) -> Self {
149
163
Self {
150
164
inner : Arc :: new ( inner. into_dyn_scheduled ( ) ) ,
165
+ _phantom : PhantomData ,
151
166
}
152
167
}
153
168
154
- pub async fn send ( & self , task : QueueTask , delay : Option < Duration > ) -> Result < ( ) > {
169
+ #[ tracing:: instrument( skip_all, name = "queue_send" ) ]
170
+ pub async fn send ( & self , task : & T , delay : Option < Duration > ) -> Result < ( ) > {
155
171
let task = Arc :: new ( task) ;
156
172
run_with_retries (
157
173
|| async {
@@ -169,57 +185,99 @@ impl TaskQueueProducer {
169
185
)
170
186
. await
171
187
}
188
+
189
+ #[ tracing:: instrument( skip_all, name = "redrive_dlq" ) ]
190
+ pub async fn redrive_dlq ( & self ) -> Result < ( ) > {
191
+ self . inner . redrive_dlq ( ) . await . map_err ( Into :: into)
192
+ }
172
193
}
173
194
174
- pub struct TaskQueueConsumer {
195
+ pub struct SvixOmniConsumer < T : OmniMessage > {
175
196
inner : DynConsumer ,
197
+ _phantom : PhantomData < T > ,
198
+ }
199
+
200
+ pub trait OmniMessage : Serialize + DeserializeOwned + Send + Sync {
201
+ fn task_id ( & self ) -> Option < & str > ;
176
202
}
177
203
178
- impl TaskQueueConsumer {
179
- pub fn new ( inner : impl QueueConsumer + ' static ) -> Self {
204
+ impl OmniMessage for QueueTask {
205
+ fn task_id ( & self ) -> Option < & str > {
206
+ self . msg_id ( )
207
+ }
208
+ }
209
+
210
+ impl < T : OmniMessage > SvixOmniConsumer < T > {
211
+ pub ( super ) fn new ( inner : impl QueueConsumer + ' static ) -> Self {
180
212
Self {
181
213
inner : inner. into_dyn ( ) ,
214
+ _phantom : PhantomData ,
182
215
}
183
216
}
184
217
185
- pub async fn receive_all ( & mut self ) -> Result < Vec < TaskQueueDelivery > > {
186
- const MAX_MESSAGES : usize = 128 ;
187
- // FIXME(onelson): need to figure out what deadline/duration to use here
218
+ # [ tracing :: instrument ( skip_all , name = "queue_receive_all" ) ]
219
+ pub async fn receive_all ( & mut self , deadline : Duration ) -> Result < Vec < SvixOmniDelivery < T > > > {
220
+ pub const MAX_MESSAGES : usize = 128 ;
188
221
self . inner
189
- . receive_all ( MAX_MESSAGES , Duration :: from_secs ( 30 ) )
222
+ . receive_all ( MAX_MESSAGES , deadline )
190
223
. await
191
- . map_err ( Into :: into )
224
+ . map_err ( Error :: from )
192
225
. trace ( ) ?
193
226
. into_iter ( )
194
- . map ( TryInto :: try_into)
227
+ . map ( |acker| {
228
+ Ok ( SvixOmniDelivery {
229
+ task : Arc :: new (
230
+ acker
231
+ . payload_serde_json ( )
232
+ . map_err ( |e| {
233
+ Error :: queue ( format ! ( "Failed to decode queue task: {e:?}" ) )
234
+ } ) ?
235
+ . ok_or_else ( || Error :: queue ( "Unexpected empty delivery" ) ) ?,
236
+ ) ,
237
+
238
+ acker,
239
+ } )
240
+ } )
195
241
. collect ( )
196
242
}
243
+
244
+ pub fn max_messages ( & self ) -> Option < NonZeroUsize > {
245
+ self . inner . max_messages ( )
246
+ }
197
247
}
198
248
199
249
#[ derive( Debug ) ]
200
- pub struct TaskQueueDelivery {
201
- pub task : Arc < QueueTask > ,
202
- acker : Delivery ,
250
+ pub struct SvixOmniDelivery < T > {
251
+ pub task : Arc < T > ,
252
+ pub ( super ) acker : Delivery ,
203
253
}
204
254
205
- impl TaskQueueDelivery {
255
+ impl < T : OmniMessage > SvixOmniDelivery < T > {
256
+ pub async fn set_ack_deadline ( & mut self , duration : Duration ) -> Result < ( ) > {
257
+ Ok ( self . acker . set_ack_deadline ( duration) . await ?)
258
+ }
206
259
pub async fn ack ( self ) -> Result < ( ) > {
207
- tracing:: trace!( msg_id = self . task. msg_id( ) , "ack" ) ;
260
+ tracing:: trace!(
261
+ task_id = self . task. task_id( ) . map( tracing:: field:: display) ,
262
+ "ack"
263
+ ) ;
208
264
209
265
let mut retry = Retry :: new ( should_retry, RETRY_SCHEDULE ) ;
210
266
let mut acker = Some ( self . acker ) ;
211
267
loop {
212
268
if let Some ( result) = retry
213
269
. run ( || async {
214
- let delivery = acker
215
- . take ( )
216
- . expect ( "acker is always Some when trying to ack" ) ;
217
- delivery. ack ( ) . await . map_err ( |( e, delivery) | {
218
- // Put the delivery back in acker before retrying, to
219
- // satisfy the expect above.
220
- acker = Some ( delivery) ;
221
- e. into ( )
222
- } )
270
+ match acker. take ( ) {
271
+ Some ( delivery) => {
272
+ delivery. ack ( ) . await . map_err ( |( e, delivery) | {
273
+ // Put the delivery back in acker before retrying, to
274
+ // satisfy the expect above.
275
+ acker = Some ( delivery) ;
276
+ e. into ( )
277
+ } )
278
+ }
279
+ None => unreachable ! ( ) ,
280
+ }
223
281
} )
224
282
. await
225
283
{
@@ -229,27 +287,31 @@ impl TaskQueueDelivery {
229
287
}
230
288
231
289
pub async fn nack ( self ) -> Result < ( ) > {
232
- tracing:: trace!( msg_id = self . task. msg_id( ) , "nack" ) ;
290
+ tracing:: trace!(
291
+ task_id = self . task. task_id( ) . map( tracing:: field:: display) ,
292
+ "nack"
293
+ ) ;
233
294
234
295
let mut retry = Retry :: new ( should_retry, RETRY_SCHEDULE ) ;
235
296
let mut acker = Some ( self . acker ) ;
236
297
loop {
237
298
if let Some ( result) = retry
238
299
. run ( || async {
239
- let delivery = acker
240
- . take ( )
241
- . expect ( "acker is always Some when trying to ack" ) ;
242
-
243
- delivery
244
- . nack ( )
245
- . await
246
- . map_err ( |( e, delivery) | {
247
- // Put the delivery back in acker before retrying, to
248
- // satisfy the expect above.
249
- acker = Some ( delivery) ;
250
- e. into ( )
251
- } )
252
- . trace ( )
300
+ match acker. take ( ) {
301
+ Some ( delivery) => {
302
+ delivery
303
+ . nack ( )
304
+ . await
305
+ . map_err ( |( e, delivery) | {
306
+ // Put the delivery back in acker before retrying, to
307
+ // satisfy the expect above.
308
+ acker = Some ( delivery) ;
309
+ Error :: from ( e)
310
+ } )
311
+ . trace ( )
312
+ }
313
+ _ => unreachable ! ( ) ,
314
+ }
253
315
} )
254
316
. await
255
317
{
@@ -258,18 +320,3 @@ impl TaskQueueDelivery {
258
320
}
259
321
}
260
322
}
261
-
262
- impl TryFrom < Delivery > for TaskQueueDelivery {
263
- type Error = Error ;
264
- fn try_from ( value : Delivery ) -> Result < Self > {
265
- Ok ( TaskQueueDelivery {
266
- task : Arc :: new (
267
- value
268
- . payload_serde_json ( )
269
- . map_err ( |_| Error :: queue ( "Failed to decode queue task" ) ) ?
270
- . ok_or_else ( || Error :: queue ( "Unexpected empty delivery" ) ) ?,
271
- ) ,
272
- acker : value,
273
- } )
274
- }
275
- }
0 commit comments