laminar_connectors/mongodb/sink/
lifecycle.rs1use super::{
4 async_trait, info, Arc, ConnectorConfig, ConnectorError, ConnectorState, ConnectorTaskTracker,
5 Duration, MongoDbSink, RecordBatch, SchemaRef, SinkConnector, SinkConsistency, SinkContract,
6 SinkInputMode, SinkTopology, WriteMode, WriteResult, MAX_BUFFERED_RETAINED_BYTES,
7};
8
9#[async_trait]
10impl SinkConnector for MongoDbSink {
11 fn terminal_task_tracker(&self) -> Option<ConnectorTaskTracker> {
12 Some(self.task_tracker.clone())
13 }
14
15 fn contract(&self, config: &ConnectorConfig) -> Result<SinkContract, ConnectorError> {
16 let (cfg, schema, _) = if config.properties().is_empty() {
17 (
18 self.config.clone(),
19 Arc::clone(&self.schema),
20 self.write_timeout,
21 )
22 } else {
23 Self::decode_connector_config(config)?
24 };
25 cfg.validate()?;
26 Self::validate_schema(&schema, &cfg)?;
27 let (topology, input_mode) = match cfg.write_mode {
28 WriteMode::Insert => (SinkTopology::MultiWriter, SinkInputMode::AppendOnly),
29 WriteMode::Upsert { .. } | WriteMode::CdcReplay => {
30 (SinkTopology::Singleton, SinkInputMode::FullChangelog)
31 }
32 };
33 Ok(SinkContract::new(
34 SinkConsistency::DurableAtLeastOnce,
35 topology,
36 input_mode,
37 ))
38 }
39
40 async fn open(&mut self, config: &ConnectorConfig) -> Result<(), ConnectorError> {
41 if self.state != ConnectorState::Created {
42 return Err(ConnectorError::InvalidState {
43 expected: ConnectorState::Created.to_string(),
44 actual: self.state.to_string(),
45 });
46 }
47 if config.properties().is_empty() {
48 self.config.validate()?;
49 Self::validate_schema(&self.schema, &self.config)?;
50 } else {
51 self.apply_connector_config(config)?;
52 }
53 self.connect().await?;
54
55 self.state = ConnectorState::Running;
56 info!(
57 database = %self.config.database,
58 collection = %self.config.collection,
59 write_mode = ?self.config.write_mode,
60 "MongoDB sink opened"
61 );
62
63 Ok(())
64 }
65
66 async fn write_batch(&mut self, batch: &RecordBatch) -> Result<WriteResult, ConnectorError> {
67 self.write_batch_with_retained_limit(batch, MAX_BUFFERED_RETAINED_BYTES)
68 .await
69 }
70
71 fn schema(&self) -> SchemaRef {
72 Arc::clone(&self.schema)
73 }
74
75 fn suggested_write_timeout(&self) -> Duration {
76 self.write_timeout
77 }
78
79 fn flush_interval(&self) -> Duration {
80 self.config.flush_interval()
81 }
82
83 async fn flush(&mut self) -> Result<(), ConnectorError> {
84 if self.state != ConnectorState::Running {
85 return Err(ConnectorError::InvalidState {
86 expected: ConnectorState::Running.to_string(),
87 actual: self.state.to_string(),
88 });
89 }
90 self.flush_inner().await.map(|_| ())
91 }
92
93 async fn close(&mut self) -> Result<(), ConnectorError> {
94 if self.state == ConnectorState::Closed {
95 return Ok(());
96 }
97
98 let flush_result = if self.state == ConnectorState::Running && !self.buffer.is_empty() {
99 self.flush_inner().await.map(|_| ())
100 } else {
101 drop(self.take_buffer());
102 Ok(())
103 };
104 self.collection = None;
105 self.client = None;
106 self.state = ConnectorState::Closed;
107 info!("MongoDB sink closed");
108 flush_result
109 }
110}