Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion core/connectors/sinks/elasticsearch_sink/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,14 @@ use secrecy::{ExposeSecret, SecretString};
use serde::{Deserialize, Serialize};
use serde_json::json;
use simd_json::{OwnedValue, prelude::*};
use std::time::Duration;
use tokio::sync::Mutex;
use tracing::{info, warn};

sink_connector!(ElasticsearchSink);

const DEFAULT_TIMEOUT_SECONDS: u64 = 30;

#[derive(Debug)]
struct State {
invocations_count: usize,
Expand Down Expand Up @@ -83,7 +86,15 @@ impl ElasticsearchSink {
.map_err(|error| Error::Connection(format!("Invalid Elasticsearch URL: {error}")))?;

let conn_pool = elasticsearch::http::transport::SingleNodeConnectionPool::new(url);
let mut transport_builder = TransportBuilder::new(conn_pool);
// elasticsearch-rs defaults to no timeout; without this, a hung ES
// connection blocks FFI open() and the connectors HTTP health never binds.
let timeout_seconds = self
.config
.timeout_seconds
.unwrap_or(DEFAULT_TIMEOUT_SECONDS)
.max(1);
let mut transport_builder =
TransportBuilder::new(conn_pool).timeout(Duration::from_secs(timeout_seconds));

if let (Some(username), Some(password)) = (&self.config.username, &self.config.password) {
let credentials =
Expand Down
24 changes: 19 additions & 5 deletions core/integration/src/harness/handle/connectors_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,19 +243,33 @@ impl IggyServerDependent for ConnectorsRuntimeHandle {
}

async fn wait_ready(&mut self) -> Result<(), TestBinaryError> {
let http_address = self.http_url();
// Prefer /health over `/` so readiness means the connectors API is up,
// not some other listener that happened to bind the reserved port.
let health_url = format!("{}/health", self.http_url());
let client = reqwest::Client::new();

for retry in 0..common::DEFAULT_HEALTH_CHECK_RETRIES {
match client.get(&http_address).send().await {
Ok(_) => {
if let Some(pid) = self.pid()
&& !common::is_process_alive(pid)
{
let (stdout, stderr) = self.collect_logs();
return Err(TestBinaryError::ProcessCrashed {
binary: "iggy-connectors".to_string(),
exit_code: None,
stdout,
stderr,
});
}

match client.get(&health_url).send().await {
Ok(response) if response.status().is_success() => {
return Ok(());
}
Err(_) => {
Ok(_) | Err(_) => {
if retry == common::DEFAULT_HEALTH_CHECK_RETRIES - 1 {
return Err(TestBinaryError::HealthCheckFailed {
binary: "iggy-connectors".to_string(),
address: http_address,
address: health_url,
retries: common::DEFAULT_HEALTH_CHECK_RETRIES,
});
}
Expand Down
Loading
Loading