Skip to content

Commit ad43680

Browse files
authored
fix: dep jobs improvements (#7081)
* dep jobs improvements * update
1 parent 10e621c commit ad43680

File tree

7 files changed

+63
-53
lines changed

7 files changed

+63
-53
lines changed

backend/windmill-common/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ pub mod job_metrics;
5353
pub mod job_s3_helpers_ee;
5454
#[cfg(feature = "parquet")]
5555
pub mod job_s3_helpers_oss;
56+
pub mod lockfiles;
5657

5758
#[cfg(feature = "private")]
5859
pub mod git_sync_ee;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use crate::scripts::ScriptLang;
2+
3+
pub const LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT: &str = "# from requirements.txt";
4+
5+
pub fn is_generated_from_raw_requirements(
6+
lang: &Option<ScriptLang>,
7+
lock: &Option<String>,
8+
) -> bool {
9+
(lang.is_some_and(|v| v == ScriptLang::Bun)
10+
&& lock
11+
.as_ref()
12+
.is_some_and(|v| v.contains("generatedFromPackageJson")))
13+
|| (lang.is_some_and(|v| v == ScriptLang::Python3)
14+
&& lock
15+
.as_ref()
16+
.is_some_and(|v| v.starts_with(LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT)))
17+
}

backend/windmill-common/src/scripts.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -732,18 +732,32 @@ pub fn hash_script(ns: &NewScript) -> i64 {
732732
dh.finish() as i64
733733
}
734734

735+
pub struct ClonedScript {
736+
pub old_script: NewScript,
737+
pub new_hash: i64,
738+
}
735739
pub async fn clone_script<'c>(
736740
base_hash: ScriptHash,
737741
w_id: &str,
738742
deployment_message: Option<String>,
739743
tx: &mut sqlx::Transaction<'c, sqlx::Postgres>,
740-
) -> crate::error::Result<i64> {
741-
let s =
742-
sqlx::query_as::<_, Script>("SELECT * FROM script WHERE hash = $1 AND workspace_id = $2")
743-
.bind(base_hash.0)
744-
.bind(w_id)
745-
.fetch_one(&mut **tx)
746-
.await?;
744+
) -> crate::error::Result<ClonedScript> {
745+
let s = sqlx::query_as::<_, Script>(
746+
"SELECT * FROM script WHERE hash = $1 AND workspace_id = $2 AND archived = false FOR UPDATE",
747+
)
748+
.bind(base_hash.0)
749+
.bind(w_id)
750+
.fetch_optional(&mut **tx)
751+
.await?;
752+
753+
let s = if let Some(s) = s {
754+
s
755+
} else {
756+
return Err(crate::error::Error::NotFound(format!(
757+
"Non-archived script with hash {} not found",
758+
base_hash.0
759+
)));
760+
};
747761

748762
let ns = NewScript {
749763
path: s.path.clone(),
@@ -819,5 +833,5 @@ pub async fn clone_script<'c>(
819833
.execute(&mut **tx)
820834
.await?;
821835

822-
Ok(new_hash)
836+
Ok(ClonedScript { old_script: ns, new_hash })
823837
}

backend/windmill-queue/src/jobs.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ use windmill_common::add_time;
3535
use windmill_common::auth::JobPerms;
3636
#[cfg(feature = "benchmark")]
3737
use windmill_common::bench::BenchmarkIter;
38+
use windmill_common::lockfiles::is_generated_from_raw_requirements;
3839
use windmill_common::jobs::{JobTriggerKind, EMAIL_ERROR_HANDLER_USER_EMAIL};
3940
use windmill_common::utils::{configure_client, now_from_db};
4041
use windmill_common::worker::{Connection, MIN_VERSION_SUPPORTS_DEBOUNCING, SCRIPT_TOKEN_EXPIRY};
@@ -5660,15 +5661,20 @@ pub async fn preprocess_dependency_job(job: &mut PulledJob, db: &DB) -> error::R
56605661
args.insert("base_hash".to_owned(), to_raw_value(&*base_hash))
56615662
});
56625663

