mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-09-09 16:05:42 +00:00
feat: Tag override for scheduled scripts (#2998)
* feat: Tag override for scheduled scripts * Refactor WorkerTagPicker to component * Fix test
This commit is contained in:
committed by
GitHub
parent
22f502d2a8
commit
2edba18038
+6
@@ -125,6 +125,11 @@
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
},
|
||||
{
|
||||
"ordinal": 25,
|
||||
"name": "jobs",
|
||||
"type_info": "JsonArray"
|
||||
}
|
||||
@@ -161,6 +166,7 @@
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
true,
|
||||
null
|
||||
]
|
||||
},
|
||||
|
||||
+11
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "INSERT INTO schedule (workspace_id, path, schedule, timezone, edited_by, script_path, is_flow, args, enabled, email, on_failure, on_failure_times, on_failure_exact, on_failure_extra_args, on_recovery, on_recovery_times, on_recovery_extra_args, ws_error_handler_muted, retry, summary, no_flow_overlap ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21 ) RETURNING *",
|
||||
"query": "INSERT INTO schedule (workspace_id, path, schedule, timezone, edited_by, script_path, is_flow, args, enabled, email, on_failure, on_failure_times, on_failure_exact, on_failure_extra_args, on_recovery, on_recovery_times, on_recovery_extra_args, ws_error_handler_muted, retry, summary, no_flow_overlap, tag ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22 ) RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -122,6 +122,11 @@
|
||||
"ordinal": 23,
|
||||
"name": "no_flow_overlap",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -146,7 +151,8 @@
|
||||
"Bool",
|
||||
"Jsonb",
|
||||
"Varchar",
|
||||
"Bool"
|
||||
"Bool",
|
||||
"Varchar"
|
||||
]
|
||||
},
|
||||
"nullable": [
|
||||
@@ -173,8 +179,9 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "6bb9e6cab7034bf28ef2597445dc617b60c49b42568fdb975cf2d2dc8702167e"
|
||||
"hash": "597335a4a1eda7799303e0d930b5468af2364f5d2075aab48787b93e5774336d"
|
||||
}
|
||||
+10
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"db_name": "PostgreSQL",
|
||||
"query": "UPDATE schedule SET schedule = $1, timezone = $2, args = $3, on_failure = $4, on_failure_times = $5, on_failure_exact = $6, on_failure_extra_args = $7, on_recovery = $8, on_recovery_times = $9, on_recovery_extra_args = $10, ws_error_handler_muted = $11, retry = $12, summary = $13, no_flow_overlap = $14 WHERE path = $15 AND workspace_id = $16 RETURNING *",
|
||||
"query": "UPDATE schedule SET schedule = $1, timezone = $2, args = $3, on_failure = $4, on_failure_times = $5, on_failure_exact = $6, on_failure_extra_args = $7, on_recovery = $8, on_recovery_times = $9, on_recovery_extra_args = $10, ws_error_handler_muted = $11, retry = $12, summary = $13, no_flow_overlap = $14, tag = $15\n WHERE path = $16 AND workspace_id = $17 RETURNING *",
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
@@ -122,6 +122,11 @@
|
||||
"ordinal": 23,
|
||||
"name": "no_flow_overlap",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -140,6 +145,7 @@
|
||||
"Jsonb",
|
||||
"Varchar",
|
||||
"Bool",
|
||||
"Varchar",
|
||||
"Text",
|
||||
"Text"
|
||||
]
|
||||
@@ -168,8 +174,9 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "b7ed211ec7611c994a49565e46e5893788bcf49b2c9357fbc45a8353a7c84f48"
|
||||
"hash": "90435687152ccd37db7e0a6a5baeb558db50f5f96b1e8eff0b10e4398566f325"
|
||||
}
|
||||
+7
-1
@@ -122,6 +122,11 @@
|
||||
"ordinal": 23,
|
||||
"name": "no_flow_overlap",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -155,7 +160,8 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "911b1e1f2a5ba6d5159916e5598020e680c45043b0736ad0153ee261a151dd90"
|
||||
|
||||
+7
-1
@@ -122,6 +122,11 @@
|
||||
"ordinal": 23,
|
||||
"name": "no_flow_overlap",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -156,7 +161,8 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "96dc1cd308f3c21cfb50b88048054dc03f93e261d25969d66aa48e9d0502960f"
|
||||
|
||||
+7
-1
@@ -122,6 +122,11 @@
|
||||
"ordinal": 23,
|
||||
"name": "no_flow_overlap",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -154,7 +159,8 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "aa2800113a8a8805f47cdc1dd0f29d94c546fe531e7edd3e91da4978af5442fb"
|
||||
|
||||
+7
-1
@@ -122,6 +122,11 @@
|
||||
"ordinal": 23,
|
||||
"name": "no_flow_overlap",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -155,7 +160,8 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "c10348d26e3e3dc9e345d9044db35db9906617eb9c98aaf58a55d9681ffb85e3"
|
||||
|
||||
+7
-1
@@ -122,6 +122,11 @@
|
||||
"ordinal": 23,
|
||||
"name": "no_flow_overlap",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -155,7 +160,8 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "dd74fa9468b5fe8c8ad657ded06076c11a78d0206af2af20685c691d4d9520bb"
|
||||
|
||||
+7
-1
@@ -122,6 +122,11 @@
|
||||
"ordinal": 23,
|
||||
"name": "no_flow_overlap",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -155,7 +160,8 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "eced0a09ba547ce1dccb54a5419b22373603c9d01f77047b3553bde125bf71e8"
|
||||
|
||||
+7
-1
@@ -122,6 +122,11 @@
|
||||
"ordinal": 23,
|
||||
"name": "no_flow_overlap",
|
||||
"type_info": "Bool"
|
||||
},
|
||||
{
|
||||
"ordinal": 24,
|
||||
"name": "tag",
|
||||
"type_info": "Varchar"
|
||||
}
|
||||
],
|
||||
"parameters": {
|
||||
@@ -153,7 +158,8 @@
|
||||
false,
|
||||
true,
|
||||
true,
|
||||
false
|
||||
false,
|
||||
true
|
||||
]
|
||||
},
|
||||
"hash": "fdd3710a381dac33ef5ee5ec5564a4874e6d7807d43fa6ea7b8408cad9e97480"
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Add down migration script here
|
||||
ALTER TABLE schedule DROP COLUMN tag;
|
||||
@@ -0,0 +1,2 @@
|
||||
-- Add up migration script here
|
||||
ALTER TABLE schedule ADD COLUMN tag VARCHAR(50);
|
||||
@@ -2873,7 +2873,7 @@ async fn test_script_schedule_handlers(db: Pool<Postgres>) {
|
||||
retry: None,
|
||||
no_flow_overlap: None,
|
||||
summary: None,
|
||||
|
||||
tag: None,
|
||||
};
|
||||
|
||||
let _ = client.create_schedule("test-workspace", &schedule).await;
|
||||
@@ -2936,7 +2936,8 @@ async fn test_script_schedule_handlers(db: Pool<Postgres>) {
|
||||
ws_error_handler_muted: None,
|
||||
retry: None,
|
||||
summary: None,
|
||||
no_flow_overlap: None
|
||||
no_flow_overlap: None,
|
||||
tag: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
@@ -3016,6 +3017,7 @@ async fn test_flow_schedule_handlers(db: Pool<Postgres>) {
|
||||
retry: None,
|
||||
no_flow_overlap: None,
|
||||
summary: None,
|
||||
tag: None,
|
||||
};
|
||||
|
||||
let _ = client.create_schedule("test-workspace", &schedule).await;
|
||||
@@ -3079,7 +3081,8 @@ async fn test_flow_schedule_handlers(db: Pool<Postgres>) {
|
||||
ws_error_handler_muted: None,
|
||||
retry: None,
|
||||
summary: None,
|
||||
no_flow_overlap: None
|
||||
no_flow_overlap: None,
|
||||
tag: None,
|
||||
},
|
||||
)
|
||||
.await
|
||||
|
||||
@@ -8250,6 +8250,8 @@ paths:
|
||||
type: boolean
|
||||
summary:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
required: &ref_148
|
||||
- path
|
||||
- schedule
|
||||
@@ -8319,6 +8321,8 @@ paths:
|
||||
type: boolean
|
||||
summary:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
required: &ref_150
|
||||
- schedule
|
||||
- timezone
|
||||
@@ -8464,6 +8468,8 @@ paths:
|
||||
type: string
|
||||
no_flow_overlap:
|
||||
type: boolean
|
||||
tag:
|
||||
type: string
|
||||
required: &ref_80
|
||||
- path
|
||||
- edited_by
|
||||
|
||||
@@ -8587,6 +8587,8 @@ components:
|
||||
type: string
|
||||
no_flow_overlap:
|
||||
type: boolean
|
||||
tag:
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
- edited_by
|
||||
@@ -8660,6 +8662,8 @@ components:
|
||||
type: boolean
|
||||
summary:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
- schedule
|
||||
@@ -8700,6 +8704,8 @@ components:
|
||||
type: boolean
|
||||
summary:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
required:
|
||||
- schedule
|
||||
- timezone
|
||||
|
||||
@@ -880,6 +880,7 @@ mod tests {
|
||||
)]
|
||||
.into(),
|
||||
hash: None,
|
||||
tag_override: None,
|
||||
},
|
||||
stop_after_if: None,
|
||||
summary: None,
|
||||
@@ -948,6 +949,7 @@ mod tests {
|
||||
path: "test".to_string(),
|
||||
input_transforms: HashMap::new(),
|
||||
hash: None,
|
||||
tag_override: None,
|
||||
},
|
||||
stop_after_if: Some(StopAfterIf {
|
||||
expr: "previous.isEmpty()".to_string(),
|
||||
@@ -983,7 +985,8 @@ mod tests {
|
||||
}
|
||||
},
|
||||
"type": "script",
|
||||
"path": "test"
|
||||
"path": "test",
|
||||
"tag_override": Option::<String>::None,
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1026,7 +1029,8 @@ mod tests {
|
||||
"value": {
|
||||
"input_transforms": {},
|
||||
"type": "script",
|
||||
"path": "test"
|
||||
"path": "test",
|
||||
"tag_override": Option::<String>::None,
|
||||
},
|
||||
"stop_after_if": {
|
||||
"expr": "previous.isEmpty()",
|
||||
|
||||
@@ -69,6 +69,7 @@ pub struct NewSchedule {
|
||||
pub on_recovery_extra_args: Option<serde_json::Value>,
|
||||
pub ws_error_handler_muted: Option<bool>,
|
||||
pub retry: Option<serde_json::Value>,
|
||||
pub tag: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
@@ -155,9 +156,9 @@ async fn create_schedule(
|
||||
"INSERT INTO schedule (workspace_id, path, schedule, timezone, edited_by, script_path, \
|
||||
is_flow, args, enabled, email, on_failure, on_failure_times, on_failure_exact, \
|
||||
on_failure_extra_args, on_recovery, on_recovery_times, on_recovery_extra_args, \
|
||||
ws_error_handler_muted, retry, summary, no_flow_overlap \
|
||||
ws_error_handler_muted, retry, summary, no_flow_overlap, tag \
|
||||
) VALUES ( \
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21 \
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22 \
|
||||
) RETURNING *",
|
||||
w_id,
|
||||
ns.path,
|
||||
@@ -180,6 +181,7 @@ async fn create_schedule(
|
||||
ns.retry,
|
||||
ns.summary,
|
||||
ns.no_flow_overlap.unwrap_or(false),
|
||||
ns.tag,
|
||||
)
|
||||
.fetch_one(&mut tx)
|
||||
.await
|
||||
@@ -233,8 +235,9 @@ async fn edit_schedule(
|
||||
Schedule,
|
||||
"UPDATE schedule SET schedule = $1, timezone = $2, args = $3, on_failure = $4, on_failure_times = $5, \
|
||||
on_failure_exact = $6, on_failure_extra_args = $7, on_recovery = $8, on_recovery_times = $9, \
|
||||
on_recovery_extra_args = $10, ws_error_handler_muted = $11, retry = $12, summary = $13, no_flow_overlap = $14 \
|
||||
WHERE path = $15 AND workspace_id = $16 RETURNING *",
|
||||
on_recovery_extra_args = $10, ws_error_handler_muted = $11, retry = $12, summary = $13, \
|
||||
no_flow_overlap = $14, tag = $15
|
||||
WHERE path = $16 AND workspace_id = $17 RETURNING *",
|
||||
es.schedule,
|
||||
es.timezone,
|
||||
es.args,
|
||||
@@ -249,6 +252,7 @@ async fn edit_schedule(
|
||||
es.retry,
|
||||
es.summary,
|
||||
es.no_flow_overlap.unwrap_or(false),
|
||||
es.tag,
|
||||
path,
|
||||
w_id,
|
||||
)
|
||||
@@ -344,6 +348,7 @@ pub struct ScheduleWJobs {
|
||||
pub jobs: Option<Vec<serde_json::Value>>,
|
||||
pub summary: Option<String>,
|
||||
pub no_flow_overlap: bool,
|
||||
pub tag: Option<String>,
|
||||
}
|
||||
|
||||
async fn list_schedule_with_jobs(
|
||||
@@ -692,6 +697,7 @@ pub struct EditSchedule {
|
||||
pub ws_error_handler_muted: Option<bool>,
|
||||
pub retry: Option<serde_json::Value>,
|
||||
pub no_flow_overlap: Option<bool>,
|
||||
pub tag: Option<String>,
|
||||
}
|
||||
|
||||
pub async fn clear_schedule<'c>(
|
||||
|
||||
@@ -292,6 +292,7 @@ pub enum FlowModuleValue {
|
||||
path: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
hash: Option<ScriptHash>,
|
||||
tag_override: Option<String>,
|
||||
},
|
||||
Flow {
|
||||
#[serde(default)]
|
||||
|
||||
@@ -317,6 +317,7 @@ pub enum JobPayload {
|
||||
concurrency_time_window_s: Option<i32>,
|
||||
cache_ttl: Option<i32>,
|
||||
priority: Option<i16>,
|
||||
tag_override: Option<String>,
|
||||
},
|
||||
DeploymentCallback {
|
||||
path: String,
|
||||
|
||||
@@ -39,6 +39,7 @@ pub struct Schedule {
|
||||
pub retry: Option<serde_json::Value>,
|
||||
pub no_flow_overlap: bool,
|
||||
pub summary: Option<String>,
|
||||
pub tag: Option<String>,
|
||||
}
|
||||
|
||||
impl Schedule {
|
||||
|
||||
@@ -1005,6 +1005,7 @@ pub async fn handle_maybe_scheduled_job<'c, R: rsmq_async::RsmqConnection + Clon
|
||||
retry: schedule.retry,
|
||||
summary: schedule.summary,
|
||||
no_flow_overlap: schedule.no_flow_overlap,
|
||||
tag: schedule.tag,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
@@ -2616,6 +2617,7 @@ pub async fn push<'c, T: Serialize + Send + Sync, R: rsmq_async::RsmqConnection
|
||||
concurrency_time_window_s,
|
||||
cache_ttl,
|
||||
priority,
|
||||
tag_override,
|
||||
} => {
|
||||
let mut input_transforms = HashMap::<String, InputTransform>::new();
|
||||
for (arg_name, arg_value) in args {
|
||||
@@ -2628,6 +2630,7 @@ pub async fn push<'c, T: Serialize + Send + Sync, R: rsmq_async::RsmqConnection
|
||||
input_transforms: input_transforms,
|
||||
path: path.clone(),
|
||||
hash: Some(hash),
|
||||
tag_override: tag_override,
|
||||
},
|
||||
stop_after_if: None,
|
||||
summary: None,
|
||||
|
||||
@@ -130,6 +130,7 @@ pub async fn push_scheduled_job<'c, R: rsmq_async::RsmqConnection + Send + 'c>(
|
||||
concurrency_time_window_s: concurrency_time_window_s,
|
||||
cache_ttl: cache_ttl,
|
||||
priority: priority,
|
||||
tag_override: schedule.tag.clone(),
|
||||
},
|
||||
Some("flow".to_string()),
|
||||
timeout,
|
||||
@@ -146,7 +147,7 @@ pub async fn push_scheduled_job<'c, R: rsmq_async::RsmqConnection + Send + 'c>(
|
||||
language,
|
||||
priority,
|
||||
},
|
||||
tag,
|
||||
schedule.tag.or(tag),
|
||||
timeout,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2310,8 +2310,10 @@ async fn compute_next_flow_transform(
|
||||
NextStatus::NextStep,
|
||||
))
|
||||
}
|
||||
FlowModuleValue::Script { path: script_path, hash: script_hash, .. } => {
|
||||
let payload = script_to_payload(script_hash, script_path, db, flow_job, module).await?;
|
||||
FlowModuleValue::Script { path: script_path, hash: script_hash, tag_override, .. } => {
|
||||
let payload =
|
||||
script_to_payload(script_hash, script_path, db, flow_job, module, tag_override)
|
||||
.await?;
|
||||
Ok(NextFlowTransform::Continue(
|
||||
ContinuePayload::SingleJob(payload),
|
||||
NextStatus::NextStep,
|
||||
@@ -2809,8 +2811,8 @@ async fn payload_from_simple_module(
|
||||
let delete_after_use = module.delete_after_use.unwrap_or(false);
|
||||
Ok(match value {
|
||||
FlowModuleValue::Flow { path, .. } => flow_to_payload(path, &delete_after_use),
|
||||
FlowModuleValue::Script { path: script_path, hash: script_hash, .. } => {
|
||||
script_to_payload(script_hash, script_path, db, flow_job, module).await?
|
||||
FlowModuleValue::Script { path: script_path, hash: script_hash, tag_override, .. } => {
|
||||
script_to_payload(script_hash, script_path, db, flow_job, module, tag_override).await?
|
||||
}
|
||||
FlowModuleValue::RawScript {
|
||||
path,
|
||||
@@ -2875,7 +2877,9 @@ async fn script_to_payload(
|
||||
db: &sqlx::Pool<sqlx::Postgres>,
|
||||
flow_job: &QueuedJob,
|
||||
module: &FlowModule,
|
||||
tag_override: &Option<String>,
|
||||
) -> Result<JobPayloadWithTag, Error> {
|
||||
tracing::warn!("Script tag override: {:?}", tag_override);
|
||||
let (payload, tag, delete_after_use, script_timeout) = if script_hash.is_none() {
|
||||
script_path_to_payload(script_path, &db, &flow_job.workspace_id).await?
|
||||
} else {
|
||||
@@ -2903,7 +2907,7 @@ async fn script_to_payload(
|
||||
dedicated_worker,
|
||||
priority,
|
||||
},
|
||||
tag,
|
||||
tag_override.to_owned().or(tag),
|
||||
delete_after_use,
|
||||
script_timeout,
|
||||
)
|
||||
|
||||
@@ -35,7 +35,7 @@ resource "aws_ecs_task_definition" "windmill_cluster_windmill_server_td" {
|
||||
value = "true"
|
||||
}, {
|
||||
name = "DATABASE_URL"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}?sslmode=disable"
|
||||
}, {
|
||||
name = "MODE"
|
||||
value = "server"
|
||||
|
||||
@@ -26,7 +26,7 @@ resource "aws_ecs_task_definition" "windmill_cluster_windmill_worker_td" {
|
||||
value = "true"
|
||||
}, {
|
||||
name = "DATABASE_URL"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}?sslmode=disable"
|
||||
}, {
|
||||
name = "MODE"
|
||||
value = "worker"
|
||||
|
||||
@@ -101,7 +101,7 @@ resource "aws_ecs_task_definition" "windmill_cluster_windmill_high_performance_w
|
||||
value = "true"
|
||||
}, {
|
||||
name = "DATABASE_URL"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}?sslmode=disable"
|
||||
}, {
|
||||
name = "MODE"
|
||||
value = "worker"
|
||||
|
||||
@@ -26,7 +26,7 @@ resource "aws_ecs_task_definition" "windmill_cluster_windmill_native_worker_td"
|
||||
value = "true"
|
||||
}, {
|
||||
name = "DATABASE_URL"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}"
|
||||
value = "postgres://${aws_db_instance.windmill_cluster_rds.username}:${aws_db_instance.windmill_cluster_rds.password}@${aws_db_instance.windmill_cluster_rds.endpoint}/${aws_db_instance.windmill_cluster_rds.db_name}?sslmode=disable"
|
||||
}, {
|
||||
name = "MODE"
|
||||
value = "worker"
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
let newTag: string = ''
|
||||
|
||||
export let customTags: string[] | undefined = undefined
|
||||
export let placement: 'bottom-end' | 'top-end' = 'bottom-end'
|
||||
|
||||
async function loadCustomTags() {
|
||||
try {
|
||||
@@ -26,7 +27,7 @@
|
||||
</script>
|
||||
|
||||
<Popup
|
||||
floatingConfig={{ strategy: 'absolute', placement: 'bottom-end' }}
|
||||
floatingConfig={{ strategy: 'absolute', placement: placement }}
|
||||
containerClasses="border rounded-lg shadow-lg p-4 bg-surface"
|
||||
>
|
||||
<svelte:fragment slot="button">
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
import Section from '$lib/components/Section.svelte'
|
||||
import { List, Save } from 'lucide-svelte'
|
||||
import FlowRetries from './flows/content/FlowRetries.svelte'
|
||||
import WorkerTagPicker from './WorkerTagPicker.svelte'
|
||||
|
||||
let optionTabSelected: 'error_handler' | 'recovery_handler' | 'retries' = 'error_handler'
|
||||
|
||||
@@ -144,6 +145,7 @@
|
||||
let pathError = ''
|
||||
let summary = ''
|
||||
let no_flow_overlap = false
|
||||
let tag: string | undefined = undefined
|
||||
|
||||
let validCRON = true
|
||||
$: allowSchedule = isValid && validCRON && script_path != ''
|
||||
@@ -271,6 +273,7 @@
|
||||
}
|
||||
args = s.args ?? {}
|
||||
can_write = canWrite(s.path, s.extra_perms, $userStore)
|
||||
tag = s.tag
|
||||
} catch (err) {
|
||||
sendUserToast(`Could not load schedule: ${err}`, true)
|
||||
}
|
||||
@@ -303,7 +306,8 @@
|
||||
ws_error_handler_muted: wsErrorHandlerMuted,
|
||||
retry: retry,
|
||||
summary: summary != '' ? summary : undefined,
|
||||
no_flow_overlap: no_flow_overlap
|
||||
no_flow_overlap: no_flow_overlap,
|
||||
tag: tag
|
||||
}
|
||||
})
|
||||
sendUserToast(`Schedule ${path} updated`)
|
||||
@@ -330,7 +334,8 @@
|
||||
ws_error_handler_muted: wsErrorHandlerMuted,
|
||||
retry: retry,
|
||||
summary: summary != '' ? summary : undefined,
|
||||
no_flow_overlap: no_flow_overlap
|
||||
no_flow_overlap: no_flow_overlap,
|
||||
tag: tag
|
||||
}
|
||||
})
|
||||
sendUserToast(`Schedule ${path} created`)
|
||||
@@ -533,12 +538,15 @@
|
||||
</div>
|
||||
</Section>
|
||||
|
||||
{#if !is_flow}{/if}
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<Tabs bind:selected={optionTabSelected}>
|
||||
<Tab value="error_handler">Error Handler</Tab>
|
||||
<Tab value="recovery_handler">Recovery Handler</Tab>
|
||||
{#if itemKind === 'script'}
|
||||
<Tab value="retries">Retries</Tab>
|
||||
<Tab value="tag">Custom tag</Tab>
|
||||
{/if}
|
||||
</Tabs>
|
||||
<div class="pt-0.5" />
|
||||
@@ -744,6 +752,13 @@
|
||||
</svelte:fragment>
|
||||
<FlowRetries bind:flowModuleRetry={retry} disabled={itemKind !== 'script'} />
|
||||
</Section>
|
||||
{:else if optionTabSelected === 'tag'}
|
||||
<Section
|
||||
label="Custom script tag"
|
||||
tooltip="When set, the script tag will be overridden by this tag"
|
||||
>
|
||||
<WorkerTagPicker bind:tag popupPlacement="top-end" />
|
||||
</Section>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
DraftService,
|
||||
NewScript,
|
||||
Script,
|
||||
ScriptService,
|
||||
WorkerService,
|
||||
type NewScriptWithDraft
|
||||
} from '$lib/gen'
|
||||
import { DraftService, NewScript, Script, ScriptService, type NewScriptWithDraft } from '$lib/gen'
|
||||
import { goto } from '$app/navigation'
|
||||
import { page } from '$app/stores'
|
||||
import { inferArgs } from '$lib/infer'
|
||||
import { initialCode } from '$lib/script_helpers'
|
||||
import { enterpriseLicense, userStore, workerTags, workspaceStore } from '$lib/stores'
|
||||
import { enterpriseLicense, userStore, workspaceStore } from '$lib/stores'
|
||||
import {
|
||||
cleanValueProperties,
|
||||
emptySchema,
|
||||
@@ -34,12 +27,9 @@
|
||||
CheckCircle,
|
||||
Code,
|
||||
DiffIcon,
|
||||
ExternalLink,
|
||||
Loader2,
|
||||
Pen,
|
||||
Plus,
|
||||
Rocket,
|
||||
RotateCw,
|
||||
Save,
|
||||
Settings,
|
||||
X
|
||||
@@ -59,7 +49,7 @@
|
||||
import type DiffDrawer from './DiffDrawer.svelte'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import type Editor from './Editor.svelte'
|
||||
import AssignableTags from './AssignableTags.svelte'
|
||||
import WorkerTagPicker from './WorkerTagPicker.svelte'
|
||||
|
||||
export let script: NewScript
|
||||
export let initialPath: string = ''
|
||||
@@ -81,14 +71,6 @@
|
||||
|
||||
const enterpriseLangs = ['bigquery', 'snowflake', 'mssql']
|
||||
|
||||
loadWorkerGroups()
|
||||
|
||||
async function loadWorkerGroups() {
|
||||
if (!$workerTags) {
|
||||
$workerTags = await WorkerService.getCustomTags()
|
||||
}
|
||||
}
|
||||
|
||||
export function setCode(code: string): void {
|
||||
editor?.setCode(code)
|
||||
}
|
||||
@@ -599,59 +581,7 @@
|
||||
group tag (queue). For instance, you could setup an "highmem", or "gpu" tag.
|
||||
</Tooltip>
|
||||
</svelte:fragment>
|
||||
<div class="flex gap-2 items-center">
|
||||
<div class="max-w-sm grow">
|
||||
{#if $workerTags}
|
||||
{#if $workerTags?.length > 0}
|
||||
<select
|
||||
bind:value={script.tag}
|
||||
on:change={(e) => {
|
||||
if (script.tag == '') {
|
||||
script.tag = undefined
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if script.tag}
|
||||
<option value="">reset to default</option>
|
||||
{:else}
|
||||
<option value="" disabled selected>Worker Group Tag</option>
|
||||
{/if}
|
||||
{#each $workerTags ?? [] as tag (tag)}
|
||||
<option value={tag}>{tag}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
<div class="text-sm text-secondary flex flex-row gap-2">
|
||||
No custom worker group tag defined on this instance in "Workers {'->'} Assignable
|
||||
Tags"
|
||||
<a
|
||||
href="https://www.windmill.dev/docs/core_concepts/worker_groups"
|
||||
target="_blank"
|
||||
class="hover:underline"
|
||||
>
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
See documentation
|
||||
<ExternalLink size="12" />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<Loader2 class="animate-spin" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="border"
|
||||
color="light"
|
||||
on:click={() => {
|
||||
$workerTags = undefined
|
||||
loadWorkerGroups()
|
||||
}}
|
||||
startIcon={{ icon: RotateCw }}
|
||||
/>
|
||||
<AssignableTags />
|
||||
</div>
|
||||
<WorkerTagPicker bind:tag={script.tag} />
|
||||
</Section>
|
||||
<Section label="Cache">
|
||||
<div class="flex gap-2 shrink flex-col">
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/common'
|
||||
import { ExternalLink, RotateCw, Loader2 } from 'lucide-svelte'
|
||||
import { workerTags } from '$lib/stores'
|
||||
import AssignableTags from './AssignableTags.svelte'
|
||||
import { WorkerService } from '$lib/gen'
|
||||
|
||||
export let tag: string | undefined
|
||||
export let popupPlacement: 'bottom-end' | 'top-end' = 'bottom-end'
|
||||
|
||||
loadWorkerGroups()
|
||||
async function loadWorkerGroups() {
|
||||
if (!$workerTags) {
|
||||
$workerTags = await WorkerService.getCustomTags()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex gap-2 items-center">
|
||||
<div class="max-w-sm grow">
|
||||
{#if workerTags}
|
||||
{#if $workerTags?.length ?? 0 > 0}
|
||||
<select
|
||||
bind:value={tag}
|
||||
on:change={(e) => {
|
||||
if (tag == '') {
|
||||
tag = undefined
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if tag}
|
||||
<option value="">reset to default</option>
|
||||
{:else}
|
||||
<option value="" disabled selected>Worker Group Tag</option>
|
||||
{/if}
|
||||
{#each $workerTags ?? [] as tag (tag)}
|
||||
<option value={tag}>{tag}</option>
|
||||
{/each}
|
||||
</select>
|
||||
{:else}
|
||||
<div class="text-sm text-secondary flex flex-row gap-2">
|
||||
No custom worker group tag defined on this instance in "Workers {'->'} Assignable Tags"
|
||||
<a
|
||||
href="https://www.windmill.dev/docs/core_concepts/worker_groups"
|
||||
target="_blank"
|
||||
class="hover:underline"
|
||||
>
|
||||
<div class="flex flex-row gap-2 items-center">
|
||||
See documentation
|
||||
<ExternalLink size="12" />
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<Loader2 class="animate-spin" />
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<Button
|
||||
variant="border"
|
||||
color="light"
|
||||
on:click={() => {
|
||||
$workerTags = undefined
|
||||
loadWorkerGroups()
|
||||
}}
|
||||
startIcon={{ icon: RotateCw }}
|
||||
/>
|
||||
<AssignableTags placement={popupPlacement} />
|
||||
</div>
|
||||
@@ -17,34 +17,26 @@
|
||||
import { isCloudHosted } from '$lib/cloud'
|
||||
import { copyToClipboard } from '$lib/utils'
|
||||
import Tooltip from '$lib/components/Tooltip.svelte'
|
||||
import { WorkerService } from '$lib/gen'
|
||||
import { AlertTriangle, Clipboard, Loader2, RotateCw } from 'lucide-svelte'
|
||||
import { AlertTriangle, Clipboard } from 'lucide-svelte'
|
||||
import SimpleEditor from '$lib/components/SimpleEditor.svelte'
|
||||
import { schemaToObject } from '$lib/schema'
|
||||
import type { Schema } from '$lib/common'
|
||||
import Section from '$lib/components/Section.svelte'
|
||||
import Label from '$lib/components/Label.svelte'
|
||||
import ErrorHandlerToggleButton from '$lib/components/details/ErrorHandlerToggleButton.svelte'
|
||||
import AssignableTags from '$lib/components/AssignableTags.svelte'
|
||||
import WorkerTagPicker from '$lib/components/WorkerTagPicker.svelte'
|
||||
|
||||
export let noEditor: boolean
|
||||
|
||||
const { selectedId, flowStore, initialPath, previewArgs, pathStore } =
|
||||
getContext<FlowEditorContext>('FlowEditorContext')
|
||||
|
||||
async function loadWorkerGroups() {
|
||||
if (!$workerTags) {
|
||||
$workerTags = await WorkerService.getCustomTags()
|
||||
}
|
||||
}
|
||||
|
||||
let hostname = BROWSER ? window.location.protocol + '//' + window.location.host : 'SSR'
|
||||
$: url = `${hostname}/api/w/${$workspaceStore}/jobs/run/f/${$pathStore}`
|
||||
$: syncedUrl = `${hostname}/api/w/${$workspaceStore}/jobs/run_wait_result/f/${$pathStore}`
|
||||
|
||||
$: if ($selectedId == 'settings-worker-group') {
|
||||
$workerTags = undefined
|
||||
loadWorkerGroups()
|
||||
}
|
||||
|
||||
function asSchema(x: any) {
|
||||
@@ -327,54 +319,7 @@
|
||||
'flow' and the steps will be executed with their respective tag
|
||||
</Alert>
|
||||
<span class="my-4 text-lg font-bold">Worker Group Tag (Queue)</span>
|
||||
<div class="flex gap-2 items-center">
|
||||
{#if $workerTags}
|
||||
{#if $workerTags?.length > 0}
|
||||
<div class="max-w-sm grow">
|
||||
<select
|
||||
placeholder="Worker group tag"
|
||||
bind:value={$flowStore.tag}
|
||||
on:change={(e) => {
|
||||
if ($flowStore.tag == '') {
|
||||
$flowStore.tag = undefined
|
||||
}
|
||||
}}
|
||||
>
|
||||
{#if $flowStore.tag}
|
||||
<option value="">reset to default</option>
|
||||
{:else}
|
||||
<option value="" disabled selected>Worker Group Tag</option>
|
||||
{/if}
|
||||
{#each $workerTags ?? [] as tag (tag)}
|
||||
<option value={tag}>{tag}</option>
|
||||
{/each}
|
||||
</select>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-sm text-secondary italic mb-2">
|
||||
No custom worker group tag defined on this instance in "Workers {'->'} Assignable
|
||||
Tags". See
|
||||
<a
|
||||
href="https://www.windmill.dev/docs/core_concepts/worker_groups"
|
||||
target="_blank">documentation</a
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<Loader2 class="animate-spin" />
|
||||
{/if}
|
||||
|
||||
<Button
|
||||
variant="border"
|
||||
color="light"
|
||||
on:click={() => {
|
||||
$workerTags = undefined
|
||||
loadWorkerGroups()
|
||||
}}
|
||||
startIcon={{ icon: RotateCw }}
|
||||
/>
|
||||
<AssignableTags />
|
||||
</div>
|
||||
<WorkerTagPicker bind:tag={$flowStore.tag} />
|
||||
|
||||
<div class="py-6" />
|
||||
<span class="my-4 text-lg font-bold flex items-baseline gap-8"
|
||||
|
||||
Reference in New Issue
Block a user