Skip to content

Commit be78886

Browse files
committed
Add delay condition
1 parent 7d93ced commit be78886

1 file changed

Lines changed: 61 additions & 6 deletions

File tree

src/transforms/delay.rs

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use vector_lib::config::clone_input_definitions;
88
use vector_lib::configurable::configurable_component;
99

1010
use crate::{
11+
conditions::{AnyCondition, Condition},
1112
config::{DataType, Input, OutputId, TransformConfig, TransformContext, TransformOutput},
1213
event::Event,
1314
schema,
@@ -24,6 +25,9 @@ pub struct DelayConfig {
2425
#[serde_as(as = "serde_with::DurationSecondsWithFrac<f64>")]
2526
#[configurable(metadata(docs::human_name = "Delay per event", docs::example = 0.2))]
2627
delay_per_event: Duration,
28+
29+
/// Delay only events matched by this condition.
30+
condition: Option<AnyCondition>,
2731
}
2832

2933
impl_generate_config_from_default!(DelayConfig);
@@ -32,7 +36,7 @@ impl_generate_config_from_default!(DelayConfig);
3236
#[typetag::serde(name = "delay")]
3337
impl TransformConfig for DelayConfig {
3438
async fn build(&self, context: &TransformContext) -> crate::Result<Transform> {
35-
Ok(Transform::event_task(Delay::new(self, context)))
39+
Ok(Transform::event_task(Delay::new(self, context)?))
3640
}
3741

3842
fn input(&self) -> Input {
@@ -55,14 +59,21 @@ impl TransformConfig for DelayConfig {
5559
pub struct Delay {
5660
delay: Duration,
5761
queue: DelayQueue<Event>,
62+
condition: Condition,
5863
}
5964

6065
impl Delay {
61-
pub fn new(config: &DelayConfig, _context: &TransformContext) -> Self {
62-
Self {
66+
pub fn new(config: &DelayConfig, context: &TransformContext) -> crate::Result<Self> {
67+
Ok(Self {
6368
delay: config.delay_per_event,
6469
queue: DelayQueue::new(),
65-
}
70+
condition: config
71+
.condition
72+
.as_ref()
73+
.map(|c| c.build(&context.enrichment_tables, &context.metrics_storage))
74+
.transpose()?
75+
.unwrap_or(Condition::AlwaysPass),
76+
})
6677
}
6778
}
6879

@@ -84,7 +95,12 @@ impl TaskTransform<Event> for Delay {
8495
done = true;
8596
}
8697
Some(event) => {
87-
self.queue.insert(event, self.delay);
98+
let (result, event) = self.condition.check(event);
99+
if result {
100+
self.queue.insert(event, self.delay);
101+
} else {
102+
yield event;
103+
}
88104
}
89105
}
90106
},
@@ -105,6 +121,7 @@ mod tests {
105121
use std::task::Poll;
106122

107123
use futures::SinkExt;
124+
use vector_lib::event::TraceEvent;
108125

109126
use super::*;
110127
use crate::event::LogEvent;
@@ -123,14 +140,52 @@ delay_per_event = 0.2
123140
)
124141
.unwrap();
125142

126-
let delay = Transform::event_task(Delay::new(&config, &TransformContext::default()));
143+
let delay =
144+
Transform::event_task(Delay::new(&config, &TransformContext::default()).unwrap());
145+
146+
let delay = delay.into_task();
147+
148+
let (mut tx, rx) = futures::channel::mpsc::channel(10);
149+
let mut out_stream = delay.transform_events(Box::pin(rx));
150+
151+
tx.send(LogEvent::default().into()).await.unwrap();
152+
153+
// We should be pending, because we are now waiting for the delay
154+
assert_eq!(Poll::Pending, futures::poll!(out_stream.next()));
155+
156+
// Wait long enough for delay to end
157+
tokio::time::sleep(Duration::from_secs_f64(0.3)).await;
158+
159+
if !matches!(futures::poll!(out_stream.next()), Poll::Ready(Some(_event))) {
160+
panic!("Unexpectedly received None or Pending in output stream");
161+
}
162+
}
163+
164+
#[tokio::test]
165+
async fn delay_events_condition() {
166+
let config = toml::from_str::<DelayConfig>(
167+
r#"
168+
delay_per_event = 0.2
169+
condition.type = "is_log"
170+
"#,
171+
)
172+
.unwrap();
173+
174+
let delay =
175+
Transform::event_task(Delay::new(&config, &TransformContext::default()).unwrap());
127176

128177
let delay = delay.into_task();
129178

130179
let (mut tx, rx) = futures::channel::mpsc::channel(10);
131180
let mut out_stream = delay.transform_events(Box::pin(rx));
132181

133182
tx.send(LogEvent::default().into()).await.unwrap();
183+
tx.send(TraceEvent::default().into()).await.unwrap();
184+
185+
let Poll::Ready(Some(event)) = futures::poll!(out_stream.next()) else {
186+
panic!("Unexpectedly received None or Pending in output stream");
187+
};
188+
assert!(event.try_into_trace().is_some());
134189

135190
// We should be pending, because we are now waiting for the delay
136191
assert_eq!(Poll::Pending, futures::poll!(out_stream.next()));

0 commit comments

Comments
 (0)