Files
windmill/backend/windmill-alerting/src/lib.rs
Ruben Fiszel e26e437dd1 refactor: extract 12 leaf crates from windmill-api (#7899)
* feat(backend): extract 12 leaf crates from windmill-api to improve incremental compilation

Extract independent modules from windmill-api (90k LOC monolith) into
separate leaf crates to reduce incremental compilation times. Modules
extracted: assets, configs, debug, flow-conversations, inputs,
npm-proxy, openapi, schedule, settings, workers, agent-workers, and
alerting (from windmill-common).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add windmill-api-settings dep to root crate, make ee_oss public

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add agent_workers integration tests

8 tests covering agent worker lifecycle:
- Simple script execution (bun)
- Script with arguments
- Script with logs (verified in job_logs table)
- Script failure handling
- Complex result (nested objects/arrays)
- Agent token creation via API
- Token creation + Initial/MainLoop ping cycle
- Multiple sequential job execution

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* all

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 10:31:03 +00:00

209 lines
6.1 KiB
Rust

use axum::Json;
use serde::Deserialize;
use windmill_common::error::{self, JsonResult};
use windmill_common::worker::CLOUD_HOSTED;
use windmill_common::DB;
#[derive(serde::Serialize)]
pub struct CriticalAlert {
id: i32,
alert_type: String,
message: String,
created_at: chrono::DateTime<chrono::Utc>,
acknowledged: Option<bool>,
workspace_id: Option<String>,
}
#[derive(Deserialize, Debug)]
pub struct AlertQueryParams {
pub page: Option<i32>,
pub page_size: Option<i32>,
pub acknowledged: Option<bool>,
}
pub async fn get_critical_alerts(
db: DB,
params: AlertQueryParams,
workspace_id: Option<String>,
) -> JsonResult<serde_json::Value> {
let page = params.page.unwrap_or(1).max(1);
let page_size = params.page_size.unwrap_or(10).min(100) as i64;
let offset = ((page - 1) * page_size as i32) as i64;
let total_rows = if let Some(workspace_id) = &workspace_id {
if params.acknowledged.is_none() {
sqlx::query_scalar!(
"SELECT COUNT(*)
FROM alerts
WHERE workspace_id = $1",
workspace_id
)
.fetch_one(&db)
.await?
} else {
sqlx::query_scalar!(
"SELECT COUNT(*)
FROM alerts
WHERE workspace_id = $1 AND COALESCE(acknowledged_workspace, false) = $2",
workspace_id,
params.acknowledged
)
.fetch_one(&db)
.await?
}
} else {
if params.acknowledged.is_none() {
sqlx::query_scalar!(
"SELECT COUNT(*)
FROM alerts"
)
.fetch_one(&db)
.await?
} else {
sqlx::query_scalar!(
"SELECT COUNT(*)
FROM alerts
WHERE COALESCE(acknowledged, false) = $1",
params.acknowledged
)
.fetch_one(&db)
.await?
}
};
let alerts = if let Some(workspace_id) = workspace_id {
if params.acknowledged.is_none() {
sqlx::query_as!(
CriticalAlert,
"SELECT id, alert_type, message, created_at, COALESCE(acknowledged_workspace, false) AS acknowledged, workspace_id
FROM alerts
WHERE workspace_id = $1
ORDER BY created_at DESC
LIMIT $2 OFFSET $3",
workspace_id,
page_size,
offset
)
.fetch_all(&db)
.await?
} else {
sqlx::query_as!(
CriticalAlert,
"SELECT id, alert_type, message, created_at, COALESCE(acknowledged_workspace, false) AS acknowledged, workspace_id
FROM alerts
WHERE workspace_id = $1 AND COALESCE(acknowledged_workspace, false) = $2
ORDER BY created_at DESC
LIMIT $3 OFFSET $4",
workspace_id,
params.acknowledged,
page_size,
offset
)
.fetch_all(&db)
.await?
}
} else {
if params.acknowledged.is_none() {
sqlx::query_as!(
CriticalAlert,
"SELECT id, alert_type, message, created_at, COALESCE(acknowledged, false) AS acknowledged, workspace_id
FROM alerts
ORDER BY created_at DESC
LIMIT $1 OFFSET $2",
page_size,
offset
)
.fetch_all(&db)
.await?
} else {
sqlx::query_as!(
CriticalAlert,
"SELECT id, alert_type, message, created_at, COALESCE(acknowledged, false) AS acknowledged, workspace_id
FROM alerts
WHERE COALESCE(acknowledged, false) = $1
ORDER BY created_at DESC
LIMIT $2 OFFSET $3",
params.acknowledged,
page_size,
offset
)
.fetch_all(&db)
.await?
}
};
let total_rows = total_rows.unwrap_or(0);
let total_pages = ((total_rows as f64) / (page_size as f64)).ceil() as i64;
Ok(Json(serde_json::json!({
"alerts": alerts,
"total_rows": total_rows,
"total_pages": total_pages
})))
}
pub async fn acknowledge_critical_alert(
db: DB,
workspace_id: Option<String>,
id: i32,
) -> error::Result<String> {
sqlx::query!(
"UPDATE alerts
SET
acknowledged = true,
acknowledged_workspace = CASE
WHEN $3 THEN
CASE
WHEN $2::text IS NOT NULL AND workspace_id = $2 THEN true
ELSE acknowledged_workspace
END
ELSE true
END
WHERE id = $1",
id,
workspace_id,
*CLOUD_HOSTED
)
.execute(&db)
.await?;
tracing::info!(
"Acknowledged critical alert with id: {}{}",
id,
workspace_id.map_or_else(|| "".to_string(), |w| format!(" for workspace_id: {}", w))
);
Ok("Critical alert acknowledged".to_string())
}
pub async fn acknowledge_all_critical_alerts(
db: DB,
workspace_id: Option<String>,
) -> error::Result<String> {
sqlx::query!(
"UPDATE alerts
SET
acknowledged = true,
acknowledged_workspace = CASE
WHEN $2 THEN
CASE
WHEN $1::text IS NOT NULL THEN true
ELSE acknowledged_workspace
END
ELSE true
END
WHERE ($1::text IS NOT NULL AND workspace_id = $1)
OR ($1::text IS NULL)",
workspace_id,
*CLOUD_HOSTED
)
.execute(&db)
.await?;
tracing::info!(
"Acknowledged all unacknowledged critical alerts{}",
workspace_id.map_or_else(|| "".to_string(), |w| format!(" for workspace_id: {}", w))
);
Ok("All unacknowledged critical alerts acknowledged".to_string())
}