Skip to content

Commit ba14653

Browse files
committed
use SCRIPT LOAD for redis scripts
1 parent 419b3ea commit ba14653

File tree

11 files changed

+296
-117
lines changed

11 files changed

+296
-117
lines changed

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
# Changelog
22

3+
## 12.0.0
4+
5+
Makes it so the scripts are loaded using `SCRIPT LOAD` so they aren't sent
6+
to redis each time.
7+
8+
Adds disabled-by-default feature that enables milisecond time precission.
9+
310
## 10.0.0 - 2024-05-08
411

5-
Change format from queue names for compatibiliti with the original Nodejs version of the crate.
12+
Change format from queue names for compatibiliti with the original Nodejs version of the crate.
613
Change details in here: https://github.com/DavidBM/rsmq-async-rs/pull/20
714

815
### Changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "rsmq_async"
3-
version = "11.2.0"
3+
version = "12.0.0"
44
authors = [
55
"David Bonet <webbonet@gmail.com>"
66
]

src/functions.rs

Lines changed: 101 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,12 @@ use crate::{
44
RsmqError, RsmqResult,
55
};
66
use core::convert::TryFrom;
7-
use lazy_static::lazy_static;
87
use radix_fmt::radix_36;
98
use rand::seq::IteratorRandom;
10-
use redis::{aio::ConnectionLike, pipe, Script};
9+
use redis::{aio::ConnectionLike, pipe};
1110
use std::convert::TryInto;
1211
use std::time::Duration;
1312

14-
lazy_static! {
15-
static ref CHANGE_MESSAGE_VISIVILITY: Script =
16-
Script::new(include_str!("./redis-scripts/changeMessageVisibility.lua"));
17-
static ref POP_MESSAGE: Script = Script::new(include_str!("./redis-scripts/popMessage.lua"));
18-
static ref RECEIVE_MESSAGE: Script =
19-
Script::new(include_str!("./redis-scripts/receiveMessage.lua"));
20-
}
21-
2213
const JS_COMPAT_MAX_TIME_MILLIS: u64 = 9_999_999_000;
2314

2415
#[cfg(feature = "break-js-comp")]
@@ -40,6 +31,75 @@ impl<T: ConnectionLike> std::fmt::Debug for RsmqFunctions<T> {
4031
}
4132
}
4233

