1use std::marker::PhantomData;
4use std::num::NonZeroUsize;
5use std::sync::Arc;
6use std::time::Duration;
7
8use redis::AsyncTypedCommands;
9use serde::de::DeserializeOwned;
10use serde::Serialize;
11use tracing::instrument;
12
13use crate::{ErrorTypes, retry_call_timeout};
14
15use super::{RedisObjects, retry_call};
16
17pub struct Queue<T: Serialize + DeserializeOwned> {
20 raw: RawQueue,
21 _data: PhantomData<T>
22}
23
24impl<T: Serialize + DeserializeOwned> std::fmt::Debug for Queue<T> {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 f.debug_struct("Queue").field("name", &self.raw.name).finish()
27 }
28}
29
30impl<T: Serialize + DeserializeOwned> Clone for Queue<T> {
31 fn clone(&self) -> Self {
32 Self { raw: self.raw.clone(), _data: self._data }
33 }
34}
35
36impl<T: Serialize + DeserializeOwned> Queue<T> {
37 pub (crate) fn new(name: String, store: Arc<RedisObjects>, ttl: Option<Duration>) -> Self {
38 Self {
39 raw: RawQueue::new(name, store, ttl),
40 _data: PhantomData,
41 }
42 }
43
44 pub fn host(&self) -> Arc<RedisObjects> {
46 self.raw.store.clone()
47 }
48
49 pub async fn push(&self, data: &T) -> Result<(), ErrorTypes> {
51 self.raw.push(&serde_json::to_vec(data)?).await
52 }
53
54 pub async fn push_batch(&self, data: &[T]) -> Result<(), ErrorTypes> {
56 let data: Result<Vec<Vec<u8>>, _> = data.iter()
57 .map(|item | serde_json::to_vec(item))
58 .collect();
59 self.raw.push_batch(data?.iter().map(|item| item.as_slice())).await
60 }
61
62 pub async fn unpop(&self, data: &T) -> Result<(), ErrorTypes> {
64 self.raw.unpop(&serde_json::to_vec(data)?).await
65 }
66
67 pub async fn length(&self) -> Result<usize, ErrorTypes> {
69 self.raw.length().await
70 }
71
72 pub async fn peek_next(&self) -> Result<Option<T>, ErrorTypes> {
74 Ok(match self.raw.peek_next().await? {
75 Some(value) => Some(serde_json::from_str(&value)?),
76 None => None
77 })
78 }
79
80 pub async fn content(&self) -> Result<Vec<T>, ErrorTypes> {
82 let response: Vec<String> = self.raw.content().await?;
83 let mut out = vec![];
84 for data in response {
85 out.push(serde_json::from_str(&data)?);
86 }
87 Ok(out)
88 }
89
90 pub async fn delete(&self) -> Result<usize, ErrorTypes> {
92 self.raw.delete().await
93 }
94
95 pub async fn pop(&self) -> Result<Option<T>, ErrorTypes> {
97 Ok(match self.raw.pop().await? {
98 Some(value) => Some(serde_json::from_str(&value)?),
99 None => None
100 })
101 }
102
103 pub async fn pop_timeout(&self, timeout: Duration) -> Result<Option<T>, ErrorTypes> {
105 Ok(match self.raw.pop_timeout(timeout).await? {
106 Some(value) => Some(serde_json::from_str(&value)?),
107 None => None
108 })
109 }
110
111 pub async fn pop_batch(&self, limit: usize) -> Result<Vec<T>, ErrorTypes> {
113 let response: Vec<String> = self.raw.pop_batch(limit).await?;
114 let mut out = vec![];
115 for data in response {
116 out.push(serde_json::from_str(&data)?);
117 }
118 Ok(out)
119 }
120
121 pub async fn select(queues: &[&Queue<T>], timeout: Option<Duration>) -> Result<Option<(String, T)>, ErrorTypes> {
123 let queues: Vec<&RawQueue> = queues.iter().map(|queue|&queue.raw).collect();
124 let response = RawQueue::select(&queues, timeout).await?;
125 Ok(match response {
126 Some((name, data)) => Some((name, serde_json::from_str(&data)?)),
127 None => None,
128 })
129 }
130
131 pub fn raw(&self) -> RawQueue {
133 self.raw.clone()
134 }
135}
136
137#[derive(Clone)]
140pub struct RawQueue {
141 name: String,
142 store: Arc<RedisObjects>,
143 ttl: Option<Duration>,
144 last_expire_time: Arc<std::sync::Mutex<Option<std::time::Instant>>>,
145}
146
147impl std::fmt::Debug for RawQueue {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 f.debug_struct("RawQueue").field("name", &self.name).field("store", &self.store).finish()
150 }
151}
152
153impl RawQueue {
154 pub (crate) fn new(name: String, store: Arc<RedisObjects>, ttl: Option<Duration>) -> Self {
155 Self {
156 name,
157 store,
158 ttl,
159 last_expire_time: Arc::new(std::sync::Mutex::new(None)),
160 }
161 }
162
163 async fn conditional_expire(&self) -> Result<(), ErrorTypes> {
165 if let Some(ttl) = self.ttl {
167 {
168 let mut last_expire_time = self.last_expire_time.lock().unwrap();
170
171 if let Some(time) = *last_expire_time {
174 if time.elapsed() < (ttl / 4) {
175 return Ok(())
176 }
177 };
178
179 *last_expire_time = Some(std::time::Instant::now());
182 }
183 let _: bool = retry_call!(self.store.pool, expire, &self.name, ttl.as_secs() as i64)?;
184 }
185 Ok(())
186 }
187
188 #[instrument(skip(data))]
190 pub async fn push(&self, data: &[u8]) -> Result<(), ErrorTypes> {
191 let _: usize = retry_call!(self.store.pool, rpush, &self.name, data)?;
192 self.conditional_expire().await
193 }
194
195 #[instrument(skip(data))]
197 pub async fn push_batch(&self, data: impl Iterator<Item=&[u8]>) -> Result<(), ErrorTypes> {
198 let mut pipe = redis::pipe();
199 for item in data {
200 pipe.rpush(&self.name, item);
201 }
202 let _: () = retry_call!(method, self.store.pool, pipe, query_async)?;
203 self.conditional_expire().await
204 }
205
206 #[instrument(skip(data))]
208 pub async fn unpop(&self, data: &[u8]) -> Result<(), ErrorTypes> {
209 let _: usize = retry_call!(self.store.pool, lpush, &self.name, data)?;
210 self.conditional_expire().await
211 }
212
213 #[instrument]
215 pub async fn length(&self) -> Result<usize, ErrorTypes> {
216 retry_call!(self.store.pool, llen, &self.name)
217 }
218
219 #[instrument]
221 pub async fn peek_next(&self) -> Result<Option<String>, ErrorTypes> {
222 let response: Vec<String> = retry_call!(self.store.pool, lrange, &self.name, 0, 0)?;
223 Ok(response.into_iter().nth(0))
224 }
225
226 #[instrument]
228 pub async fn content(&self) -> Result<Vec<String>, ErrorTypes> {
229 Ok(retry_call!(self.store.pool, lrange, &self.name, 0, -1)?)
230 }
231
232 #[instrument]
234 pub async fn delete(&self) -> Result<usize, ErrorTypes> {
235 retry_call!(self.store.pool, del, &self.name)
236 }
237
238 #[instrument]
240 pub async fn pop(&self) -> Result<Option<String>, ErrorTypes> {
241 Ok(retry_call!(self.store.pool, lpop, &self.name, None)?)
242 }
243
244 #[instrument]
246 pub async fn pop_timeout(&self, timeout: Duration) -> Result<Option<String>, ErrorTypes> {
247 let to = timeout.as_secs_f64();
248 let response: Option<[String; 2]> = retry_call_timeout!(self.store.pool, blpop, to, &self.name)?;
249 Ok(response.map(|[_, data]| data))
250 }
251
252 #[instrument]
254 pub async fn pop_batch(&self, limit: usize) -> Result<Vec<String>, ErrorTypes> {
255 let limit = match NonZeroUsize::new(limit) {
256 Some(value) => value,
257 None => return Ok(Default::default()),
258 };
259 Ok(retry_call!(self.store.pool, lpop, &self.name, Some(limit))?)
260 }
261
262 #[instrument]
264 pub async fn select(queues: &[&RawQueue], timeout: Option<Duration>) -> Result<Option<(String, String)>, ErrorTypes> {
265 let timeout = timeout.unwrap_or_default().as_secs_f64();
266 if queues.is_empty() {
267 return Ok(None)
268 }
269
270 let store = &queues[0].store;
271 let mut command = redis::cmd("BLPOP");
272 for queue in queues {
273 command.arg(queue.name.as_str());
274 }
275 command.arg(timeout);
276
277 let result: Option<[String; 2]> = retry_call_timeout!(method, store.pool, command, query_async, timeout)?;
278
279 Ok(result.map(|[a, b]| (a, b)))
280 }
281}
282
283const PQ_DEQUEUE_RANGE_SCRIPT: &str = r#"
292local unpack = table.unpack or unpack
293local min_score = tonumber(ARGV[1]);
294if min_score == nil then min_score = -math.huge end
295local max_score = tonumber(ARGV[2]);
296if max_score == nil then max_score = math.huge end
297local rem_offset = tonumber(ARGV[3]);
298local rem_limit = tonumber(ARGV[4]);
299
300local entries = redis.call("zrangebyscore", KEYS[1], min_score, max_score, "limit", rem_offset, rem_limit);
301if #entries > 0 then redis.call("zrem", KEYS[1], unpack(entries)) end
302return entries
303"#;
304
305const SORTING_KEY_LEN: usize = 21;
307
308pub struct PriorityQueue<T> {
310 name: String,
311 store: Arc<RedisObjects>,
312 dequeue_range: redis::Script,
313 _data: PhantomData<T>,
314}
315
316impl<T> std::fmt::Debug for PriorityQueue<T> {
317 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
318 f.debug_struct("PriorityQueue").field("name", &self.name).field("store", &self.store).finish()
319 }
320}
321
322impl<T: Serialize + DeserializeOwned> PriorityQueue<T> {
323 pub (crate) fn new(name: String, store: Arc<RedisObjects>) -> Self {
324 Self {
325 name,
326 store,
327 dequeue_range: redis::Script::new(PQ_DEQUEUE_RANGE_SCRIPT),
328 _data: PhantomData,
329 }
330 }
331
332 pub fn name(&self) -> &str {
334 self.name.as_str()
335 }
336
337 fn encode(item: &T) -> Result<String, ErrorTypes> {
338 let vip = false;
339 let vip = if vip { 0 } else { 9 };
340
341 let now = chrono::Utc::now().timestamp_micros();
342 let data = serde_json::to_string(&item)?;
343
344 Ok(format!("{vip}{now:020}{data}"))
346 }
347 fn decode(data: &str) -> Result<T, ErrorTypes> {
348 Ok(serde_json::from_str(&data[SORTING_KEY_LEN..])?)
349 }
350
351 #[instrument]
353 pub async fn count(&self, lowest: f64, highest: f64) -> Result<usize, ErrorTypes> {
354 Ok(retry_call!(self.store.pool, zcount, &self.name, -highest, -lowest)?)
355 }
356
357 #[instrument]
359 pub async fn delete(&self) -> Result<usize, ErrorTypes> {
360 retry_call!(self.store.pool, del, &self.name)
361 }
362
363 #[instrument]
365 pub async fn length(&self) -> Result<usize, ErrorTypes> {
366 retry_call!(self.store.pool, zcard, &self.name)
367 }
368
369 #[instrument]
371 pub async fn pop(&self, num: isize) -> Result<Vec<T>, ErrorTypes> {
372 if num <= 0 {
373 return Ok(Default::default())
374 };
375 let items: Vec<String> = retry_call!(self.store.pool, zpopmin, &self.name, num)?;
376 let mut items = items.into_iter();
377 let mut out = vec![];
378 while let Some(data) = items.next() {
379 let _priority = items.next();
380 out.push(Self::decode(&data)?);
381 }
382 Ok(out)
383 }
384
385 #[instrument]
387 pub async fn blocking_pop(&self, timeout: Duration, low_priority: bool) -> Result<Option<T>, ErrorTypes> {
388 let result: Option<(String, String, f64)> = if low_priority {
389 retry_call_timeout!(self.store.pool, bzpopmax, timeout.as_secs_f64(), &self.name)?
390 } else {
391 retry_call_timeout!(self.store.pool, bzpopmin, timeout.as_secs_f64(), &self.name)?
392 };
393 match result {
394 Some(result) => Ok(Some(Self::decode(&result.1)?)),
395 None => Ok(None)
396 }
397 }
398
399 #[instrument]
407 pub async fn dequeue_range(&self, lower_limit: Option<i64>, upper_limit: Option<i64>, skip: Option<u32>, num: Option<u32>) -> Result<Vec<T>, ErrorTypes> {
408 let skip = skip.unwrap_or(0);
409 let num = num.unwrap_or(1);
410 let mut call = self.dequeue_range.key(&self.name);
411
412 let inner_lower = match upper_limit {
413 Some(value) => -value,
414 None => i64::MIN,
415 };
416 let inner_upper = match lower_limit {
417 Some(value) => -value,
418 None => i64::MAX,
419 };
420
421 let call = call.arg(inner_lower).arg(inner_upper).arg(skip).arg(num);
422 let results: Vec<String> = retry_call!(method, self.store.pool, call, invoke_async)?;
423 results.iter()
424 .map(|row| Self::decode(row))
425 .collect()
426 }
429
430 #[instrument(skip(data))]
432 pub async fn push(&self, priority: f64, data: &T) -> Result<String, ErrorTypes> {
433 let value = Self::encode(data)?;
434 if retry_call!(self.store.pool, zadd, &self.name, &value, -priority)? > 0 {
435 Ok(value)
436 } else {
437 Err(ErrorTypes::UnknownRedisError)
438 }
439 }
440
441 #[instrument(skip(raw_value))]
443 pub async fn rank(&self, raw_value: &str) -> Result<Option<usize>, ErrorTypes> {
444 retry_call!(self.store.pool, zrank, &self.name, raw_value)
445 }
446
447 #[instrument(skip(raw_value))]
449 pub async fn remove(&self, raw_value: &str) -> Result<bool, ErrorTypes> {
450 let count: usize = retry_call!(self.store.pool, zrem, &self.name, raw_value)?;
451 Ok(count >= 1)
452 }
453
454 #[instrument]
456 pub async fn unpush(&self, num: isize) -> Result<Vec<T>, ErrorTypes> {
457 if num <= 0 {
458 return Ok(Default::default())
459 };
460 let items: Vec<String> = retry_call!(self.store.pool, zpopmax, &self.name, num)?;
461 let mut items = items.into_iter();
462 let mut out = vec![];
463 while let Some(data) = items.next() {
464 let _priority = items.next();
465 out.push(Self::decode(&data)?);
466 }
467 Ok(out)
468 }
469
470 #[instrument]
472 pub async fn select(queues: &[&PriorityQueue<T>], timeout: Option<Duration>) -> Result<Option<(String, T)>, ErrorTypes> {
473 if queues.is_empty() {
474 return Ok(Default::default())
475 }
476
477 let timeout = timeout.unwrap_or_default().as_secs_f64();
478 let mut names = vec![];
480 for queue in queues {
481 names.push(queue.name.as_str());
482 }
483 let response: Option<(String, String, f64)> = retry_call_timeout!(queues[0].store.pool, bzpopmin, timeout, &names)?;
484
485 Ok(match response {
486 Some((queue, value, _)) => Some((queue, Self::decode(&value)?)),
487 None => None,
488 })
489 }
490
491 #[instrument]
493 pub async fn all_length(queues: &[&PriorityQueue<T>]) -> Result<Vec<u64>, ErrorTypes> {
494 if queues.is_empty() {
495 return Ok(Default::default())
496 }
497
498 let mut pipe = redis::pipe();
499 for que in queues {
500 pipe.zcard(&que.name);
501 }
502
503 Ok(retry_call!(method, queues[0].store.pool, pipe, query_async)?)
504 }
505
506
507}
508
509pub struct MultiQueue<Message: Serialize + DeserializeOwned> {
511 store: Arc<RedisObjects>,
512 prefix: String,
513 _data: PhantomData<Message>,
514}
515
516impl<Message: Serialize + DeserializeOwned> std::fmt::Debug for MultiQueue<Message> {
517 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
518 f.debug_struct("MultiQueue").field("store", &self.store).field("prefix", &self.prefix).finish()
519 }
520}
521
522impl<Message: Serialize + DeserializeOwned> MultiQueue<Message> {
523 pub(crate) fn new(prefix: String, store: Arc<RedisObjects>) -> Self {
524 Self {store, prefix, _data: Default::default()}
525 }
526
527 #[instrument]
529 pub async fn delete(&self, name: &str) -> Result<usize, ErrorTypes> {
530 retry_call!(self.store.pool, del, self.prefix.clone() + name)
531 }
532
533 #[instrument]
535 pub async fn length(&self, name: &str) -> Result<usize, ErrorTypes> {
536 retry_call!(self.store.pool, llen, self.prefix.clone() + name)
537 }
538
539 #[instrument]
541 pub async fn pop_nonblocking(&self, name: &str) -> Result<Option<Message>, ErrorTypes> {
542 let result: Option<String> = retry_call!(self.store.pool, lpop, self.prefix.clone() + name, None)?;
543 match result {
544 Some(result) => Ok(serde_json::from_str(&result)?),
545 None => Ok(None)
546 }
547 }
548
549 #[instrument]
551 pub async fn pop(&self, name: &str, timeout: Duration) -> Result<Option<Message>, ErrorTypes> {
552 let to = timeout.as_secs_f64();
553 let result: Option<[String; 2]> = retry_call_timeout!(self.store.pool, blpop, to, self.prefix.clone() + name)?;
554 match result {
555 Some([_, result]) => Ok(serde_json::from_str(&result)?),
556 None => Ok(None),
557 }
558 }
559
560 #[instrument(skip(message))]
562 pub async fn push(&self, name: &str, message: &Message) -> Result<(), ErrorTypes> {
563 let _: usize = retry_call!(self.store.pool, rpush, self.prefix.clone() + name, serde_json::to_string(message)?)?;
564 Ok(())
565 }
566}