Skip to content

Commit a11d46d

Browse files
nikhilsinhaparseableparmesant
authored andcommitted
Merge branch 'main' into alerts-updates
2 parents 4c5784b + 574e3b1 commit a11d46d

File tree

7 files changed

+89
-19
lines changed

7 files changed

+89
-19
lines changed

src/alerts/alert_enums.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ pub enum EvalConfig {
235235
pub enum AlertState {
236236
Triggered,
237237
#[default]
238+
#[serde(rename = "not-triggered")]
238239
NotTriggered,
239240
Disabled,
240241
}
@@ -254,7 +255,7 @@ impl Display for AlertState {
254255
pub enum NotificationState {
255256
#[default]
256257
Notify,
257-
/// Snoozed means the alert will evaluate but no notifications will be sent out
258+
/// Mute means the alert will evaluate but no notifications will be sent out
258259
///
259260
/// It is a state which can only be set manually
260261
///

src/alerts/alert_structs.rs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
*
1717
*/
1818

19-
use std::collections::HashMap;
19+
use std::{collections::HashMap, time::Duration};
2020

2121
use chrono::{DateTime, Utc};
2222
use serde::{Deserialize, Serialize};
@@ -431,12 +431,56 @@ pub struct ForecastConfig {
431431
pub forecast_duration: String,
432432
}
433433

434+
impl ForecastConfig {
435+
pub fn calculate_eval_window(&self) -> Result<String, AlertError> {
436+
let parsed_historic_duration =
437+
if let Ok(historic_duration) = humantime::parse_duration(&self.historic_duration) {
438+
historic_duration
439+
} else {
440+
return Err(AlertError::Metadata(
441+
"historicDuration should be of type humantime",
442+
));
443+
};
444+
445+
let eval_window = if parsed_historic_duration.lt(&Duration::from_secs(60 * 60 * 24 * 3)) {
446+
// less than 3 days = 10 mins
447+
"10m"
448+
} else {
449+
"30m"
450+
};
451+
452+
Ok(eval_window.into())
453+
}
454+
}
455+
434456
#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, PartialEq)]
435457
#[serde(rename_all = "camelCase")]
436458
pub struct AnomalyConfig {
437459
pub historic_duration: String,
438460
}
439461

462+
impl AnomalyConfig {
463+
pub fn calculate_eval_window(&self) -> Result<String, AlertError> {
464+
let parsed_historic_duration =
465+
if let Ok(historic_duration) = humantime::parse_duration(&self.historic_duration) {
466+
historic_duration
467+
} else {
468+
return Err(AlertError::Metadata(
469+
"historicDuration should be of type humantime",
470+
));
471+
};
472+
473+
let eval_window = if parsed_historic_duration.lt(&Duration::from_secs(60 * 60 * 24 * 3)) {
474+
// less than 3 days = 10 mins
475+
"10m"
476+
} else {
477+
"30m"
478+
};
479+
480+
Ok(eval_window.into())
481+
}
482+
}
483+
440484
/// Result structure for alert query execution with group support
441485
#[derive(Debug, Clone, Serialize, Deserialize)]
442486
pub struct AlertQueryResult {

src/alerts/alerts_utils.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,10 +275,9 @@ async fn update_alert_state(
275275
} else {
276276
return Err(AlertError::CustomError("No AlertManager set".into()));
277277
}
278-
// Lock is released here
279278
};
280279

281-
// Now perform the state update without holding the ALERTS lock
280+
// Now perform the state update
282281
if let Some(msg) = message {
283282
alerts
284283
.update_state(*alert.get_id(), AlertState::Triggered, Some(msg))

src/alerts/target.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,6 @@ impl Target {
233233
// call once and then start sleeping
234234
// reduce repeats by 1
235235
call_target(self.target.clone(), context.clone());
236-
// trace!("state not timed out- {state:?}");
237236
// set state
238237
state.timed_out = true;
239238
state.awaiting_resolve = true;
@@ -539,17 +538,6 @@ impl CallableTarget for AlertManager {
539538

540539
let alert = &mut alerts[0];
541540

542-
// alert["labels"].as_object_mut().expect("is object").extend(
543-
// payload
544-
// .additional_labels
545-
// .as_object()
546-
// .expect("is object")
547-
// .iter()
548-
// // filter non null values for alertmanager and only pass strings
549-
// .filter(|(_, value)| !value.is_null())
550-
// .map(|(k, value)| (k.to_owned(), json::convert_to_string(value))),
551-
// );
552-
553541
// fill in status label accordingly
554542
match payload.alert_info.alert_state {
555543
AlertState::Triggered => alert["labels"]["status"] = "triggered".into(),

src/handlers/http/alerts.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ pub async fn post(
8181
) -> Result<impl Responder, AlertError> {
8282
let mut alert: AlertConfig = alert.into().await?;
8383

84+
if alert.notification_config.interval > alert.get_eval_frequency() {
85+
return Err(AlertError::ValidationFailure(
86+
"Notification interval cannot exceed evaluation frequency".into(),
87+
));
88+
}
89+
8490
if alert.get_eval_frequency().eq(&0) {
8591
return Err(AlertError::ValidationFailure(
8692
"Eval frequency cannot be 0".into(),
@@ -386,6 +392,8 @@ pub async fn modify_alert(
386392
}
387393
};
388394

395+
new_alert.validate(&session_key).await?;
396+
389397
// Perform I/O operations
390398
let path = alert_json_path(*new_alert.get_id());
391399
let store = PARSEABLE.storage.get_object_store();

src/static_schema.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ pub fn convert_static_schema_to_arrow_schema(
124124
"boolean_list" => {
125125
DataType::List(Arc::new(Field::new("item", DataType::Boolean, true)))
126126
}
127-
_ => DataType::Null,
127+
_ => {
128+
return Err(StaticSchemaError::UnrecognizedDataType(
129+
field.data_type.clone(),
130+
));
131+
}
128132
}
129133
},
130134
nullable: default_nullable(),
@@ -216,6 +220,9 @@ pub enum StaticSchemaError {
216220

217221
#[error("duplicate field name: {0}")]
218222
DuplicateField(String),
223+
224+
#[error("unrecognized data type: {0}")]
225+
UnrecognizedDataType(String),
219226
}
220227

221228
#[cfg(test)]
@@ -233,4 +240,24 @@ mod tests {
233240
let _ = validate_field_names("test_field", &mut existing_field_names);
234241
assert!(validate_field_names("test_field", &mut existing_field_names).is_err());
235242
}
243+
244+
#[test]
245+
fn unrecognized_data_type() {
246+
let static_schema = StaticSchema {
247+
fields: vec![SchemaFields {
248+
name: "test_field".to_string(),
249+
data_type: "unknown_type".to_string(),
250+
}],
251+
};
252+
253+
let result = convert_static_schema_to_arrow_schema(static_schema, "", None);
254+
255+
assert!(result.is_err());
256+
match result.unwrap_err() {
257+
StaticSchemaError::UnrecognizedDataType(data_type) => {
258+
assert_eq!(data_type, "unknown_type");
259+
}
260+
_ => panic!("Expected UnrecognizedDataType error"),
261+
}
262+
}
236263
}

src/sync.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,12 @@ pub async fn alert_runtime(mut rx: mpsc::Receiver<AlertTask>) -> Result<(), anyh
340340
if let Some(handle) = alert_tasks.remove(&ulid) {
341341
// cancel the task
342342
handle.abort();
343-
warn!("Alert with id {} deleted", ulid);
343+
warn!("Alert with id {} deleted from evaluation tasks list", ulid);
344344
} else {
345-
error!("Alert with id {} does not exist", ulid);
345+
error!(
346+
"Alert with id {} does not exist in evaluation tasks list",
347+
ulid
348+
);
346349
}
347350
}
348351
}

0 commit comments

Comments
 (0)