34+
#[derive(Debug, Clone)]
35+
pub struct CachedScript {
36+
change_message_visibility_sha1: String,
37+
receive_message_sha1: String,
38+
}
39+
40+
impl CachedScript {
41+
async fn init<T: ConnectionLike>(conn: &mut T) -> RsmqResult<Self> {
42+
let change_message_visibility_sha1: String = redis::cmd("SCRIPT")
43+
.arg("LOAD")
44+
.arg(include_str!("./redis-scripts/changeMessageVisibility.lua"))
45+
.query_async(conn)
46+
.await?;
47+
let receive_message_sha1: String = redis::cmd("SCRIPT")
48+
.arg("LOAD")
49+
.arg(include_str!("./redis-scripts/receiveMessage.lua"))
50+
.query_async(conn)
51+
.await?;
52+
Ok(Self {
53+
change_message_visibility_sha1,
54+
receive_message_sha1,
55+
})
56+
}
57+
58+
async fn invoke_change_message_visibility<R, T: ConnectionLike>(
59+
&self,
60+
conn: &mut T,
61+
key1: String,
62+
key2: String,
63+
key3: String,
64+
) -> RsmqResult<R>
65+
where
66+
R: redis::FromRedisValue,
67+
{
68+
redis::cmd("EVALSHA")
69+
.arg(&self.change_message_visibility_sha1)
70+
.arg(3)
71+
.arg(key1)
72+
.arg(key2)
73+
.arg(key3)
74+
.query_async(conn)
75+
.await
76+
.map_err(Into::into)
77+
}
78+
79+
async fn invoke_receive_message<R, T: ConnectionLike>(
80+
&self,
81+
conn: &mut T,
82+
key1: String,
83+
key2: String,
84+
key3: String,
85+
should_delete: String,
86+
) -> RsmqResult<R>
87+
where
88+
R: redis::FromRedisValue,
89+
{
90+
redis::cmd("EVALSHA")
91+
.arg(&self.receive_message_sha1)
92+
.arg(3)
93+
.arg(key1)
94+
.arg(key2)
95+
.arg(key3)
96+
.arg(should_delete)
97+
.query_async(conn)
98+
.await
99+
.map_err(Into::into)
100+
}
101+
}
102+
43103
impl<T: ConnectionLike> RsmqFunctions<T> {
44104
/// Change the hidden time of a already sent message.
45105
pub async fn change_message_visibility(
@@ -48,23 +108,30 @@ impl<T: ConnectionLike> RsmqFunctions<T> {
48108
qname: &str,
49109
message_id: &str,
50110
hidden: Duration,
111+
cached_script: &CachedScript,
51112
) -> RsmqResult<()> {
52113
let hidden = get_redis_duration(Some(hidden), &Duration::from_secs(30));
53114

54115
let queue = self.get_queue(conn, qname, false).await?;
55116

56117
number_in_range(hidden, 0, JS_COMPAT_MAX_TIME_MILLIS)?;
57118

58-
CHANGE_MESSAGE_VISIVILITY
59-
.key(format!("{}:{}", self.ns, qname))
60-
.key(message_id)
61-
.key(queue.ts + hidden)
62-
.invoke_async::<_, bool>(conn)
119+
cached_script
120+
.invoke_change_message_visibility::<_, T>(
121+
conn,
122+
format!("{}:{}", self.ns, qname),
123+
message_id.to_string(),
124+
(queue.ts + hidden).to_string(),
125+
)
63126
.await?;
64127

65128
Ok(())
66129
}
67130

131+
pub async fn load_scripts(&self, conn: &mut T) -> RsmqResult<CachedScript> {
132+
CachedScript::init(conn).await
133+
}
134+
68135
/// Creates a new queue. Attributes can be later modified with "set_queue_attributes" method
69136
///
70137
/// hidden: Time the messages will be hidden when they are received with the "receive_message" method.
@@ -266,13 +333,18 @@ impl<T: ConnectionLike> RsmqFunctions<T> {
266333
&self,
267334
conn: &mut T,
268335
qname: &str,
336+
cached_script: &CachedScript,
269337
) -> RsmqResult<Option<RsmqMessage<E>>> {
270338
let queue = self.get_queue(conn, qname, false).await?;
271339

272-
let result: (bool, String, Vec<u8>, u64, u64) = POP_MESSAGE
273-
.key(format!("{}:{}", self.ns, qname))
274-
.key(queue.ts)
275-
.invoke_async(conn)
340+
let result: (bool, String, Vec<u8>, u64, u64) = cached_script
341+
.invoke_receive_message(
342+
conn,
343+
format!("{}:{}", self.ns, qname),
344+
queue.ts.to_string(),
345+
queue.ts.to_string(),
346+
"true".to_string(),
347+
)
276348
.await?;
277349

278350
if !result.0 {
@@ -298,17 +370,21 @@ impl<T: ConnectionLike> RsmqFunctions<T> {
298370
conn: &mut T,
299371
qname: &str,
300372
hidden: Option<Duration>,
373+
cached_script: &CachedScript,
301374
) -> RsmqResult<Option<RsmqMessage<E>>> {
302375
let queue = self.get_queue(conn, qname, false).await?;
303376

304377
let hidden = get_redis_duration(hidden, &queue.vt);
305378
number_in_range(hidden, 0, JS_COMPAT_MAX_TIME_MILLIS)?;
306379

307-
let result: (bool, String, Vec<u8>, u64, u64) = RECEIVE_MESSAGE
308-
.key(format!("{}:{}", self.ns, qname))
309-
.key(queue.ts)
310-
.key(queue.ts + hidden)
311-
.invoke_async(conn)
380+
let result: (bool, String, Vec<u8>, u64, u64) = cached_script
381+
.invoke_receive_message(
382+
conn,
383+
format!("{}:{}", self.ns, qname),
384+
queue.ts.to_string(),
385+
(queue.ts + hidden).to_string(),
386+
"false".to_string(),
387+
)
312388
.await?;
313389

314390
if !result.0 {
@@ -474,7 +550,7 @@ impl<T: ConnectionLike> RsmqFunctions<T> {
474550
.cmd("TIME")
475551
.query_async(conn)
476552
.await?;
477-
553+
478554
#[cfg(feature = "break-js-comp")]
479555
let time = (result.1).0 * 1000000 + (result.1).1;
480556
#[cfg(not(feature = "break-js-comp"))]

src/multiplexed_facade.rs

Lines changed: 27 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::functions::RsmqFunctions;
1+
use crate::functions::{CachedScript, RsmqFunctions};
22
use crate::r#trait::RsmqConnection;
33
use crate::types::{RedisBytes, RsmqMessage, RsmqOptions, RsmqQueueAttributes};
44
use crate::RsmqResult;
@@ -19,6 +19,7 @@ impl std::fmt::Debug for RedisConnection {
1919
pub struct Rsmq {
2020
connection: RedisConnection,
2121
functions: RsmqFunctions<redis::aio::MultiplexedConnection>,
22+
scripts: CachedScript,
2223
}
2324

2425
impl Rsmq {
@@ -37,27 +38,28 @@ impl Rsmq {
3738

3839
let connection = client.get_multiplexed_async_connection().await?;
3940

40-
Ok(Rsmq::new_with_connection(
41-
connection,
42-
options.realtime,
43-
Some(&options.ns),
44-
))
41+
Rsmq::new_with_connection(connection, options.realtime, Some(&options.ns)).await
4542
}
4643

4744
/// Special method for when you already have a redis-rs connection and you don't want redis_async to create a new one.
48-
pub fn new_with_connection(
49-
connection: redis::aio::MultiplexedConnection,
45+
pub async fn new_with_connection(
46+
mut connection: redis::aio::MultiplexedConnection,
5047
realtime: bool,
5148
ns: Option<&str>,
52-
) -> Rsmq {
53-
Rsmq {
49+
) -> RsmqResult<Rsmq> {
50+
let functions = RsmqFunctions {
51+
ns: ns.unwrap_or("rsmq").to_string(),
52+
realtime,
53+
conn: PhantomData,
54+
};
55+
56+
let scripts = functions.load_scripts(&mut connection).await?;
57+
58+
Ok(Rsmq {
5459
connection: RedisConnection(connection),
55-
functions: RsmqFunctions {
56-
ns: ns.unwrap_or("rsmq").to_string(),
57-
realtime,
58-
conn: PhantomData,
59-
},
60-
}
60+
functions,
61+
scripts,
62+
})
6163
}
6264
}
6365

@@ -70,7 +72,13 @@ impl RsmqConnection for Rsmq {
7072
hidden: Duration,
7173
) -> RsmqResult<()> {
7274
self.functions
73-
.change_message_visibility(&mut self.connection.0, qname, message_id, hidden)
75+
.change_message_visibility(
76+
&mut self.connection.0,
77+
qname,
78+
message_id,
79+
hidden,
80+
&self.scripts,
81+
)
7482
.await
7583
}
7684

@@ -111,7 +119,7 @@ impl RsmqConnection for Rsmq {
111119
qname: &str,
112120
) -> RsmqResult<Option<RsmqMessage<E>>> {
113121
self.functions
114-
.pop_message::<E>(&mut self.connection.0, qname)
122+
.pop_message::<E>(&mut self.connection.0, qname, &self.scripts)
115123
.await
116124
}
117125

@@ -121,7 +129,7 @@ impl RsmqConnection for Rsmq {
121129
hidden: Option<Duration>,
122130
) -> RsmqResult<Option<RsmqMessage<E>>> {
123131
self.functions
124-
.receive_message::<E>(&mut self.connection.0, qname, hidden)
132+
.receive_message::<E>(&mut self.connection.0, qname, hidden, &self.scripts)
125133
.await
126134
}
127135

0 commit comments

Comments
 (0)