mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-09 00:04:10 +00:00
fix: add WM_SCHEDULED_FOR to contextual variables and early stop of flows
This commit is contained in:
@@ -567,6 +567,7 @@ pub async fn transform_json_value<'c>(
|
||||
job.flow_step_id.clone(),
|
||||
job.root_job.map(|x| x.to_string()),
|
||||
None,
|
||||
Some(job.scheduled_for.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ async fn list_contextual_variables(
|
||||
Some("c".to_string()),
|
||||
Some("017e0ad5-f499-73b6-5488-92a61c5196dd".to_string()),
|
||||
Some("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c".to_string()),
|
||||
Some(chrono::offset::Utc::now())
|
||||
)
|
||||
.await
|
||||
.to_vec(),
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
* LICENSE-AGPL for a copy of the license.
|
||||
*/
|
||||
|
||||
use chrono::Utc;
|
||||
use magic_crypt::{MagicCrypt256, MagicCryptError, MagicCryptTrait};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
@@ -147,6 +148,8 @@ pub async fn decrypt_value_with_mc(
|
||||
})?)
|
||||
}
|
||||
|
||||
pub const WM_SCHEDULED_FOR: &str = "WM_SCHEDULED_FOR";
|
||||
|
||||
pub async fn get_reserved_variables(
|
||||
db: &DB,
|
||||
w_id: &str,
|
||||
@@ -162,6 +165,7 @@ pub async fn get_reserved_variables(
|
||||
step_id: Option<String>,
|
||||
root_flow_id: Option<String>,
|
||||
jwt_token: Option<String>,
|
||||
scheduled_for: Option<chrono::DateTime<Utc>>,
|
||||
) -> Vec<ContextualVariable> {
|
||||
let state_path = {
|
||||
let trigger = if schedule_path.is_some() {
|
||||
@@ -247,6 +251,14 @@ pub async fn get_reserved_variables(
|
||||
description: "Job id of the current script".to_string(),
|
||||
is_custom: false,
|
||||
},
|
||||
ContextualVariable {
|
||||
name: WM_SCHEDULED_FOR.to_string(),
|
||||
value: scheduled_for
|
||||
.map(|ts| ts.to_string())
|
||||
.unwrap_or_else(|| "".to_string()),
|
||||
description: "date-time in UTC (e.g: 2014-11-28T12:45:59.324310806Z) of when the job was scheduled".to_string(),
|
||||
is_custom: false,
|
||||
},
|
||||
ContextualVariable {
|
||||
name: "WM_JOB_PATH".to_string(),
|
||||
value: path.unwrap_or_else(|| "".to_string()),
|
||||
|
||||
@@ -945,6 +945,7 @@ pub async fn start_worker(
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let context_envs = build_envs_map(context.to_vec()).await;
|
||||
|
||||
@@ -314,6 +314,7 @@ pub async fn transform_json_value(
|
||||
job.flow_step_id.clone(),
|
||||
job.root_job.clone().map(|x| x.to_string()),
|
||||
None,
|
||||
Some(job.scheduled_for.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -411,6 +412,7 @@ pub async fn get_reserved_variables(
|
||||
job.flow_step_id.clone(),
|
||||
job.root_job.clone().map(|x| x.to_string()),
|
||||
None,
|
||||
Some(job.scheduled_for.clone()),
|
||||
)
|
||||
.await
|
||||
.to_vec();
|
||||
|
||||
@@ -435,6 +435,7 @@ pub async fn start_worker(
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let context_envs = build_envs_map(context.to_vec()).await;
|
||||
|
||||
@@ -141,6 +141,7 @@ pub async fn eval_timeout(
|
||||
flow_input: Option<mappable_rc::Marc<HashMap<String, Box<RawValue>>>>,
|
||||
authed_client: Option<&AuthedClient>,
|
||||
by_id: Option<IdContext>,
|
||||
ctx: Option<Vec<(String, String)>>,
|
||||
) -> anyhow::Result<Box<RawValue>> {
|
||||
let expr = expr.trim().to_string();
|
||||
|
||||
@@ -305,6 +306,7 @@ pub async fn eval_timeout(
|
||||
context_keys,
|
||||
by_id,
|
||||
has_client,
|
||||
ctx,
|
||||
))?;
|
||||
|
||||
Ok(r) as anyhow::Result<Box<RawValue>>
|
||||
@@ -367,8 +369,10 @@ async fn eval(
|
||||
transform_context: Vec<String>,
|
||||
by_id: Option<IdContext>,
|
||||
has_client: bool,
|
||||
ctx: Option<Vec<(String, String)>>,
|
||||
) -> anyhow::Result<Box<RawValue>> {
|
||||
tracing::debug!("evaluating: {} {:#?}", expr, by_id);
|
||||
|
||||
let (api_code, by_id_code) = if has_client {
|
||||
let by_id_code = if let Some(by_id) = by_id {
|
||||
format!(
|
||||
@@ -440,11 +444,21 @@ async function resource(path) {{
|
||||
} else {
|
||||
format!("return {expr}")
|
||||
};
|
||||
|
||||
let ctx_str = ctx
|
||||
.map(|x| {
|
||||
x.into_iter()
|
||||
.map(|(k, v)| format!("let {} = \"{}\";", k, v))
|
||||
.join("\n")
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let code = format!(
|
||||
r#"
|
||||
function get_from_env(name) {{
|
||||
return JSON.parse(Deno.core.ops.op_get_context(name));
|
||||
}}
|
||||
{ctx_str}
|
||||
|
||||
{api_code}
|
||||
{}
|
||||
{}
|
||||
@@ -868,6 +882,7 @@ mod tests {
|
||||
vec!["params".to_string(), "value".to_string()],
|
||||
None,
|
||||
false,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
assert_eq!(res.get(), "4");
|
||||
@@ -882,7 +897,7 @@ return `my ${x}
|
||||
multiline template`";
|
||||
|
||||
let mut runtime = JsRuntime::new(RuntimeOptions::default());
|
||||
let res = eval(&mut runtime, code, env, None, false).await?;
|
||||
let res = eval(&mut runtime, code, env, None, false, None).await?;
|
||||
assert_eq!(res.get(), "\"my 5\\nmultiline template\"");
|
||||
Ok(())
|
||||
}
|
||||
@@ -908,7 +923,7 @@ multiline template`";
|
||||
op_state.put(TransformContext { flow_input: None, envs: env.clone() })
|
||||
}
|
||||
|
||||
let res = eval_timeout(code.to_string(), env, None, None, None).await?;
|
||||
let res = eval_timeout(code.to_string(), env, None, None, None, None).await?;
|
||||
assert_eq!(res.get(), "2");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1049,6 +1049,7 @@ pub async fn start_worker(
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.to_vec();
|
||||
@@ -1167,6 +1168,7 @@ for line in sys.stdin:
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
|
||||
|
||||
@@ -288,6 +288,7 @@ pub async fn update_flow_status_after_job_completion_internal<
|
||||
None,
|
||||
Some(client),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
@@ -1174,6 +1175,7 @@ async fn compute_bool_from_expr(
|
||||
by_id: Option<IdContext>,
|
||||
client: Option<&AuthedClient>,
|
||||
resumes: Option<(Arc<Box<RawValue>>, Arc<Box<RawValue>>, Arc<Box<RawValue>>)>,
|
||||
ctx: Option<Vec<(String, String)>>,
|
||||
) -> error::Result<bool> {
|
||||
let mut context = HashMap::with_capacity(if resumes.is_some() { 7 } else { 3 });
|
||||
context.insert("result".to_string(), result.clone());
|
||||
@@ -1191,6 +1193,7 @@ async fn compute_bool_from_expr(
|
||||
Some(flow_args),
|
||||
client,
|
||||
by_id,
|
||||
ctx,
|
||||
)
|
||||
.await?
|
||||
.get()
|
||||
@@ -1300,6 +1303,7 @@ async fn transform_input(
|
||||
Some(flow_args.clone()),
|
||||
Some(client),
|
||||
Some(by_id.clone()),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@@ -1552,6 +1556,10 @@ async fn push_next_flow_job<R: rsmq_async::RsmqConnection + Send + Sync + Clone>
|
||||
None,
|
||||
Some(client),
|
||||
None,
|
||||
Some(vec![(
|
||||
windmill_common::variables::WM_SCHEDULED_FOR.to_string(),
|
||||
flow_job.scheduled_for.to_string(),
|
||||
)]),
|
||||
)
|
||||
.await?;
|
||||
if skip {
|
||||
@@ -1667,6 +1675,7 @@ async fn push_next_flow_job<R: rsmq_async::RsmqConnection + Send + Sync + Clone>
|
||||
Some(arc_flow_job_args.clone()),
|
||||
None,
|
||||
None,
|
||||
None
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@@ -1855,6 +1864,7 @@ async fn push_next_flow_job<R: rsmq_async::RsmqConnection + Send + Sync + Clone>
|
||||
Some(arc_flow_job_args.clone()),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
@@ -2936,6 +2946,7 @@ async fn compute_next_flow_transform(
|
||||
Some(idcontext.clone()),
|
||||
Some(client),
|
||||
Some((resumes.clone(), resume.clone(), approvers.clone())),
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -3254,6 +3265,7 @@ async fn next_forloop_status(
|
||||
Some(arc_flow_job_args),
|
||||
Some(client),
|
||||
Some(by_id),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
@@ -3314,6 +3326,7 @@ async fn next_forloop_status(
|
||||
Some(arc_flow_job_args),
|
||||
Some(client),
|
||||
Some(by_id),
|
||||
None,
|
||||
)
|
||||
.await?
|
||||
}
|
||||
|
||||
@@ -431,8 +431,15 @@
|
||||
class="small-editor"
|
||||
extraLib={`declare const flow_input = ${JSON.stringify(
|
||||
schemaToObject(asSchema($flowStore.schema), $previewArgs)
|
||||
)};`}
|
||||
)};
|
||||
declare const WM_SCHEDULED_FOR: string;`}
|
||||
/>
|
||||
<div class="text-xs text-tertiary mt-2">
|
||||
You can use the variable `flow_input` to access the inputs of the flow. <br
|
||||
/>The variable `WM_SCHEDULED_FOR` contains the time the flow was scheduled for
|
||||
which you can use to stop early non fresh jobs:
|
||||
<pre>new Date().getTime() - new Date(WM_SCHEDULED_FOR).getTime() {'>'} X</pre>
|
||||
</div>
|
||||
</div>
|
||||
{:else}
|
||||
<textarea disabled rows="3" class="min-h-[80px]" />
|
||||
|
||||
@@ -428,6 +428,7 @@ interface Process {
|
||||
WM_USERNAME: string;
|
||||
WM_BASE_URL: string;
|
||||
WM_JOB_ID: string;
|
||||
WM_SCHEDULED_FOR: string;
|
||||
WM_JOB_PATH: string;
|
||||
WM_FLOW_JOB_ID: string;
|
||||
WM_ROOT_FLOW_JOB_ID: string;
|
||||
|
||||
@@ -164,6 +164,7 @@ declare module 'process' {
|
||||
WM_USERNAME: string
|
||||
WM_BASE_URL: string
|
||||
WM_JOB_ID: string
|
||||
WM_SCHEDULED_FOR: string
|
||||
WM_JOB_PATH: string
|
||||
WM_FLOW_JOB_ID: string
|
||||
WM_ROOT_FLOW_JOB_ID: string
|
||||
|
||||
Reference in New Issue
Block a user