Skip to content

Commit 0b2bde0

Browse files
committed
Support custom message field in Redis
1 parent 36530cf commit 0b2bde0

File tree

8 files changed

+49
-13
lines changed

8 files changed

+49
-13
lines changed

sea-streamer-file/src/file.rs

+1
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,7 @@ impl AsyncFile {
224224
.seek(match to {
225225
SeqPos::Beginning => SeekFrom::Start(0),
226226
SeqPos::End => SeekFrom::End(0),
227+
#[allow(clippy::useless_conversion)]
227228
SeqPos::At(to) => SeekFrom::Start(to.try_into().expect("SeqNo out of range")),
228229
})
229230
.await

sea-streamer-file/src/messages.rs

+2
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ impl MessageSource {
112112
SeqPos::Beginning | SeqPos::At(0) => SeqPos::At(Header::size() as SeqNo),
113113
SeqPos::End => SeqPos::End,
114114
SeqPos::At(nth) => {
115+
#[allow(clippy::unnecessary_cast)]
115116
let at = nth as u64 * self.beacon_interval();
116117
if at < self.known_size() {
117118
SeqPos::At(at as SeqNo)
@@ -130,6 +131,7 @@ impl MessageSource {
130131
SeqPos::Beginning | SeqPos::At(0) => unreachable!(),
131132
SeqPos::End => max,
132133
SeqPos::At(nth) => {
134+
#[allow(clippy::unnecessary_cast)]
133135
let at = nth as u64 * self.beacon_interval();
134136
if at < self.known_size() {
135137
at

sea-streamer-redis/src/consumer/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ use flume::{bounded, unbounded, Receiver, Sender};
1515
use std::{fmt::Debug, future::Future, sync::Arc, time::Duration};
1616

1717
use crate::{
18-
from_seq_no, get_message_id, host_id, MessageId, RedisCluster, RedisErr, RedisResult,
19-
TimestampFormat, DEFAULT_TIMEOUT, MAX_MSG_ID,
18+
from_seq_no, get_message_id, host_id, MessageField, MessageId, RedisCluster, RedisErr,
19+
RedisResult, TimestampFormat, DEFAULT_TIMEOUT, MAX_MSG_ID,
2020
};
2121
use sea_streamer_runtime::{spawn_task, timeout};
2222
use sea_streamer_types::{
@@ -51,6 +51,7 @@ pub struct RedisConsumerOptions {
5151
shard_ownership: ShardOwnership,
5252
mkstream: bool,
5353
pub(crate) timestamp_format: TimestampFormat,
54+
pub(crate) message_field: MessageField,
5455
}
5556

5657
#[derive(Debug)]

sea-streamer-redis/src/consumer/node.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,11 @@ impl Node {
545545
assert!(self.buffer.is_empty());
546546
match conn.req_packed_command(&cmd).await {
547547
Ok(value) => {
548-
match StreamReadReply::from_redis_value(value, self.options.timestamp_format) {
548+
match StreamReadReply::from_redis_value(
549+
value,
550+
self.options.timestamp_format,
551+
self.options.message_field,
552+
) {
549553
Ok(StreamReadReply(mut mess)) => {
550554
log::trace!("Read {} messages", mess.len());
551555
if mess.is_empty() {
@@ -678,6 +682,7 @@ impl Node {
678682
claiming.stream.0.clone(),
679683
claiming.stream.1,
680684
self.options.timestamp_format,
685+
self.options.message_field,
681686
) {
682687
Ok(AutoClaimReply(mut mess)) => {
683688
log::trace!(

sea-streamer-redis/src/consumer/options.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use super::{constants::*, ConsumerConfig, RedisConsumerOptions};
2-
use crate::{RedisErr, RedisResult, TimestampFormat};
2+
use crate::{MessageField, RedisErr, RedisResult, TimestampFormat};
33
use sea_streamer_types::{ConsumerGroup, ConsumerId, ConsumerMode, ConsumerOptions, StreamErr};
44
use std::time::Duration;
55

@@ -84,6 +84,7 @@ impl ConsumerOptions for RedisConsumerOptions {
8484
shard_ownership: ShardOwnership::Shared,
8585
mkstream: false,
8686
timestamp_format: TimestampFormat::default(),
87+
message_field: MessageField::default(),
8788
}
8889
}
8990

sea-streamer-redis/src/message.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{RedisErr, RedisResult, TimestampFormat as TsFmt, MSG, ZERO};
1+
use crate::{MessageField as MsgF, RedisErr, RedisResult, TimestampFormat as TsFmt, ZERO};
22
use redis::Value;
33
use sea_streamer_types::{
44
MessageHeader, SeqNo, ShardId, SharedMessage, StreamErr, StreamKey, Timestamp,
@@ -66,6 +66,7 @@ pub(crate) fn get_message_id(header: &MessageHeader) -> MessageId {
6666

6767
#[inline]
6868
pub(crate) fn from_seq_no(seq_no: SeqNo) -> MessageId {
69+
#[allow(clippy::unnecessary_cast)]
6970
((seq_no >> 16) as u64, (seq_no & 0xFFFF) as u16)
7071
}
7172

@@ -85,7 +86,7 @@ impl RedisMessageId for RedisMessage {
8586
// LOL such nesting. This is still undesirable, as there are 5 layers of nested Vec. But at least we don't have to copy the bytes again.
8687
impl StreamReadReply {
8788
/// Like [`redis::FromRedisValue`], but taking ownership instead of copying.
88-
pub(crate) fn from_redis_value(value: Value, ts_fmt: TsFmt) -> RedisResult<Self> {
89+
pub(crate) fn from_redis_value(value: Value, ts_fmt: TsFmt, msg: MsgF) -> RedisResult<Self> {
8990
let mut messages = Vec::new();
9091

9192
if let Value::Bulk(values) = value {
@@ -113,7 +114,7 @@ impl StreamReadReply {
113114
};
114115
let stream_key = StreamKey::new(stream_key)?;
115116
if let Value::Bulk(values) = value_1 {
116-
parse_messages(values, stream_key, shard, &mut messages, ts_fmt)?;
117+
parse_messages(values, stream_key, shard, &mut messages, ts_fmt, msg)?;
117118
}
118119
}
119120
}
@@ -129,6 +130,7 @@ impl AutoClaimReply {
129130
stream_key: StreamKey,
130131
shard: ShardId,
131132
ts_fmt: TsFmt,
133+
msg: MsgF,
132134
) -> RedisResult<Self> {
133135
let mut messages = Vec::new();
134136
if let Value::Bulk(values) = value {
@@ -139,7 +141,7 @@ impl AutoClaimReply {
139141
_ = values.next().unwrap();
140142
let value = values.next().unwrap();
141143
if let Value::Bulk(values) = value {
142-
parse_messages(values, stream_key, shard, &mut messages, ts_fmt)?;
144+
parse_messages(values, stream_key, shard, &mut messages, ts_fmt, msg)?;
143145
} else {
144146
return Err(err(value));
145147
}
@@ -154,6 +156,7 @@ fn parse_messages(
154156
shard: ShardId,
155157
messages: &mut Vec<RedisMessage>,
156158
ts_fmt: TsFmt,
159+
msg: MsgF,
157160
) -> RedisResult<()> {
158161
for value in values {
159162
if let Value::Bulk(values) = value {
@@ -173,7 +176,7 @@ fn parse_messages(
173176
let field = values.next().unwrap();
174177
let field = string_from_redis_value(field)?;
175178
let value = values.next().unwrap();
176-
if field == MSG {
179+
if field == msg.0 {
177180
let bytes = bytes_from_redis_value(value)?;
178181
let length = bytes.len();
179182
messages.push(RedisMessage::new(

sea-streamer-redis/src/producer.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use redis::{aio::ConnectionLike, cmd as command, ErrorKind, Pipeline};
33
use std::{fmt::Debug, future::Future, sync::Arc, time::Duration};
44

55
use crate::{
6-
map_err, parse_message_id, string_from_redis_value, RedisCluster, RedisErr, RedisResult,
7-
TimestampFormat, MSG, ZERO,
6+
map_err, parse_message_id, string_from_redis_value, MessageField, RedisCluster, RedisErr,
7+
RedisResult, TimestampFormat, ZERO,
88
};
99
use sea_streamer_runtime::{sleep, spawn_task};
1010
use sea_streamer_types::{
@@ -26,6 +26,7 @@ pub struct RedisProducer {
2626
pub struct RedisProducerOptions {
2727
sharder: Option<Arc<dyn SharderConfig>>,
2828
pub(crate) timestamp_format: TimestampFormat,
29+
pub(crate) message_field: MessageField,
2930
}
3031

3132
impl Debug for RedisProducerOptions {
@@ -190,6 +191,7 @@ pub(crate) async fn create_producer(
190191
let (sender, receiver) = unbounded();
191192
let mut sharder = options.sharder.take().map(|a| a.init());
192193
let timestamp_format = options.timestamp_format;
194+
let message_field = options.message_field;
193195

194196
// Redis commands are exclusive (`&mut self`), so we need a producer task
195197
spawn_task(async move {
@@ -238,7 +240,7 @@ pub(crate) async fn create_producer(
238240
cmd.arg(&ts)
239241
}
240242
};
241-
let msg = [(MSG, bytes)];
243+
let msg = [(message_field.0, bytes)];
242244
cmd.arg(&msg);
243245
let command = (redis_key.to_owned(), stream_key, shard, receipt);
244246
if batch.0.is_empty() || batch.0.last().unwrap().0 == command.0 {

sea-streamer-redis/src/streamer.rs

+22-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::{sync::Arc, time::Duration};
22

33
use crate::{
44
create_consumer, create_producer, RedisCluster, RedisConsumer, RedisConsumerOptions, RedisErr,
5-
RedisProducer, RedisProducerOptions, RedisResult, REDIS_PORT,
5+
RedisProducer, RedisProducerOptions, RedisResult, MSG, REDIS_PORT,
66
};
77
use sea_streamer_types::{
88
ConnectOptions, StreamErr, StreamKey, StreamUrlErr, Streamer, StreamerUri,
@@ -25,6 +25,16 @@ pub struct RedisConnectOptions {
2525
enable_cluster: bool,
2626
disable_hostname_verification: bool,
2727
timestamp_format: TimestampFormat,
28+
message_field: MessageField,
29+
}
30+
31+
#[derive(Debug, Copy, Clone)]
32+
pub(crate) struct MessageField(pub &'static str);
33+
34+
impl Default for MessageField {
35+
fn default() -> Self {
36+
Self(MSG)
37+
}
2838
}
2939

3040
#[derive(Debug, Default, Clone, Copy)]
@@ -75,6 +85,7 @@ impl Streamer for RedisStreamer {
7585
mut options: Self::ProducerOptions,
7686
) -> RedisResult<Self::Producer> {
7787
options.timestamp_format = self.options.timestamp_format;
88+
options.message_field = self.options.message_field;
7889
let cluster = RedisCluster::new(self.uri.clone(), self.options.clone())?;
7990
create_producer(cluster, options).await
8091
}
@@ -85,6 +96,7 @@ impl Streamer for RedisStreamer {
8596
mut options: Self::ConsumerOptions,
8697
) -> RedisResult<Self::Consumer> {
8798
options.timestamp_format = self.options.timestamp_format;
99+
options.message_field = self.options.message_field;
88100
let cluster = RedisCluster::new(self.uri.clone(), self.options.clone())?;
89101
create_consumer(cluster, options, streams.to_vec()).await
90102
}
@@ -160,4 +172,13 @@ impl RedisConnectOptions {
160172
self.timestamp_format = fmt;
161173
self
162174
}
175+
176+
pub fn message_field(&self) -> &'static str {
177+
self.message_field.0
178+
}
179+
/// The field used to hold the message. Defaults to [`crate::MSG`].
180+
pub fn set_message_field(&mut self, field: &'static str) -> &mut Self {
181+
self.message_field = MessageField(field);
182+
self
183+
}
163184
}

0 commit comments

Comments
 (0)