refactor: enhanced trigger interval (#6740)

* refactor: enhance trigger interval

* update greptime-proto

* fix: build
This commit is contained in:
fys
2025-08-18 12:03:26 +08:00
committed by GitHub
parent f9d2a89a0c
commit 326198162e
17 changed files with 248 additions and 101 deletions

View File

@@ -17,7 +17,7 @@ pg_kvbackend = [
"dep:rustls",
]
mysql_kvbackend = ["dep:sqlx", "dep:backon"]
enterprise = []
enterprise = ["prost-types"]
[lints]
workspace = true
@@ -64,6 +64,7 @@ moka.workspace = true
object-store.workspace = true
prometheus.workspace = true
prost.workspace = true
prost-types = { workspace = true, optional = true }
rand.workspace = true
regex.workspace = true
rskafka.workspace = true

View File

@@ -1027,6 +1027,31 @@ pub enum Error {
actual_column_name: String,
actual_column_id: u32,
},
#[cfg(feature = "enterprise")]
#[snafu(display("Too large duration"))]
TooLargeDuration {
#[snafu(source)]
error: prost_types::DurationError,
#[snafu(implicit)]
location: Location,
},
#[cfg(feature = "enterprise")]
#[snafu(display("Negative duration"))]
NegativeDuration {
#[snafu(source)]
error: prost_types::DurationError,
#[snafu(implicit)]
location: Location,
},
#[cfg(feature = "enterprise")]
#[snafu(display("Missing interval field"))]
MissingInterval {
#[snafu(implicit)]
location: Location,
},
}
pub type Result<T> = std::result::Result<T, Error>;
@@ -1116,8 +1141,13 @@ impl ErrorExt for Error {
| InvalidTimeZone { .. }
| InvalidFileExtension { .. }
| InvalidFileName { .. }
| InvalidFlowRequestBody { .. }
| InvalidFilePath { .. } => StatusCode::InvalidArguments,
InvalidFlowRequestBody { .. } => StatusCode::InvalidArguments,
#[cfg(feature = "enterprise")]
MissingInterval { .. } | NegativeDuration { .. } | TooLargeDuration { .. } => {
StatusCode::InvalidArguments
}
FlowNotFound { .. } => StatusCode::FlowNotFound,
FlowRouteNotFound { .. } => StatusCode::Unexpected,

View File

@@ -328,7 +328,7 @@ impl TryFrom<SubmitDdlTaskRequest> for PbDdlTaskRequest {
DdlTask::CreateView(task) => Task::CreateViewTask(task.try_into()?),
DdlTask::DropView(task) => Task::DropViewTask(task.into()),
#[cfg(feature = "enterprise")]
DdlTask::CreateTrigger(task) => Task::CreateTriggerTask(task.into()),
DdlTask::CreateTrigger(task) => Task::CreateTriggerTask(task.try_into()?),
#[cfg(feature = "enterprise")]
DdlTask::DropTrigger(task) => Task::DropTriggerTask(task.into()),
};

View File

@@ -10,7 +10,7 @@ use api::v1::{
NotifyChannel as PbNotifyChannel, WebhookOptions as PbWebhookOptions,
};
use serde::{Deserialize, Serialize};
use snafu::OptionExt;
use snafu::{OptionExt, ResultExt};
use crate::error;
use crate::error::Result;
@@ -27,6 +27,7 @@ pub struct CreateTriggerTask {
pub labels: HashMap<String, String>,
pub annotations: HashMap<String, String>,
pub interval: Duration,
pub raw_interval_expr: String,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
@@ -51,14 +52,21 @@ pub struct WebhookOptions {
pub opts: HashMap<String, String>,
}
impl From<CreateTriggerTask> for PbCreateTriggerTask {
fn from(task: CreateTriggerTask) -> Self {
impl TryFrom<CreateTriggerTask> for PbCreateTriggerTask {
type Error = error::Error;
fn try_from(task: CreateTriggerTask) -> Result<Self> {
let channels = task
.channels
.into_iter()
.map(PbNotifyChannel::from)
.collect();
let interval = task
.interval
.try_into()
.context(error::TooLargeDurationSnafu)?;
let expr = PbCreateTriggerExpr {
catalog_name: task.catalog_name,
trigger_name: task.trigger_name,
@@ -67,12 +75,13 @@ impl From<CreateTriggerTask> for PbCreateTriggerTask {
channels,
labels: task.labels,
annotations: task.annotations,
interval: task.interval.as_secs(),
interval: Some(interval),
raw_interval_expr: task.raw_interval_expr,
};
PbCreateTriggerTask {
Ok(PbCreateTriggerTask {
create_trigger: Some(expr),
}
})
}
}
@@ -90,6 +99,9 @@ impl TryFrom<PbCreateTriggerTask> for CreateTriggerTask {
.map(NotifyChannel::try_from)
.collect::<Result<Vec<_>>>()?;
let interval = expr.interval.context(error::MissingIntervalSnafu)?;
let interval = interval.try_into().context(error::NegativeDurationSnafu)?;
let task = CreateTriggerTask {
catalog_name: expr.catalog_name,
trigger_name: expr.trigger_name,
@@ -98,7 +110,8 @@ impl TryFrom<PbCreateTriggerTask> for CreateTriggerTask {
channels,
labels: expr.labels,
annotations: expr.annotations,
interval: Duration::from_secs(expr.interval),
interval,
raw_interval_expr: expr.raw_interval_expr,
};
Ok(task)
}
@@ -258,9 +271,10 @@ mod tests {
.into_iter()
.collect(),
interval: Duration::from_secs(60),
raw_interval_expr: "'1 minute'::INTERVAL".to_string(),
};
let pb_task: PbCreateTriggerTask = original.clone().into();
let pb_task: PbCreateTriggerTask = original.clone().try_into().unwrap();
let expr = pb_task.create_trigger.as_ref().unwrap();
assert_eq!(expr.catalog_name, "test_catalog");
@@ -277,7 +291,8 @@ mod tests {
expr.annotations.get("description").unwrap(),
"This is a test"
);
assert_eq!(expr.interval, 60);
let expected: prost_types::Duration = Duration::from_secs(60).try_into().unwrap();
assert_eq!(expr.interval, Some(expected));
let round_tripped = CreateTriggerTask::try_from(pb_task).unwrap();