mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-31 09:18:28 +00:00
refactor(targets): unify queue/connectivity handling and coverage (#2953)
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: marshawcoco <marshawcoco@gmail.com>
This commit is contained in:
@@ -16,15 +16,15 @@ use crate::{
|
||||
StoreError, Target,
|
||||
arn::TargetID,
|
||||
error::TargetError,
|
||||
store::{Key, QueueStore, Store},
|
||||
store::{Key, Store},
|
||||
target::{
|
||||
ChannelTargetType, EntityTarget, QueuedPayload, QueuedPayloadMeta, TargetDeliveryCounters, TargetDeliverySnapshot,
|
||||
TargetType, build_queued_payload, delete_stored_payload, queue_store_subdir_name,
|
||||
TargetType, build_queued_payload, delete_stored_payload, is_connectivity_error, open_target_queue_store,
|
||||
persist_queued_payload_to_store,
|
||||
},
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
use mysql_async::{Conn, Opts, OptsBuilder, Pool, PoolConstraints, PoolOpts, SslOpts, prelude::Queryable};
|
||||
use rustfs_config::notify::NOTIFY_STORE_EXTENSION;
|
||||
use rustfs_config::{MYSQL_TLS_CA, MYSQL_TLS_CLIENT_CERT, MYSQL_TLS_CLIENT_KEY};
|
||||
use serde::Serialize;
|
||||
use serde::de::DeserializeOwned;
|
||||
@@ -494,25 +494,14 @@ where
|
||||
|
||||
let target_id = TargetID::new(id, ChannelTargetType::MySql.as_str().to_string());
|
||||
|
||||
// If `queue_dir` is non-empty, a `QueueStore` is created for persistent at-least-once delivery.
|
||||
let queue_store = if !args.queue_dir.is_empty() {
|
||||
let queue_dir =
|
||||
PathBuf::from(&args.queue_dir).join(queue_store_subdir_name(ChannelTargetType::MySql.as_str(), &target_id.id));
|
||||
|
||||
let extension = match args.target_type {
|
||||
TargetType::AuditLog => rustfs_config::audit::AUDIT_STORE_EXTENSION,
|
||||
TargetType::NotifyEvent => NOTIFY_STORE_EXTENSION,
|
||||
};
|
||||
|
||||
let store = QueueStore::<QueuedPayload>::new(queue_dir, args.queue_limit, extension);
|
||||
if let Err(e) = store.open() {
|
||||
return Err(TargetError::Storage(format!("Failed to open MySQL queue store: {e}")));
|
||||
}
|
||||
|
||||
Some(Box::new(store) as Box<dyn Store<QueuedPayload, Error = StoreError, Key = Key> + Send + Sync>)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let queue_store = open_target_queue_store(
|
||||
&args.queue_dir,
|
||||
args.queue_limit,
|
||||
args.target_type,
|
||||
ChannelTargetType::MySql.as_str(),
|
||||
&target_id,
|
||||
"Failed to open MySQL queue store",
|
||||
)?;
|
||||
|
||||
info!(target_id = %target_id.id, table = %args.table, "MySQL target created");
|
||||
|
||||
@@ -733,18 +722,9 @@ where
|
||||
};
|
||||
|
||||
if let Some(store) = &self.store {
|
||||
// persist the event to a local queue before attempting to insert into MySQL. This will allow us to guarantee at-least-once delivery even if the database is temporarily unreachable or if the process crashes after acknowledging receipt but before writing to the database.
|
||||
let encoded = match queued.encode() {
|
||||
Ok(encoded) => encoded,
|
||||
Err(err) => {
|
||||
self.delivery_counters.record_final_failure();
|
||||
return Err(TargetError::Storage(format!("Failed to encode queued payload: {err}")));
|
||||
}
|
||||
};
|
||||
|
||||
if let Err(e) = store.put_raw(&encoded) {
|
||||
if let Err(e) = persist_queued_payload_to_store(store.as_ref(), &queued) {
|
||||
self.delivery_counters.record_final_failure();
|
||||
return Err(TargetError::Storage(format!("Failed to save event to store: {e}")));
|
||||
return Err(e);
|
||||
}
|
||||
|
||||
debug!("Event saved to queue store for MySQL target: {}", self.id);
|
||||
@@ -789,12 +769,8 @@ where
|
||||
}
|
||||
|
||||
if let Err(e) = self.insert_event(&body, &meta).await {
|
||||
if matches!(e, TargetError::NotConnected) {
|
||||
if is_connectivity_error(&e) {
|
||||
warn!(target_id = %self.id, "MySQL not reachable, event remains in queue store");
|
||||
return Err(TargetError::NotConnected);
|
||||
}
|
||||
if matches!(e, TargetError::Timeout(_)) {
|
||||
warn!(target_id = %self.id, "MySQL timeout, event remains in queue store");
|
||||
return Err(e);
|
||||
}
|
||||
error!(target_id = %self.id, error = %e, "Failed to send event from store");
|
||||
|
||||
Reference in New Issue
Block a user