Skip to content

Commit 43c2c9e

Browse files
committed
feat: close producer when topic is deleted
1 parent 790b7fd commit 43c2c9e

File tree

6 files changed

+78
-22
lines changed

6 files changed

+78
-22
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/fluvio-cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ producer-file-io = ["fluvio-cli-common/file-records"]
3939
[dependencies]
4040
async-channel = { workspace = true }
4141
async-trait = { workspace = true }
42+
async-std = { workspace = true }
4243
anyhow = { workspace = true }
4344
bytesize = { workspace = true, features = ['serde'] }
4445
clap = { workspace = true, features = ["std", "derive", "string", "help", "usage", "env", "error-context"] }

crates/fluvio-cli/src/client/produce/mod.rs

Lines changed: 60 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,23 @@ mod cmd {
1111
#[cfg(feature = "producer-file-io")]
1212
use std::path::PathBuf;
1313

14+
use async_std::io::stdin;
1415
use async_trait::async_trait;
16+
use fluvio_future::io::StreamExt;
17+
use fluvio_sc_schema::message::MsgType;
18+
use fluvio_sc_schema::topic::TopicSpec;
1519
#[cfg(feature = "producer-file-io")]
1620
use futures::future::join_all;
1721
use clap::Parser;
22+
use tokio::select;
1823
use tracing::{error, warn};
1924
use humantime::parse_duration;
2025
use anyhow::Result;
2126

2227
use fluvio::{
23-
Compression, Fluvio, FluvioError, TopicProducerPool, TopicProducerConfigBuilder, RecordKey,
24-
ProduceOutput, DeliverySemantic, SmartModuleContextData, Isolation, SmartModuleInvocation,
28+
Compression, DeliverySemantic, Fluvio, FluvioAdmin, FluvioError, Isolation, ProduceOutput,
29+
RecordKey, SmartModuleContextData, SmartModuleInvocation, TopicProducerConfigBuilder,
30+
TopicProducerPool,
2531
};
2632
use fluvio_extension_common::Terminal;
2733
use fluvio_types::print_cli_ok;
@@ -243,16 +249,18 @@ mod cmd {
243249
.await?,
244250
);
245251

252+
let admin = fluvio.admin().await;
253+
246254
#[cfg(feature = "producer-file-io")]
247255
if self.raw {
248256
self.process_raw_file(&producer).await?;
249257
} else {
250-
self.produce_lines(producer.clone()).await?;
258+
self.produce_lines(producer.clone(), &admin).await?;
251259
};
252260

253261
#[cfg(not(feature = "producer-file-io"))]
254262
{
255-
self.produce_lines(producer.clone()).await?;
263+
self.produce_lines(producer.clone(), &admin).await?;
256264
}
257265

258266
producer.flush().await?;
@@ -315,7 +323,11 @@ mod cmd {
315323
}
316324
}
317325