5663-
let new_hash = windmill_common::scripts::clone_script(
5664+
let cloned_script = windmill_common::scripts::clone_script(
56645665
base_hash,
56655666
&job.workspace_id,
56665667
deployment_message,
56675668
&mut tx,
56685669
)
56695670
.await?;
5670-
5671-
new_hash
5671+
if is_generated_from_raw_requirements(&Some(cloned_script.old_script.language), &cloned_script.old_script.lock.map(|v| v.to_string())) {
5672+
return Err(Error::BadRequest(format!(
5673+
"Script at path {} is generated from raw requirements, not overriding",
5674+
job.runnable_path()
5675+
)));
5676+
}
5677+
cloned_script.new_hash
56725678
}
56735679
JobKind::FlowDependencies => {
56745680
sqlx::query_scalar!(

backend/windmill-worker/src/python_versions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use tokio::{fs::DirBuilder, process::Command, sync::RwLock};
1212
use uuid::Uuid;
1313
use windmill_common::{
1414
error::{self, Error},
15+
lockfiles::LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT,
1516
worker::Connection,
1617
};
1718

@@ -22,7 +23,6 @@ use crate::{
2223
common::{start_child_process, OccupancyMetrics},
2324
handle_child::handle_child,
2425
python_executor::{PYTHON_PATH, UV_PATH},
25-
worker_lockfiles::LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT,
2626
HOME_ENV, INSTANCE_PYTHON_VERSION, PATH_ENV, PROXY_ENVS, PY_INSTALL_DIR, WIN_ENVS,
2727
};
2828

backend/windmill-worker/src/scoped_dependency_map.rs

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,12 @@ use windmill_common::{
55
cache,
66
error::{Error, Result},
77
flows::{FlowModuleValue, FlowValue},
8-
scripts::ScriptLang,
98
};
109

1110
use std::collections::HashSet;
1211

13-
use crate::worker_lockfiles::{
14-
extract_relative_imports, is_generated_from_raw_requirements,
15-
LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT,
16-
};
12+
use crate::worker_lockfiles::extract_relative_imports;
13+
use windmill_common::lockfiles::is_generated_from_raw_requirements;
1714

1815
// TODO: To be removed in future versions
1916
lazy_static::lazy_static! {
@@ -295,16 +292,7 @@ SELECT importer_node_id, imported_path
295292
let mut dmap = ScopedDependencyMap::fetch(w_id, &r.path, "script", db).await?;
296293
let mut tx = db.begin().await?;
297294

298-
if (smd.language.is_some_and(|v| v == ScriptLang::Bun)
299-
&& sd
300-
.lock
301-
.as_ref()
302-
.is_some_and(|v| v.contains("generatedFromPackageJson")))
303-
|| (smd.language.is_some_and(|v| v == ScriptLang::Python3)
304-
&& sd.lock.as_ref().is_some_and(|v| {
305-
v.starts_with(LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT)
306-
}))
307-
{
295+
if is_generated_from_raw_requirements(&smd.language, &sd.lock) {
308296
// if the lock file is generated from a package.json/requirements.txt, we need to clear the dependency map
309297
// because we do not want to have dependencies be recomputed automatically. Empty relative imports passed
310298
// to update_script_dependency_map will clear the dependency map.
@@ -350,7 +338,7 @@ SELECT importer_node_id, imported_path
350338
match fmv {
351339
// Since we fetched from flow_version it is safe to assume all inline scripts are in form of RawScript.
352340
FlowModuleValue::RawScript { content, language, lock ,.. } => {
353-
if !is_generated_from_raw_requirements(Some(*language), lock) {
341+
if !is_generated_from_raw_requirements(&Some(*language), lock) {
354342
to_process.push((
355343
extract_relative_imports(
356344
content,

backend/windmill-worker/src/worker_lockfiles.rs

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use windmill_common::error::Error;
2020
use windmill_common::error::Result;
2121
use windmill_common::flows::{FlowModule, FlowModuleValue, FlowNodeId};
2222
use windmill_common::jobs::JobPayload;
23+
use windmill_common::lockfiles::is_generated_from_raw_requirements;
2324
use windmill_common::scripts::ScriptHash;
2425
use windmill_common::utils::WarnAfterExt;
2526
#[cfg(feature = "python")]
@@ -373,15 +374,7 @@ pub async fn process_relative_imports(
373374
db,
374375
)
375376
.await?;
376-
if (script_lang.is_some_and(|v| v == ScriptLang::Bun)
377-
&& lock
378-
.as_ref()
379-
.is_some_and(|v| v.contains("generatedFromPackageJson")))
380-
|| (script_lang.is_some_and(|v| v == ScriptLang::Python3)
381-
&& lock
382-
.as_ref()
383-
.is_some_and(|v| v.starts_with(LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT)))
384-
{
377+
if is_generated_from_raw_requirements(script_lang, &lock) {
385378
// if the lock file is generated from a package.json/requirements.txt, we need to clear the dependency map
386379
// because we do not want to have dependencies be recomputed automatically. Empty relative imports passed
387380
// to update_script_dependency_map will clear the dependency map.
@@ -445,17 +438,6 @@ pub async fn process_relative_imports(
445438
Ok(())
446439
}
447440

448-
pub fn is_generated_from_raw_requirements(lang: Option<ScriptLang>, lock: &Option<String>) -> bool {
449-
(lang.is_some_and(|v| v == ScriptLang::Bun)
450-
&& lock
451-
.as_ref()
452-
.is_some_and(|v| v.contains("generatedFromPackageJson")))
453-
|| (lang.is_some_and(|v| v == ScriptLang::Python3)
454-
&& lock
455-
.as_ref()
456-
.is_some_and(|v| v.starts_with(LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT)))
457-
}
458-
459441
pub async fn trigger_dependents_to_recompute_dependencies(
460442
w_id: &str,
461443
script_path: &str,
@@ -1450,7 +1432,7 @@ async fn lock_modules<'c>(
14501432

14511433
if let Some(locks_to_reload) = locks_to_reload {
14521434
if !locks_to_reload.contains(&e.id) {
1453-
if !is_generated_from_raw_requirements(Some(language), &lock) {
1435+
if !is_generated_from_raw_requirements(&Some(language), &lock) {
14541436
let relative_imports = get_imports();
14551437
tx = dependency_map
14561438
.patch(relative_imports.clone(), e.id.clone(), tx)
@@ -1463,7 +1445,7 @@ async fn lock_modules<'c>(
14631445
if lock.as_ref().is_some_and(|x| !x.trim().is_empty()) {
14641446
let skip_creating_new_lock = skip_creating_new_lock(&language, &content);
14651447
if skip_creating_new_lock {
1466-
if !is_generated_from_raw_requirements(Some(language), &lock) {
1448+
if !is_generated_from_raw_requirements(&Some(language), &lock) {
14671449
let relative_imports = get_imports();
14681450
tx = dependency_map
14691451
.patch(relative_imports.clone(), e.id.clone(), tx)
@@ -2582,8 +2564,6 @@ async fn ansible_dep(
25822564
serde_json::to_string(&ansible_lockfile).map_err(|e| e.into())
25832565
}
25842566

2585-
pub const LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT: &str = "# from requirements.txt";
2586-
25872567
async fn capture_dependency_job(
25882568
job_id: &Uuid,
25892569
job_language: &ScriptLang,
@@ -2672,7 +2652,11 @@ async fn capture_dependency_job(
26722652
.await
26732653
.map(|res| {
26742654
if raw_deps {
2675-
format!("{}\n{}", LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT, res)
2655+
format!(
2656+
"{}\n{}",
2657+
windmill_common::lockfiles::LOCKFILE_GENERATED_FROM_REQUIREMENTS_TXT,
2658+
res
2659+
)
26762660
} else {
26772661
res
26782662
}

0 commit comments

Comments
 (0)