318-
async fn produce_lines(&self, producer: Arc<TopicProducerPool>) -> Result<()> {
326+
async fn produce_lines(
327+
&self,
328+
producer: Arc<TopicProducerPool>,
329+
admin: &FluvioAdmin,
330+
) -> Result<()> {
319331
#[cfg(feature = "producer-file-io")]
320332
if let Some(path) = &self.file {
321333
let reader = BufReader::new(File::open(path)?);
@@ -340,7 +352,7 @@ mod cmd {
340352
.collect::<Result<Vec<_>, _>>()?;
341353
}
342354
} else {
343-
self.producer_stdin(&producer).await?
355+
self.producer_stdin(&producer, admin).await?
344356
}
345357

346358
#[cfg(not(feature = "producer-file-io"))]
@@ -349,27 +361,55 @@ mod cmd {
349361
Ok(())
350362
}
351363

352-
async fn producer_stdin(&self, producer: &Arc<TopicProducerPool>) -> Result<()> {
353-
let mut lines = BufReader::new(std::io::stdin()).lines();
364+
async fn producer_stdin(
365+
&self,
366+
producer: &Arc<TopicProducerPool>,
367+
admin: &FluvioAdmin,
368+
) -> Result<()> {
369+
use async_std::io::prelude::*;
370+
use async_std::io::BufReader;
371+
let mut lines = BufReader::new(stdin()).lines();
372+
let mut partition_stream = admin.watch::<TopicSpec>().await?;
373+
354374
if self.interactive_mode() {
355375
eprint!("> ");
356376
}
357377

358-
while let Some(Ok(line)) = lines.next() {
359-
let produce_output = self.produce_line(producer, &line).await?;
360-
361-
if let Some(produce_output) = produce_output {
362-
if self.delivery_semantic != DeliverySemantic::AtMostOnce {
363-
// ensure it was properly sent
364-
produce_output.wait().await?;
378+
loop {
379+
select! {
380+
line = lines.next() => {
381+
if let Some(Ok(line)) = line {
382+
let produce_output = self.produce_line(producer, &line).await?;
383+
384+
if let Some(produce_output) = produce_output {
385+
if self.delivery_semantic != DeliverySemantic::AtMostOnce {
386+
// ensure it was properly sent
387+
produce_output.wait().await?;
388+
}
389+
}
390+
391+
if self.interactive_mode() {
392+
print_cli_ok!();
393+
eprint!("> ");
394+
}
395+
} else {
396+
// When stdin is closed, we break the loop
397+
break;
398+
}
399+
}
400+
stream = partition_stream.next() => {
401+
if let Some(stream) = stream {
402+
let stream = stream?;
403+
for change in stream.inner().changes {
404+
if change.header == MsgType::DELETE && change.content.name == self.topic {
405+
return Err(CliError::TopicDeleted(self.topic.clone()).into());
406+
}
407+
}
408+
}
365409
}
366-
}
367-
368-
if self.interactive_mode() {
369-
print_cli_ok!();
370-
eprint!("> ");
371410
}
372411
}
412+
373413
Ok(())
374414
}
375415

crates/fluvio-cli/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,6 @@ pub enum CliError {
6767
SmartModuleConfigBuilder(#[from] fluvio_smartengine::SmartModuleConfigBuilderError),
6868
#[error("Hub error: {0}")]
6969
HubError(String),
70+
#[error("Topic \"{0}\" was deleted")]
71+
TopicDeleted(String),
7072
}

tests/cli/fluvio_smoke_tests/produce-error.bats

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,15 @@ teardown_file() {
5757
run bash -c 'echo abcdefgh | timeout 15s "$FLUVIO_BIN" produce "$TOPIC_NAME_2" --compression lz4'
5858
assert_failure
5959
}
60+
61+
# Delete topics should stop producer and return error
62+
@test "Delete topics" {
63+
run bash -c '/usr/bin/expect << EOF
64+
spawn "$FLUVIO_BIN" produce "$TOPIC_NAME"
65+
expect "> "
66+
exec "$FLUVIO_BIN" topic delete "$TOPIC_NAME"
67+
expect eof
68+
'
69+
assert_success
70+
assert_output --partial "Topic \"$TOPIC_NAME\" was deleted"
71+
}

tests/cli/mirroring_smoke_tests/e2e/fluvio-core.bats

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ setup_file() {
130130
}
131131

132132
@test "Home status at remote 1 should show the home cluster connected" {
133-
sleep 15
133+
sleep 20
134134
run timeout 15s "$FLUVIO_BIN" home status
135135

136136
assert_success
@@ -165,7 +165,7 @@ setup_file() {
165165
}
166166

167167
@test "Home status at remote 2 should show the home cluster connected" {
168-
sleep 15
168+
sleep 20
169169
run timeout 15s "$FLUVIO_BIN" home status
170170

171171
assert_success

0 commit comments

Comments
 (0)