diff --git a/.env b/.env index d4a48661cd927..da41f78d5cddb 100644 --- a/.env +++ b/.env @@ -7,3 +7,7 @@ WM_IMAGE=ghcr.io/windmill-labs/windmill:main # To use another port than :80, setup the Caddyfile and the caddy section of the docker-compose to your needs: https://caddyserver.com/docs/getting-started # To have caddy take care of automatic TLS + +# To rotate logs, set the following variables: +#LOG_MAX_SIZE=10m +#LOG_MAX_FILE=3 diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index f95dee00daa0c..b48ad1c990be3 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -162,6 +162,7 @@ jobs: -c https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/suite_config.json --workers 4 + --factor 3 - name: Save benchmark results uses: actions/upload-artifact@v4 with: @@ -281,6 +282,7 @@ jobs: -c https://raw.githubusercontent.com/windmill-labs/windmill/${GITHUB_REF##ref/head/}/benchmarks/suite_config.json --workers 8 + --factor 3 - name: Save benchmark results uses: actions/upload-artifact@v4 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index a535cc09f7d5e..d87d723777e5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,67 @@ # Changelog +## [1.463.6](https://github.com/windmill-labs/windmill/compare/v1.463.5...v1.463.6) (2025-02-18) + + +### Bug Fixes + +* fix reactivity issue on loading live flow on runs page ([52e12d1](https://github.com/windmill-labs/windmill/commit/52e12d1021831adc2ce9b7b0946a93562038017e)) +* improve v2 migration finalizer to avoid deadlocks ([1069ad3](https://github.com/windmill-labs/windmill/commit/1069ad39992940e32e5d8566ef2283970525be1a)) + +## [1.463.5](https://github.com/windmill-labs/windmill/compare/v1.463.4...v1.463.5) (2025-02-18) + + +### Bug Fixes + +* fix teams cleanup preventing start ([1b46e0f](https://github.com/windmill-labs/windmill/commit/1b46e0f08426497d549cf5007c93981df9ab41e5)) + + +## [1.463.4](https://github.com/windmill-labs/windmill/compare/v1.463.3...v1.463.4) (2025-02-17) + + +### Bug Fixes + +* improve queue job indices for faster performances ([9530826](https://github.com/windmill-labs/windmill/commit/953082681e2c4fd71d5ac1acf372265ccc72297b)) +* improve teams settings in workspace settings ([#5316](https://github.com/windmill-labs/windmill/issues/5316)) ([935b5b7](https://github.com/windmill-labs/windmill/commit/935b5b799636c0f02597315837268d4a76f6709a)) + +## [1.463.3](https://github.com/windmill-labs/windmill/compare/v1.463.2...v1.463.3) (2025-02-17) + + +### Bug Fixes + +* windmill_admin has implicit bypass rls on v2_job even if role not set ([0208f53](https://github.com/windmill-labs/windmill/commit/0208f53541473aa51bed0e15d938def3d4530e3f)) + +## [1.463.2](https://github.com/windmill-labs/windmill/compare/v1.463.1...v1.463.2) (2025-02-16) + + +### Bug Fixes + +* show skipped flows as success ([#5304](https://github.com/windmill-labs/windmill/issues/5304)) ([062e6bc](https://github.com/windmill-labs/windmill/commit/062e6bc161b56215cb081209d37ad8e0cbd1dd99)) + +## [1.463.1](https://github.com/windmill-labs/windmill/compare/v1.463.0...v1.463.1) (2025-02-15) + + +### Bug Fixes + +* not able to filter runs by schedule ([#5302](https://github.com/windmill-labs/windmill/issues/5302)) ([53f47bc](https://github.com/windmill-labs/windmill/commit/53f47bcfc84ed747b55d3a7d84ccf13ff1c43c97)) + +## [1.463.0](https://github.com/windmill-labs/windmill/compare/v1.462.1...v1.463.0) (2025-02-14) + + +### Features + +* adding docker log rotation by default in docker compose ([#5295](https://github.com/windmill-labs/windmill/issues/5295)) ([dad829a](https://github.com/windmill-labs/windmill/commit/dad829adf4bff97e998f7d18e0bbafb8497d4198)) +* parse script for preprocessor/no_main_func on deploy ([#5292](https://github.com/windmill-labs/windmill/issues/5292)) ([28558e6](https://github.com/windmill-labs/windmill/commit/28558e674f60fef1b165a79c039b1b450759d500)) + + +### Bug Fixes + +* display branch chosen even if emoty branch ([77a8eed](https://github.com/windmill-labs/windmill/commit/77a8eedc96171e9f84463407bdc5aec9b7b10d62)) +* improve handling of empty branches and loops ([e7d4582](https://github.com/windmill-labs/windmill/commit/e7d458278969897aa7312dcd20a8091aaad772d7)) +* improve runs page load time ([266f820](https://github.com/windmill-labs/windmill/commit/266f82046ad287163d24910902393cd63156ca1d)) +* static website serving ([#5298](https://github.com/windmill-labs/windmill/issues/5298)) ([41eecc1](https://github.com/windmill-labs/windmill/commit/41eecc1437301bea557fb467cc48b502162de419)) +* users should be able to see their own jobs ([9ccadb6](https://github.com/windmill-labs/windmill/commit/9ccadb6085498119bdfcc172d52c7fce1eb3336e)) + ## [1.462.3](https://github.com/windmill-labs/windmill/compare/v1.462.1...v1.462.2) (2025-02-14) diff --git a/backend/.sqlx/query-08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7.json b/backend/.sqlx/query-08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7.json index 4bcf3c6ce3cf3..2be39fce267e6 100644 --- a/backend/.sqlx/query-08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7.json +++ b/backend/.sqlx/query-08f288d2781d823e109a9e5b8848234ca7d1efeee9661f3901f298da375e73f7.json @@ -130,28 +130,28 @@ }, { "ordinal": 25, - "name": "ai_models", - "type_info": "VarcharArray" + "name": "teams_command_script", + "type_info": "Text" }, { "ordinal": 26, - "name": "code_completion_model", - "type_info": "Varchar" + "name": "teams_team_id", + "type_info": "Text" }, { "ordinal": 27, - "name": "teams_command_script", + "name": "teams_team_name", "type_info": "Text" }, { "ordinal": 28, - "name": "teams_team_id", - "type_info": "Text" + "name": "ai_models", + "type_info": "VarcharArray" }, { "ordinal": 29, - "name": "teams_team_name", - "type_info": "Text" + "name": "code_completion_model", + "type_info": "Varchar" } ], "parameters": { @@ -185,10 +185,10 @@ true, true, true, - false, true, true, true, + false, true ] }, diff --git a/backend/.sqlx/query-19cc8499f682ec34d54bc4f694cb281a9bd7f5431c646c6268513751fff95395.json b/backend/.sqlx/query-0cb0e912bc942af2b1ef784455f3f073a79e300f3dd48f14122d1782eee663cd.json similarity index 72% rename from backend/.sqlx/query-19cc8499f682ec34d54bc4f694cb281a9bd7f5431c646c6268513751fff95395.json rename to backend/.sqlx/query-0cb0e912bc942af2b1ef784455f3f073a79e300f3dd48f14122d1782eee663cd.json index 0c379a7bdb028..0a9e91b206ac2 100644 --- a/backend/.sqlx/query-19cc8499f682ec34d54bc4f694cb281a9bd7f5431c646c6268513751fff95395.json +++ b/backend/.sqlx/query-0cb0e912bc942af2b1ef784455f3f073a79e300f3dd48f14122d1782eee663cd.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM v2_as_queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now()", + "query": "SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM v2_as_queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now() AND ($3::text[] IS NULL OR tag = ANY($3))", "describe": { "columns": [ { @@ -17,7 +17,8 @@ "parameters": { "Left": [ "Text", - "Bool" + "Bool", + "TextArray" ] }, "nullable": [ @@ -25,5 +26,5 @@ null ] }, - "hash": "19cc8499f682ec34d54bc4f694cb281a9bd7f5431c646c6268513751fff95395" + "hash": "0cb0e912bc942af2b1ef784455f3f073a79e300f3dd48f14122d1782eee663cd" } diff --git a/backend/.sqlx/query-0efb16cbf130ec6e9922ecc82a95b252449bd569df374e40ce8820fc3d75a0f0.json b/backend/.sqlx/query-0efb16cbf130ec6e9922ecc82a95b252449bd569df374e40ce8820fc3d75a0f0.json new file mode 100644 index 0000000000000..2f17b5e8db1f3 --- /dev/null +++ b/backend/.sqlx/query-0efb16cbf130ec6e9922ecc82a95b252449bd569df374e40ce8820fc3d75a0f0.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DROP INDEX CONCURRENTLY IF EXISTS queue_sort", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "0efb16cbf130ec6e9922ecc82a95b252449bd569df374e40ce8820fc3d75a0f0" +} diff --git a/backend/.sqlx/query-2fa27b0a71740e4e168879cf9a58ed593004c22bb5d11170b3196e290dd1d966.json b/backend/.sqlx/query-2fa27b0a71740e4e168879cf9a58ed593004c22bb5d11170b3196e290dd1d966.json deleted file mode 100644 index 704778d04a6b9..0000000000000 --- a/backend/.sqlx/query-2fa27b0a71740e4e168879cf9a58ed593004c22bb5d11170b3196e290dd1d966.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "\n WITH assigned_teams AS (\n SELECT teams_team_id\n FROM workspace_settings\n ),\n all_teams AS (\n SELECT jsonb_array_elements(value::jsonb) AS team\n FROM global_settings\n WHERE name = 'teams'\n )\n SELECT team->>'team_name' AS team_name, team->>'team_internal_id' AS team_id\n FROM all_teams\n WHERE NOT EXISTS (\n SELECT 1\n FROM assigned_teams\n WHERE assigned_teams.teams_team_id = team->>'team_internal_id'\n )\n AND team->>'team_name' IS NOT NULL\n AND team->>'team_id' IS NOT NULL\n ", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "team_name", - "type_info": "Text" - }, - { - "ordinal": 1, - "name": "team_id", - "type_info": "Text" - } - ], - "parameters": { - "Left": [] - }, - "nullable": [ - null, - null - ] - }, - "hash": "2fa27b0a71740e4e168879cf9a58ed593004c22bb5d11170b3196e290dd1d966" -} diff --git a/backend/.sqlx/query-3738096c29ab9d964be8a74bfd14ff1d599049ebefdaf97a017c9cef8d52ce20.json b/backend/.sqlx/query-3738096c29ab9d964be8a74bfd14ff1d599049ebefdaf97a017c9cef8d52ce20.json new file mode 100644 index 0000000000000..d804949078af9 --- /dev/null +++ b/backend/.sqlx/query-3738096c29ab9d964be8a74bfd14ff1d599049ebefdaf97a017c9cef8d52ce20.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DROP INDEX CONCURRENTLY IF EXISTS queue_sort_2", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "3738096c29ab9d964be8a74bfd14ff1d599049ebefdaf97a017c9cef8d52ce20" +} diff --git a/backend/.sqlx/query-3bacf9cd9aa63f4bec5f983f4a0c3030216b5a4ed669f77962509d1c2c6cb780.json b/backend/.sqlx/query-3bacf9cd9aa63f4bec5f983f4a0c3030216b5a4ed669f77962509d1c2c6cb780.json deleted file mode 100644 index 200a5bf47f728..0000000000000 --- a/backend/.sqlx/query-3bacf9cd9aa63f4bec5f983f4a0c3030216b5a4ed669f77962509d1c2c6cb780.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "create index concurrently if not exists root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL", - "describe": { - "columns": [], - "parameters": { - "Left": [] - }, - "nullable": [] - }, - "hash": "3bacf9cd9aa63f4bec5f983f4a0c3030216b5a4ed669f77962509d1c2c6cb780" -} diff --git a/backend/.sqlx/query-3bbde0fa35d935ec2dd8bd1fb14cfecf48305f5f4b644b3c35355074e1ccce28.json b/backend/.sqlx/query-3bbde0fa35d935ec2dd8bd1fb14cfecf48305f5f4b644b3c35355074e1ccce28.json new file mode 100644 index 0000000000000..815f1fed70ad9 --- /dev/null +++ b/backend/.sqlx/query-3bbde0fa35d935ec2dd8bd1fb14cfecf48305f5f4b644b3c35355074e1ccce28.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "CREATE INDEX CONCURRENTLY queue_sort_v2 ON v2_job_queue (priority DESC NULLS LAST, scheduled_for, tag) WHERE running = false", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "3bbde0fa35d935ec2dd8bd1fb14cfecf48305f5f4b644b3c35355074e1ccce28" +} diff --git a/backend/.sqlx/query-47455b0ebaf999ab58b2cba3d74cb4bdd64075939a4aa2c117e18372511ea7e0.json b/backend/.sqlx/query-47455b0ebaf999ab58b2cba3d74cb4bdd64075939a4aa2c117e18372511ea7e0.json deleted file mode 100644 index 6ccaeece1ce0f..0000000000000 --- a/backend/.sqlx/query-47455b0ebaf999ab58b2cba3d74cb4bdd64075939a4aa2c117e18372511ea7e0.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "VACUUM (skip_locked) v2_job_queue, v2_job_runtime, v2_job_status", - "describe": { - "columns": [], - "parameters": { - "Left": [] - }, - "nullable": [] - }, - "hash": "47455b0ebaf999ab58b2cba3d74cb4bdd64075939a4aa2c117e18372511ea7e0" -} diff --git a/backend/.sqlx/query-4d4aa16b2a55e57f9376d0cb253e671525969fb5f528ae07576e9dc5e77af1f1.json b/backend/.sqlx/query-4d4aa16b2a55e57f9376d0cb253e671525969fb5f528ae07576e9dc5e77af1f1.json new file mode 100644 index 0000000000000..3dea4439541b5 --- /dev/null +++ b/backend/.sqlx/query-4d4aa16b2a55e57f9376d0cb253e671525969fb5f528ae07576e9dc5e77af1f1.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DROP INDEX CONCURRENTLY IF EXISTS ix_job_workspace_id_created_at_new_7", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "4d4aa16b2a55e57f9376d0cb253e671525969fb5f528ae07576e9dc5e77af1f1" +} diff --git a/backend/.sqlx/query-50c17c7848760aaf0f869acfc444caecda6335eda5b2e97e5a7370361653ff48.json b/backend/.sqlx/query-50c17c7848760aaf0f869acfc444caecda6335eda5b2e97e5a7370361653ff48.json new file mode 100644 index 0000000000000..f3dc15325474d --- /dev/null +++ b/backend/.sqlx/query-50c17c7848760aaf0f869acfc444caecda6335eda5b2e97e5a7370361653ff48.json @@ -0,0 +1,26 @@ +{ + "db_name": "PostgreSQL", + "query": "\n WITH assigned_teams AS (\n SELECT teams_team_id\n FROM workspace_settings\n ),\n all_teams AS (\n SELECT jsonb_array_elements(CASE\n WHEN jsonb_typeof(value::jsonb) = 'array' THEN value::jsonb\n ELSE '[]'::jsonb\n END) AS team\n FROM global_settings\n WHERE name = 'teams'\n )\n SELECT team->>'team_name' AS team_name, team->>'team_internal_id' AS team_id\n FROM all_teams\n WHERE NOT EXISTS (\n SELECT 1\n FROM assigned_teams\n WHERE assigned_teams.teams_team_id = team->>'team_internal_id'\n )\n AND team->>'team_name' IS NOT NULL\n AND team->>'team_id' IS NOT NULL\n ", + "describe": { + "columns": [ + { + "ordinal": 0, + "name": "team_name", + "type_info": "Text" + }, + { + "ordinal": 1, + "name": "team_id", + "type_info": "Text" + } + ], + "parameters": { + "Left": [] + }, + "nullable": [ + null, + null + ] + }, + "hash": "50c17c7848760aaf0f869acfc444caecda6335eda5b2e97e5a7370361653ff48" +} diff --git a/backend/.sqlx/query-55cb03040bc2a8c53dd7fbb42bbdcc40f463cbc52d94ed9315cf9a547d4c89f2.json b/backend/.sqlx/query-55cb03040bc2a8c53dd7fbb42bbdcc40f463cbc52d94ed9315cf9a547d4c89f2.json index 14685a8bfa6ec..9243288c9d321 100644 --- a/backend/.sqlx/query-55cb03040bc2a8c53dd7fbb42bbdcc40f463cbc52d94ed9315cf9a547d4c89f2.json +++ b/backend/.sqlx/query-55cb03040bc2a8c53dd7fbb42bbdcc40f463cbc52d94ed9315cf9a547d4c89f2.json @@ -130,28 +130,28 @@ }, { "ordinal": 25, - "name": "ai_models", - "type_info": "VarcharArray" + "name": "teams_command_script", + "type_info": "Text" }, { "ordinal": 26, - "name": "code_completion_model", - "type_info": "Varchar" + "name": "teams_team_id", + "type_info": "Text" }, { "ordinal": 27, - "name": "teams_command_script", + "name": "teams_team_name", "type_info": "Text" }, { "ordinal": 28, - "name": "teams_team_id", - "type_info": "Text" + "name": "ai_models", + "type_info": "VarcharArray" }, { "ordinal": 29, - "name": "teams_team_name", - "type_info": "Text" + "name": "code_completion_model", + "type_info": "Varchar" } ], "parameters": { @@ -185,10 +185,10 @@ true, true, true, - false, true, true, true, + false, true ] }, diff --git a/backend/.sqlx/query-6536214f31e9d600e868b01385d8c6395e2440ea27553b7ccb18d7149b106728.json b/backend/.sqlx/query-6536214f31e9d600e868b01385d8c6395e2440ea27553b7ccb18d7149b106728.json new file mode 100644 index 0000000000000..fce1c4942adec --- /dev/null +++ b/backend/.sqlx/query-6536214f31e9d600e868b01385d8c6395e2440ea27553b7ccb18d7149b106728.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DROP INDEX CONCURRENTLY IF EXISTS root_job_index_by_path_2", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "6536214f31e9d600e868b01385d8c6395e2440ea27553b7ccb18d7149b106728" +} diff --git a/backend/.sqlx/query-65c339164e7669360d231d70105849e72bdc197c17c0fc51777c1dc9267e2daf.json b/backend/.sqlx/query-65c339164e7669360d231d70105849e72bdc197c17c0fc51777c1dc9267e2daf.json new file mode 100644 index 0000000000000..d52d46f1ddb7c --- /dev/null +++ b/backend/.sqlx/query-65c339164e7669360d231d70105849e72bdc197c17c0fc51777c1dc9267e2daf.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE workspace_settings\n SET teams_command_script = NULL,\n teams_team_id = NULL,\n teams_team_name = NULL\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "65c339164e7669360d231d70105849e72bdc197c17c0fc51777c1dc9267e2daf" +} diff --git a/backend/.sqlx/query-81b06122c7a12a314d8905ba5c7c14aa7614f2610e79a8c7302eaa63fb74984d.json b/backend/.sqlx/query-81b06122c7a12a314d8905ba5c7c14aa7614f2610e79a8c7302eaa63fb74984d.json new file mode 100644 index 0000000000000..91718513bbb6b --- /dev/null +++ b/backend/.sqlx/query-81b06122c7a12a314d8905ba5c7c14aa7614f2610e79a8c7302eaa63fb74984d.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "\n UPDATE global_settings\n SET value = (\n SELECT COALESCE(jsonb_agg(elem), '[]'::jsonb)\n FROM jsonb_array_elements(value) AS elem\n WHERE NOT (elem ? 'teams_channel')\n )\n WHERE name = 'critical_error_channels'\n ", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "81b06122c7a12a314d8905ba5c7c14aa7614f2610e79a8c7302eaa63fb74984d" +} diff --git a/backend/.sqlx/query-8be277b89102a26dda506202a3ef7eb05342cfb3aa9b4f5d80c70fbc50d437ba.json b/backend/.sqlx/query-8be277b89102a26dda506202a3ef7eb05342cfb3aa9b4f5d80c70fbc50d437ba.json deleted file mode 100644 index e5819f5c6ab3f..0000000000000 --- a/backend/.sqlx/query-8be277b89102a26dda506202a3ef7eb05342cfb3aa9b4f5d80c70fbc50d437ba.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "create index concurrently if not exists ix_job_workspace_id_created_at_new_6 ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow') AND parent_job IS NULL", - "describe": { - "columns": [], - "parameters": { - "Left": [] - }, - "nullable": [] - }, - "hash": "8be277b89102a26dda506202a3ef7eb05342cfb3aa9b4f5d80c70fbc50d437ba" -} diff --git a/backend/.sqlx/query-ae8dfecd46425d5f86003eea9a578e9831fc0e700cc76ab9627afe9040a4efe0.json b/backend/.sqlx/query-ae8dfecd46425d5f86003eea9a578e9831fc0e700cc76ab9627afe9040a4efe0.json deleted file mode 100644 index c0703bc518664..0000000000000 --- a/backend/.sqlx/query-ae8dfecd46425d5f86003eea9a578e9831fc0e700cc76ab9627afe9040a4efe0.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "create index concurrently if not exists ix_job_workspace_id_created_at_new_7 ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow') AND parent_job IS NULL", - "describe": { - "columns": [], - "parameters": { - "Left": [] - }, - "nullable": [] - }, - "hash": "ae8dfecd46425d5f86003eea9a578e9831fc0e700cc76ab9627afe9040a4efe0" -} diff --git a/backend/.sqlx/query-b9b38d63af3670d1f11d5cbb82a8008a9479bf4b3d7231371ebf26382ecde365.json b/backend/.sqlx/query-b9b38d63af3670d1f11d5cbb82a8008a9479bf4b3d7231371ebf26382ecde365.json new file mode 100644 index 0000000000000..641c94c555b3b --- /dev/null +++ b/backend/.sqlx/query-b9b38d63af3670d1f11d5cbb82a8008a9479bf4b3d7231371ebf26382ecde365.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "VACUUM v2_job_queue, v2_job_runtime, v2_job_status", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "b9b38d63af3670d1f11d5cbb82a8008a9479bf4b3d7231371ebf26382ecde365" +} diff --git a/backend/.sqlx/query-c481e5d63ebf1aa537cc4ce4e84f9a71af5996bc76f328b3ba1cf68a71880462.json b/backend/.sqlx/query-c481e5d63ebf1aa537cc4ce4e84f9a71af5996bc76f328b3ba1cf68a71880462.json new file mode 100644 index 0000000000000..b3d20ccceab50 --- /dev/null +++ b/backend/.sqlx/query-c481e5d63ebf1aa537cc4ce4e84f9a71af5996bc76f328b3ba1cf68a71880462.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "create index concurrently if not exists ix_job_root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "c481e5d63ebf1aa537cc4ce4e84f9a71af5996bc76f328b3ba1cf68a71880462" +} diff --git a/backend/.sqlx/query-d25c58d2722ad3dcd91101ce6f66e1d802dd5d82e1cd5f5ed3a15cbc75eb6745.json b/backend/.sqlx/query-c92cc71e6d10c41368f7aa75b0799c2e1e9ca0ed33077ade8d7560e7cc21fa06.json similarity index 60% rename from backend/.sqlx/query-d25c58d2722ad3dcd91101ce6f66e1d802dd5d82e1cd5f5ed3a15cbc75eb6745.json rename to backend/.sqlx/query-c92cc71e6d10c41368f7aa75b0799c2e1e9ca0ed33077ade8d7560e7cc21fa06.json index 2872c1655ba8f..8a4b957c2a69a 100644 --- a/backend/.sqlx/query-d25c58d2722ad3dcd91101ce6f66e1d802dd5d82e1cd5f5ed3a15cbc75eb6745.json +++ b/backend/.sqlx/query-c92cc71e6d10c41368f7aa75b0799c2e1e9ca0ed33077ade8d7560e7cc21fa06.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "DELETE FROM v2_job_queue WHERE workspace_id = $1 AND id = $2 RETURNING 1", + "query": "DELETE FROM v2_job_queue WHERE id = $1 RETURNING 1", "describe": { "columns": [ { @@ -11,7 +11,6 @@ ], "parameters": { "Left": [ - "Text", "Uuid" ] }, @@ -19,5 +18,5 @@ null ] }, - "hash": "d25c58d2722ad3dcd91101ce6f66e1d802dd5d82e1cd5f5ed3a15cbc75eb6745" + "hash": "c92cc71e6d10c41368f7aa75b0799c2e1e9ca0ed33077ade8d7560e7cc21fa06" } diff --git a/backend/.sqlx/query-d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0.json b/backend/.sqlx/query-d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0.json new file mode 100644 index 0000000000000..72169ec94bb65 --- /dev/null +++ b/backend/.sqlx/query-d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "create index concurrently if not exists ix_v2_job_workspace_id_created_at ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow', 'singlescriptflow') AND parent_job IS NULL", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "d585aa6301c41308b02a1f0fbf068221e732e48dfa6e34d5b025adbbdcbb03e0" +} diff --git a/backend/.sqlx/query-e565f3b2e51059f563d18a8a9442bcae9640cee7b936820cb46c011222a77ff0.json b/backend/.sqlx/query-e565f3b2e51059f563d18a8a9442bcae9640cee7b936820cb46c011222a77ff0.json new file mode 100644 index 0000000000000..4c2cd96ca9945 --- /dev/null +++ b/backend/.sqlx/query-e565f3b2e51059f563d18a8a9442bcae9640cee7b936820cb46c011222a77ff0.json @@ -0,0 +1,14 @@ +{ + "db_name": "PostgreSQL", + "query": "UPDATE global_settings SET value = $1 WHERE name = 'teams'", + "describe": { + "columns": [], + "parameters": { + "Left": [ + "Jsonb" + ] + }, + "nullable": [] + }, + "hash": "e565f3b2e51059f563d18a8a9442bcae9640cee7b936820cb46c011222a77ff0" +} diff --git a/backend/.sqlx/query-faa0e401e6beebde6c3fef06151d3e73a5806f61cae4a53b5bdc888ec7164395.json b/backend/.sqlx/query-faa0e401e6beebde6c3fef06151d3e73a5806f61cae4a53b5bdc888ec7164395.json new file mode 100644 index 0000000000000..2824316ed30e6 --- /dev/null +++ b/backend/.sqlx/query-faa0e401e6beebde6c3fef06151d3e73a5806f61cae4a53b5bdc888ec7164395.json @@ -0,0 +1,12 @@ +{ + "db_name": "PostgreSQL", + "query": "DROP INDEX CONCURRENTLY IF EXISTS ix_job_workspace_id_created_at_new_6", + "describe": { + "columns": [], + "parameters": { + "Left": [] + }, + "nullable": [] + }, + "hash": "faa0e401e6beebde6c3fef06151d3e73a5806f61cae4a53b5bdc888ec7164395" +} diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 2ac7a62a7e157..d57277aef5902 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -713,7 +713,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "tracing", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -1029,9 +1029,9 @@ dependencies = [ [[package]] name = "backon" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5289ec98f68f28dd809fd601059e6aa908bb8f6108620930828283d4ee23d7" +checksum = "49fef586913a57ff189f25c9b3d034356a5bf6b3fa9a7f067588fe1698ba1f5d" dependencies = [ "fastrand 2.3.0", "gloo-timers", @@ -1244,15 +1244,16 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.5" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +checksum = "1230237285e3e10cde447185e8975408ae24deaa67205ce684805c25bc0c7937" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", + "memmap2", ] [[package]] @@ -1690,9 +1691,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.29" +version = "4.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184" +checksum = "92b7b18d71fad5313a1e320fa9897994228ce274b60faa4d694fe0ea89cd9e6d" dependencies = [ "clap_builder", "clap_derive", @@ -1700,9 +1701,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.29" +version = "4.5.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9" +checksum = "a35db2071778a7344791a4fb4f95308b5673d219dee3ae348b86642574ecc90c" dependencies = [ "anstream", "anstyle", @@ -2285,7 +2286,7 @@ dependencies = [ "tokio", "tokio-util", "url", - "uuid 1.13.1", + "uuid 1.13.2", "xz2", "zstd", ] @@ -2385,7 +2386,7 @@ dependencies = [ "regex", "sha2 0.10.8", "unicode-segmentation", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -2552,7 +2553,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" dependencies = [ "serde", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -2847,7 +2848,7 @@ dependencies = [ "serde", "thiserror 1.0.69", "tokio", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -3231,9 +3232,9 @@ dependencies = [ [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -5427,7 +5428,7 @@ dependencies = [ "sha2 0.10.8", "subprocess", "thiserror 1.0.69", - "uuid 1.13.1", + "uuid 1.13.2", "zstd", ] @@ -5798,9 +5799,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.70" +version = "0.10.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6" +checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" dependencies = [ "bitflags 2.8.0", "cfg-if", @@ -5839,9 +5840,9 @@ dependencies = [ [[package]] name = "openssl-sys" -version = "0.9.105" +version = "0.9.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" dependencies = [ "cc", "libc", @@ -6388,7 +6389,7 @@ dependencies = [ "postgres-protocol 0.6.8", "serde", "serde_json", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -6630,9 +6631,9 @@ dependencies = [ [[package]] name = "psm" -version = "0.1.24" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200b9ff220857e53e184257720a14553b2f4aa02577d2ed9842d45d4b9654810" +checksum = "f58e5423e24c18cc840e1c98370b3993c6649cd1678b4d24318bcf0a083cbe88" dependencies = [ "cc", ] @@ -6759,9 +6760,9 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" +checksum = "e46f3055866785f6b92bc6164b76be02ca8f2eb4b002c0354b28cf4c119e5944" dependencies = [ "cfg_aliases", "libc", @@ -6817,8 +6818,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.0", - "zerocopy 0.8.17", + "rand_core 0.9.1", + "zerocopy 0.8.18", ] [[package]] @@ -6848,7 +6849,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.0", + "rand_core 0.9.1", ] [[package]] @@ -6871,12 +6872,12 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" +checksum = "a88e0da7a2c97baa202165137c158d0a2e824ac465d13d81046727b34cb247d3" dependencies = [ "getrandom 0.3.1", - "zerocopy 0.8.17", + "zerocopy 0.8.18", ] [[package]] @@ -7244,7 +7245,7 @@ dependencies = [ "rkyv_derive", "seahash", "tinyvec", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -7597,9 +7598,9 @@ checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "ryu-js" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad97d4ce1560a5e27cec89519dc8300d1aa6035b099821261c651486a19e44d5" +checksum = "dd29631678d6fb0903b69223673e122c32e9ae559d0960a38d574695ebc0ea15" [[package]] name = "safetensors" @@ -7635,7 +7636,7 @@ dependencies = [ "serde", "thiserror 1.0.69", "url", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -7673,7 +7674,7 @@ dependencies = [ "schemars_derive", "serde", "serde_json", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -8172,9 +8173,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" dependencies = [ "serde", ] @@ -8408,7 +8409,7 @@ dependencies = [ "tokio-stream", "tracing", "url", - "uuid 1.13.1", + "uuid 1.13.2", "webpki-roots", ] @@ -8492,7 +8493,7 @@ dependencies = [ "stringprep", "thiserror 2.0.11", "tracing", - "uuid 1.13.1", + "uuid 1.13.2", "whoami", ] @@ -8533,7 +8534,7 @@ dependencies = [ "stringprep", "thiserror 2.0.11", "tracing", - "uuid 1.13.1", + "uuid 1.13.2", "whoami", ] @@ -8559,7 +8560,7 @@ dependencies = [ "sqlx-core", "tracing", "url", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -9206,7 +9207,7 @@ dependencies = [ "tempfile", "thiserror 1.0.69", "time", - "uuid 1.13.1", + "uuid 1.13.2", "winapi", ] @@ -9319,9 +9320,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.16.0" +version = "3.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" +checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", "fastrand 2.3.0", @@ -9436,7 +9437,7 @@ dependencies = [ "tokio-rustls 0.24.1", "tokio-util", "tracing", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] @@ -10143,9 +10144,9 @@ dependencies = [ [[package]] name = "tree-sitter-language" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eee4db33814de3d004de9d8d825627ed3320d0989cce0dea30efaf5be4736c" +checksum = "c4013970217383f67b18aef68f6fb2e8d409bc5755227092d32efb0422ba24b8" [[package]] name = "triomphe" @@ -10217,9 +10218,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "typify" @@ -10272,7 +10273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab82fc73182c29b02e2926a6df32f2241dbadb5cfc111fd595515b3598f46bb3" dependencies = [ "rand 0.9.0", - "uuid 1.13.1", + "uuid 1.13.2", "web-time", ] @@ -10554,9 +10555,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" +checksum = "8c1f41ffb7cf259f1ecc2876861a17e7142e63ead296f671f81f6ae85903e0d6" dependencies = [ "getrandom 0.3.1", "serde", @@ -10880,7 +10881,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windmill" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "axum", @@ -10909,7 +10910,7 @@ dependencies = [ "tokio", "tracing", "url", - "uuid 1.13.1", + "uuid 1.13.2", "v8", "windmill-api", "windmill-api-client", @@ -10923,7 +10924,7 @@ dependencies = [ [[package]] name = "windmill-api" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "argon2", @@ -11006,19 +11007,20 @@ dependencies = [ "ulid", "url", "urlencoding", - "uuid 1.13.1", + "uuid 1.13.2", "windmill-audit", "windmill-common", "windmill-git-sync", "windmill-indexer", "windmill-parser", + "windmill-parser-py", "windmill-parser-ts", "windmill-queue", ] [[package]] name = "windmill-api-client" -version = "1.462.3" +version = "1.463.6" dependencies = [ "base64 0.22.1", "chrono", @@ -11031,12 +11033,12 @@ dependencies = [ "serde", "serde_json", "syn 1.0.109", - "uuid 1.13.1", + "uuid 1.13.2", ] [[package]] name = "windmill-audit" -version = "1.462.3" +version = "1.463.6" dependencies = [ "chrono", "serde", @@ -11049,21 +11051,21 @@ dependencies = [ [[package]] name = "windmill-autoscaling" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "serde", "serde_json", "sqlx", "tracing", - "uuid 1.13.1", + "uuid 1.13.2", "windmill-common", "windmill-queue", ] [[package]] name = "windmill-common" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "async-stream", @@ -11116,27 +11118,27 @@ dependencies = [ "tracing-loki", "tracing-opentelemetry", "tracing-subscriber", - "uuid 1.13.1", + "uuid 1.13.2", "windmill-macros", ] [[package]] name = "windmill-git-sync" -version = "1.462.3" +version = "1.463.6" dependencies = [ "regex", "serde", "serde_json", "sqlx", "tracing", - "uuid 1.13.1", + "uuid 1.13.2", "windmill-common", "windmill-queue", ] [[package]] name = "windmill-indexer" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "bytes", @@ -11153,13 +11155,13 @@ dependencies = [ "tokio", "tokio-tar", "tracing", - "uuid 1.13.1", + "uuid 1.13.2", "windmill-common", ] [[package]] name = "windmill-macros" -version = "1.462.3" +version = "1.463.6" dependencies = [ "itertools 0.14.0", "lazy_static", @@ -11171,7 +11173,7 @@ dependencies = [ [[package]] name = "windmill-parser" -version = "1.462.3" +version = "1.463.6" dependencies = [ "convert_case 0.6.0", "serde", @@ -11180,7 +11182,7 @@ dependencies = [ [[package]] name = "windmill-parser-bash" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "lazy_static", @@ -11192,7 +11194,7 @@ dependencies = [ [[package]] name = "windmill-parser-csharp" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "serde_json", @@ -11204,7 +11206,7 @@ dependencies = [ [[package]] name = "windmill-parser-go" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "gosyn", @@ -11216,7 +11218,7 @@ dependencies = [ [[package]] name = "windmill-parser-graphql" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "lazy_static", @@ -11228,7 +11230,7 @@ dependencies = [ [[package]] name = "windmill-parser-php" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "itertools 0.14.0", @@ -11239,7 +11241,7 @@ dependencies = [ [[package]] name = "windmill-parser-py" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "itertools 0.14.0", @@ -11250,7 +11252,7 @@ dependencies = [ [[package]] name = "windmill-parser-py-imports" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "async-recursion", @@ -11270,7 +11272,7 @@ dependencies = [ [[package]] name = "windmill-parser-rust" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -11287,7 +11289,7 @@ dependencies = [ [[package]] name = "windmill-parser-sql" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "lazy_static", @@ -11299,7 +11301,7 @@ dependencies = [ [[package]] name = "windmill-parser-ts" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "lazy_static", @@ -11317,7 +11319,7 @@ dependencies = [ [[package]] name = "windmill-parser-wasm" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "getrandom 0.2.15", @@ -11339,7 +11341,7 @@ dependencies = [ [[package]] name = "windmill-parser-yaml" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "serde_json", @@ -11349,7 +11351,7 @@ dependencies = [ [[package]] name = "windmill-queue" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "async-recursion", @@ -11375,14 +11377,14 @@ dependencies = [ "tokio", "tracing", "ulid", - "uuid 1.13.1", + "uuid 1.13.2", "windmill-audit", "windmill-common", ] [[package]] name = "windmill-sql-datatype-parser-wasm" -version = "1.462.3" +version = "1.463.6" dependencies = [ "wasm-bindgen", "wasm-bindgen-test", @@ -11392,7 +11394,7 @@ dependencies = [ [[package]] name = "windmill-worker" -version = "1.462.3" +version = "1.463.6" dependencies = [ "anyhow", "async-recursion", @@ -11449,7 +11451,7 @@ dependencies = [ "tokio-util", "tracing", "urlencoding", - "uuid 1.13.1", + "uuid 1.13.2", "windmill-audit", "windmill-common", "windmill-git-sync", @@ -11806,11 +11808,11 @@ dependencies = [ [[package]] name = "zerocopy" -version = "0.8.17" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" +checksum = "79386d31a42a4996e3336b0919ddb90f81112af416270cff95b5f5af22b839c2" dependencies = [ - "zerocopy-derive 0.8.17", + "zerocopy-derive 0.8.18", ] [[package]] @@ -11826,9 +11828,9 @@ dependencies = [ [[package]] name = "zerocopy-derive" -version = "0.8.17" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" +checksum = "76331675d372f91bf8d17e13afbd5fe639200b73d01f0fc748bb059f9cca2db7" dependencies = [ "proc-macro2", "quote", diff --git a/backend/Cargo.toml b/backend/Cargo.toml index f930b255e3c85..6cc04dcd39dcc 100644 --- a/backend/Cargo.toml +++ b/backend/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "windmill" -version = "1.462.3" +version = "1.463.6" authors.workspace = true edition.workspace = true @@ -30,7 +30,7 @@ members = [ ] [workspace.package] -version = "1.462.3" +version = "1.463.6" authors = ["Ruben Fiszel "] edition = "2021" @@ -175,7 +175,7 @@ uuid = { version = "^1", features = ["serde", "v4"] } thiserror = "^2" anyhow = "^1" chrono = { version = "0.4.35", features = ["serde"] } -chrono-tz = "^0" +chrono-tz = "^0.10.1" tracing = "^0" tracing-subscriber = { version = "^0", features = ["env-filter", "json"] } tracing-appender = "^0" diff --git a/backend/migrations/20250205131519_windmill_admin_skip_bypassrls_on_v2_job.down.sql b/backend/migrations/20250205131519_windmill_admin_skip_bypassrls_on_v2_job.down.sql new file mode 100644 index 0000000000000..d2f607c5b8bd6 --- /dev/null +++ b/backend/migrations/20250205131519_windmill_admin_skip_bypassrls_on_v2_job.down.sql @@ -0,0 +1 @@ +-- Add down migration script here diff --git a/backend/migrations/20250205131519_windmill_admin_skip_bypassrls_on_v2_job.up.sql b/backend/migrations/20250205131519_windmill_admin_skip_bypassrls_on_v2_job.up.sql new file mode 100644 index 0000000000000..f83ee7f3482ff --- /dev/null +++ b/backend/migrations/20250205131519_windmill_admin_skip_bypassrls_on_v2_job.up.sql @@ -0,0 +1,3 @@ +-- Add up migration script here +DROP POLICY IF EXISTS admin_policy ON v2_job; +CREATE POLICY admin_policy ON v2_job FOR ALL TO windmill_admin USING (true); diff --git a/backend/parsers/windmill-parser-py/src/lib.rs b/backend/parsers/windmill-parser-py/src/lib.rs index 738bc8ed7c798..76f0c415ea1e7 100644 --- a/backend/parsers/windmill-parser-py/src/lib.rs +++ b/backend/parsers/windmill-parser-py/src/lib.rs @@ -60,6 +60,7 @@ fn filter_non_main(code: &str, main_name: &str) -> String { pub fn parse_python_signature( code: &str, override_main: Option, + skip_params: bool, ) -> anyhow::Result { let main_name = override_main.unwrap_or("main".to_string()); @@ -78,11 +79,13 @@ pub fn parse_python_signature( let ast = Suite::parse(&filtered_code, "main.py") .map_err(|e| anyhow::anyhow!("Error parsing code: {}", e.to_string()))?; - let param = ast.into_iter().find_map(|x| match x { + let params = ast.into_iter().find_map(|x| match x { Stmt::FunctionDef(StmtFunctionDef { name, args, .. }) if &name == &main_name => Some(*args), _ => None, }); - if let Some(params) = param { + + if !skip_params && params.is_some() { + let params = params.unwrap(); //println!("{:?}", params); let def_arg_start = params.args.len() - params.defaults().count(); Ok(MainArgSignature { @@ -149,7 +152,7 @@ pub fn parse_python_signature( star_args: false, star_kwargs: false, args: vec![], - no_main_func: Some(true), + no_main_func: Some(params.is_none()), has_preprocessor: Some(has_preprocessor), }) } @@ -287,7 +290,7 @@ def main(test1: str, name: datetime.datetime = datetime.now(), byte: bytes = byt "; //println!("{}", serde_json::to_string()?); assert_eq!( - parse_python_signature(code, None)?, + parse_python_signature(code, None, false)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -376,7 +379,7 @@ def main(test1: str, "; //println!("{}", serde_json::to_string()?); assert_eq!( - parse_python_signature(code, None)?, + parse_python_signature(code, None, false)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -436,7 +439,7 @@ def main(test1: str, "; //println!("{}", serde_json::to_string()?); assert_eq!( - parse_python_signature(code, None)?, + parse_python_signature(code, None, false)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -493,7 +496,7 @@ def main(test1: Literal["foo", "bar"], test2: List[Literal["foo", "bar"]]): retu "#; //println!("{}", serde_json::to_string()?); assert_eq!( - parse_python_signature(code, None)?, + parse_python_signature(code, None, false)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -537,7 +540,7 @@ def main(test1: DynSelect_foo): return "#; //println!("{}", serde_json::to_string()?); assert_eq!( - parse_python_signature(code, None)?, + parse_python_signature(code, None, false)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -568,7 +571,7 @@ def hello(): return "#; //println!("{}", serde_json::to_string()?); assert_eq!( - parse_python_signature(code, None)?, + parse_python_signature(code, None, false)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -596,7 +599,7 @@ def main(): return "#; //println!("{}", serde_json::to_string()?); assert_eq!( - parse_python_signature(code, None)?, + parse_python_signature(code, None, false)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -617,10 +620,10 @@ def main(a: list, e: List[int], b: list = [1,2,3,4], c = [1,2,3,4], d = ["a", "b "#; println!( "{}", - serde_json::to_string(&parse_python_signature(code, None)?)? + serde_json::to_string(&parse_python_signature(code, None, false)?)? ); assert_eq!( - parse_python_signature(code, None)?, + parse_python_signature(code, None, false)?, MainArgSignature { star_args: false, star_kwargs: false, diff --git a/backend/parsers/windmill-parser-ts/src/lib.rs b/backend/parsers/windmill-parser-ts/src/lib.rs index f69169c0e2658..78a83cd9290b4 100644 --- a/backend/parsers/windmill-parser-ts/src/lib.rs +++ b/backend/parsers/windmill-parser-ts/src/lib.rs @@ -134,6 +134,7 @@ pub fn parse_expr_for_ids(code: &str) -> anyhow::Result> { pub fn parse_deno_signature( code: &str, skip_dflt: bool, + skip_params: bool, main_override: Option, ) -> anyhow::Result { let cm: Lrc = Default::default(); @@ -179,27 +180,26 @@ pub fn parse_deno_signature( }); let mut c: u16 = 0; - if let Some(params) = params { - let r = MainArgSignature { - star_args: false, - star_kwargs: false, - args: params - .into_iter() - .map(|x| parse_param(x, &cm, skip_dflt, &mut c)) - .collect::>>()?, - no_main_func: Some(false), - has_preprocessor: Some(has_preprocessor), - }; - Ok(r) - } else { - Ok(MainArgSignature { - star_args: false, - star_kwargs: false, - args: vec![], - no_main_func: Some(true), - has_preprocessor: Some(has_preprocessor), - }) - } + let no_main_func = params.is_none(); + let r = MainArgSignature { + star_args: false, + star_kwargs: false, + args: if skip_params { + vec![] + } else { + params + .map(|x| { + x.into_iter() + .map(|x| parse_param(x, &cm, skip_dflt, &mut c)) + .collect::>>() + }) + .transpose()? + .unwrap_or_else(|| vec![]) + }, + no_main_func: Some(no_main_func), + has_preprocessor: Some(has_preprocessor), + }; + Ok(r) } fn parse_param( diff --git a/backend/parsers/windmill-parser-wasm/src/lib.rs b/backend/parsers/windmill-parser-wasm/src/lib.rs index e3de739f9634c..306d67751cbf3 100644 --- a/backend/parsers/windmill-parser-wasm/src/lib.rs +++ b/backend/parsers/windmill-parser-wasm/src/lib.rs @@ -17,10 +17,11 @@ fn wrap_sig(r: anyhow::Result) -> String { #[cfg(feature = "ts-parser")] #[wasm_bindgen] -pub fn parse_deno(code: &str, main_override: Option) -> String { +pub fn parse_deno(code: &str, main_override: Option, skip_params: Option) -> String { wrap_sig(windmill_parser_ts::parse_deno_signature( code, false, + false, main_override, )) } @@ -73,6 +74,7 @@ pub fn parse_python(code: &str, main_override: Option) -> String { wrap_sig(windmill_parser_py::parse_python_signature( code, main_override, + false, )) } diff --git a/backend/parsers/windmill-parser-wasm/tests/wasm.rs b/backend/parsers/windmill-parser-wasm/tests/wasm.rs index 1c201ecd4eedf..9f6d452a21df9 100644 --- a/backend/parsers/windmill-parser-wasm/tests/wasm.rs +++ b/backend/parsers/windmill-parser-wasm/tests/wasm.rs @@ -18,7 +18,7 @@ export function main(test1?: string, test2: string = \"burkina\", } "; assert_eq!( - parse_deno_signature(code, false, None)?, + parse_deno_signature(code, false, false, None)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -159,7 +159,7 @@ export function main(test2 = \"burkina\", } "; assert_eq!( - parse_deno_signature(code, false, None)?, + parse_deno_signature(code, false, false, None)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -236,7 +236,7 @@ export function main(foo: FooBar, {a, b}: FooBar, {c, d}: FooBar = {a: \"foo\", } "; assert_eq!( - parse_deno_signature(code, false, None)?, + parse_deno_signature(code, false, false, None)?, MainArgSignature { star_args: false, star_kwargs: false, @@ -282,7 +282,7 @@ export function main(foo: (\"foo\" | \"bar\")[]) { } "; assert_eq!( - parse_deno_signature(code, false, None)?, + parse_deno_signature(code, false, false, None)?, MainArgSignature { star_args: false, star_kwargs: false, diff --git a/backend/pg_log_tail b/backend/pg_log_tail new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/backend/src/main.rs b/backend/src/main.rs index 432095580d931..56eae30332ee1 100644 --- a/backend/src/main.rs +++ b/backend/src/main.rs @@ -21,7 +21,7 @@ use std::{ net::{IpAddr, Ipv4Addr, SocketAddr}, time::Duration, }; -use tokio::{fs::File, io::AsyncReadExt}; +use tokio::{fs::File, io::AsyncReadExt, task::JoinHandle}; use uuid::Uuid; use windmill_api::HTTP_CLIENT; @@ -372,6 +372,7 @@ async fn windmill_main() -> anyhow::Result<()> { let is_agent = mode == Mode::Agent; + let mut migration_handle: Option> = None; #[cfg(feature = "parquet")] let disable_s3_store = std::env::var("DISABLE_S3_STORE") .ok() @@ -384,7 +385,7 @@ async fn windmill_main() -> anyhow::Result<()> { if !skip_migration { // migration code to avoid break - windmill_api::migrate_db(&db).await?; + migration_handle = windmill_api::migrate_db(&db).await?; } else { tracing::info!("SKIP_MIGRATION set, skipping db migration...") } @@ -682,6 +683,14 @@ Windmill Community Edition {GIT_VERSION} loop { tokio::select! { biased; + Some(_) = async { if let Some(jh) = migration_handle.take() { + tracing::info!("migration job finished"); + Some(jh.await) + } else { + None + }} => { + continue; + }, _ = monitor_killpill_rx.recv() => { tracing::info!("received killpill for monitor job"); break; @@ -892,14 +901,21 @@ Windmill Community Edition {GIT_VERSION} }; let metrics_f = async { - if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) { - #[cfg(not(feature = "enterprise"))] + let enabled = METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed); + #[cfg(not(feature = "enterprise"))] + if enabled { tracing::error!("Metrics are only available in the EE, ignoring..."); - - #[cfg(feature = "enterprise")] - windmill_common::serve_metrics(*METRICS_ADDR, _killpill_phase2_rx, num_workers > 0) - .await; } + + #[cfg(all(feature = "enterprise", feature = "prometheus"))] + windmill_common::serve_metrics( + *METRICS_ADDR, + _killpill_phase2_rx, + num_workers > 0, + enabled, + ) + .await; + Ok(()) as anyhow::Result<()> }; diff --git a/backend/substitute_ee_code.sh b/backend/substitute_ee_code.sh index c15d19a2597a3..28b890990b0be 100755 --- a/backend/substitute_ee_code.sh +++ b/backend/substitute_ee_code.sh @@ -68,7 +68,7 @@ fi if [ "$REVERT" == "YES" ]; then for ee_file in $(find ${EE_CODE_DIR} -name "*ee.rs"); do - ce_file="${ee_file/${EE_CODE_DIR}/.}" + ce_file="${ee_file/${EE_CODE_DIR}/}" ce_file="${root_dirpath}/backend/${ce_file}" if [ "$REVERT_PREVIOUS" == "YES" ]; then git checkout HEAD@{3} ${ce_file} || true @@ -80,7 +80,7 @@ if [ "$REVERT" == "YES" ]; then else # This replaces all files in current repo with alternative EE files in windmill-ee-private for ee_file in $(find "${EE_CODE_DIR}" -name "*ee.rs"); do - ce_file="${ee_file/${EE_CODE_DIR}/.}" + ce_file="${ee_file/${EE_CODE_DIR}/}" ce_file="${root_dirpath}/backend/${ce_file}" if [[ -f "${ce_file}" ]]; then rm "${ce_file}" diff --git a/backend/windmill-api/Cargo.toml b/backend/windmill-api/Cargo.toml index 1ad361144d333..d5f8f6f420709 100644 --- a/backend/windmill-api/Cargo.toml +++ b/backend/windmill-api/Cargo.toml @@ -37,6 +37,7 @@ windmill-common = { workspace = true, default-features = false } windmill-audit.workspace = true windmill-parser.workspace = true windmill-parser-ts.workspace = true +windmill-parser-py.workspace = true windmill-git-sync.workspace = true windmill-indexer = { workspace = true, optional = true } tokio.workspace = true diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index 5bf9026938499..d2d38268d59be 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.462.3 + version: 1.463.6 title: Windmill API contact: diff --git a/backend/windmill-api/src/db.rs b/backend/windmill-api/src/db.rs index 69bc969a7526c..9b694ad3bfcc9 100644 --- a/backend/windmill-api/src/db.rs +++ b/backend/windmill-api/src/db.rs @@ -15,6 +15,7 @@ use sqlx::{ Executor, PgConnection, Pool, Postgres, }; +use tokio::task::JoinHandle; use windmill_audit::audit_ee::{AuditAuthor, AuditAuthorable}; use windmill_common::{ db::{Authable, Authed}, @@ -170,7 +171,7 @@ impl Migrate for CustomMigrator { } } -pub async fn migrate(db: &DB) -> Result<(), Error> { +pub async fn migrate(db: &DB) -> Result>, Error> { let migrator = db.acquire().await?; let mut custom_migrator = CustomMigrator { inner: migrator }; @@ -225,9 +226,10 @@ pub async fn migrate(db: &DB) -> Result<(), Error> { } }); - if !has_done_migration(db, "v2_finalize_disable_sync_III").await { + let mut jh = None; + if !has_done_migration(db, "v2_finalize_job_completed").await { let db2 = db.clone(); - let _ = tokio::task::spawn(async move { + let v2jh = tokio::task::spawn(async move { loop { if !*MIN_VERSION_IS_AT_LEAST_1_461.read().await { tracing::info!("Waiting for all workers to be at least version 1.461 before applying v2 finalize migration, sleeping for 5s..."); @@ -245,9 +247,10 @@ pub async fn migrate(db: &DB) -> Result<(), Error> { break; } }); + jh = Some(v2jh) } - Ok(()) + Ok(jh) } async fn fix_flow_versioning_migration( @@ -373,29 +376,91 @@ async fn v2_finalize(db: &DB) -> Result<(), Error> { run_windmill_migration!("v2_finalize_disable_sync_III", db, |tx| { tx.execute( r#" + LOCK TABLE v2_job_queue IN ACCESS EXCLUSIVE MODE; ALTER TABLE v2_job_queue DISABLE ROW LEVEL SECURITY; + "#, + ) + .await?; + }); + + run_windmill_migration!("v2_finalize_disable_sync_III_2", db, |tx| { + tx.execute( + r#" + LOCK TABLE v2_job_completed IN ACCESS EXCLUSIVE MODE; ALTER TABLE v2_job_completed DISABLE ROW LEVEL SECURITY; + "#, + ) + .await?; + }); + run_windmill_migration!("v2_finalize_disable_sync_III_3", db, |tx| { + tx.execute( + r#" + LOCK TABLE v2_job IN ACCESS EXCLUSIVE MODE; DROP FUNCTION IF EXISTS v2_job_after_update CASCADE; + "#, + ) + .await?; + }); + + run_windmill_migration!("v2_finalize_disable_sync_III_4", db, |tx| { + tx.execute( + r#" + LOCK TABLE v2_job_completed IN ACCESS EXCLUSIVE MODE; DROP FUNCTION IF EXISTS v2_job_completed_before_insert CASCADE; - DROP FUNCTION IF EXISTS v2_job_completed_before_update CASCADE; + DROP FUNCTION IF EXISTS v2_job_completed_before_update CASCADE; + "#, + ) + .await?; + }); + + run_windmill_migration!("v2_finalize_disable_sync_III_5", db, |tx| { + tx.execute( + r#" + LOCK TABLE v2_job_queue IN ACCESS EXCLUSIVE MODE; DROP FUNCTION IF EXISTS v2_job_queue_after_insert CASCADE; DROP FUNCTION IF EXISTS v2_job_queue_before_insert CASCADE; - DROP FUNCTION IF EXISTS v2_job_queue_before_update CASCADE; + DROP FUNCTION IF EXISTS v2_job_queue_before_update CASCADE; + "#, + ) + .await?; + }); + + run_windmill_migration!("v2_finalize_disable_sync_III_6", db, |tx| { + tx.execute( + r#" + LOCK TABLE v2_job_runtime IN ACCESS EXCLUSIVE MODE; DROP FUNCTION IF EXISTS v2_job_runtime_before_insert CASCADE; - DROP FUNCTION IF EXISTS v2_job_runtime_before_update CASCADE; + DROP FUNCTION IF EXISTS v2_job_runtime_before_update CASCADE; + "#, + ) + .await?; + }); + + run_windmill_migration!("v2_finalize_disable_sync_III_7", db, |tx| { + tx.execute( + r#" + LOCK TABLE v2_job_status IN ACCESS EXCLUSIVE MODE; DROP FUNCTION IF EXISTS v2_job_status_before_insert CASCADE; - DROP FUNCTION IF EXISTS v2_job_status_before_update CASCADE; + DROP FUNCTION IF EXISTS v2_job_status_before_update CASCADE; + "#, + ) + .await?; + }); + run_windmill_migration!("v2_finalize_disable_sync_III_8", db, |tx| { + tx.execute( + r#" DROP VIEW IF EXISTS completed_job, completed_job_view, job, queue, queue_view CASCADE; - "#, ) .await?; }); + run_windmill_migration!("v2_finalize_job_queue", db, |tx| { tx.execute( r#" + LOCK TABLE v2_job_queue IN ACCESS EXCLUSIVE MODE; ALTER TABLE v2_job_queue DROP COLUMN IF EXISTS __parent_job CASCADE, DROP COLUMN IF EXISTS __created_by CASCADE, @@ -434,6 +499,7 @@ async fn v2_finalize(db: &DB) -> Result<(), Error> { run_windmill_migration!("v2_finalize_job_completed", db, |tx| { tx.execute( r#" + LOCK TABLE v2_job_completed IN ACCESS EXCLUSIVE MODE; ALTER TABLE v2_job_completed DROP COLUMN IF EXISTS __parent_job CASCADE, DROP COLUMN IF EXISTS __created_by CASCADE, @@ -545,8 +611,8 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> { .await?; }); - run_windmill_migration!("fix_job_index_1", &db, |tx| { - let migration_job_name = "fix_job_completed_index_4"; + run_windmill_migration!("fix_job_index_1_II", &db, |tx| { + let migration_job_name = "fix_job_index_1_II"; let mut i = 1; tracing::info!("step {i} of {migration_job_name} migration"); sqlx::query!("create index concurrently if not exists ix_job_workspace_id_created_at_new_3 ON v2_job (workspace_id, created_at DESC)") @@ -573,27 +639,22 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> { i += 1; tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query!("create index concurrently if not exists ix_job_workspace_id_created_at_new_6 ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow') AND parent_job IS NULL") + sqlx::query!("create index concurrently if not exists ix_completed_job_workspace_id_started_at_new_2 ON v2_job_completed (workspace_id, started_at DESC)") .execute(db) .await?; i += 1; tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query!("create index concurrently if not exists ix_job_workspace_id_created_at_new_7 ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow') AND parent_job IS NULL") + sqlx::query!("create index concurrently if not exists ix_job_root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL") .execute(db) .await?; - i += 1; - tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query!("create index concurrently if not exists ix_completed_job_workspace_id_started_at_new_2 ON v2_job_completed (workspace_id, started_at DESC)") - .execute(db) - .await?; i += 1; tracing::info!("step {i} of {migration_job_name} migration"); - sqlx::query!("create index concurrently if not exists root_job_index_by_path_2 ON v2_job (workspace_id, runnable_path, created_at desc) WHERE parent_job IS NULL") - .execute(db) - .await?; + sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS root_job_index_by_path_2") + .execute(db) + .await?; i += 1; tracing::info!("step {i} of {migration_job_name} migration"); @@ -653,6 +714,37 @@ async fn fix_job_completed_index(db: &DB) -> Result<(), Error> { .await?; }); + run_windmill_migration!("v2_improve_v2_job_indices_ii", &db, |tx| { + sqlx::query!("create index concurrently if not exists ix_v2_job_workspace_id_created_at ON v2_job (workspace_id, created_at DESC) where kind in ('script', 'flow', 'singlescriptflow') AND parent_job IS NULL") + .execute(db) + .await?; + + sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS ix_job_workspace_id_created_at_new_6") + .execute(db) + .await?; + + sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS ix_job_workspace_id_created_at_new_7") + .execute(db) + .await?; + }); + + run_windmill_migration!("v2_improve_v2_queued_jobs_indices", &db, |tx| { + sqlx::query!("CREATE INDEX CONCURRENTLY queue_sort_v2 ON v2_job_queue (priority DESC NULLS LAST, scheduled_for, tag) WHERE running = false") + .execute(db) + .await?; + + // sqlx::query!("CREATE INDEX CONCURRENTLY queue_sort_2_v2 ON v2_job_queue (tag, priority DESC NULLS LAST, scheduled_for) WHERE running = false") + // .execute(db) + // .await?; + + sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS queue_sort") + .execute(db) + .await?; + + sqlx::query!("DROP INDEX CONCURRENTLY IF EXISTS queue_sort_2") + .execute(db) + .await?; + }); Ok(()) } diff --git a/backend/windmill-api/src/http_triggers.rs b/backend/windmill-api/src/http_triggers.rs index 0d6be258e1659..722a639842396 100644 --- a/backend/windmill-api/src/http_triggers.rs +++ b/backend/windmill-api/src/http_triggers.rs @@ -538,7 +538,7 @@ async fn get_http_route_trigger( let route_path = trigger.route_path.clone(); if trigger.is_static_website { router - .insert(format!("{}/*wm_subpath", route_path), idx) + .insert(format!("/{}/*wm_subpath", route_path), idx) .unwrap_or_else(|e| { tracing::warn!( "Failed to consider http trigger route {}: {:?}", @@ -547,19 +547,22 @@ async fn get_http_route_trigger( ); }); } - router.insert(route_path.as_str(), idx).unwrap_or_else(|e| { - tracing::warn!( - "Failed to consider http trigger route {}: {:?}", - route_path, - e, - ); - }); + router + .insert(format!("/{}", route_path), idx) + .unwrap_or_else(|e| { + tracing::warn!( + "Failed to consider http trigger route {}: {:?}", + route_path, + e, + ); + }); } - let trigger_idx = router.at(route_path.0.as_str()).ok(); + let requested_path = format!("/{}", route_path.0); + let trigger_idx = router.at(requested_path.as_str()).ok(); let matchit::Match { value: trigger_idx, params } = - not_found_if_none(trigger_idx, "Trigger", route_path.0.as_str())?; + not_found_if_none(trigger_idx, "Trigger", requested_path.as_str())?; let trigger = triggers.remove(trigger_idx.to_owned()); diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 092d6b69b11d6..b5e1bc5a0867a 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -1161,7 +1161,7 @@ pub struct ListableCompletedJob { pub parent_job: Option, pub created_by: String, pub created_at: chrono::DateTime, - pub started_at: chrono::DateTime, + pub started_at: Option>, pub duration_ms: i64, pub success: bool, #[serde(skip_serializing_if = "Option::is_none")] @@ -1319,7 +1319,7 @@ pub fn filter_list_queue_query( } if let Some(p) = &lq.schedule_path { sqlb.and_where_eq("trigger", "?".bind(p)); - sqlb.and_where_eq("trigger_kind", "schedule"); + sqlb.and_where_eq("trigger_kind", "'schedule'"); } if let Some(h) = &lq.script_hash { sqlb.and_where_eq("runnable_id", "?".bind(h)); @@ -1647,6 +1647,7 @@ struct QueueStats { #[derive(Deserialize)] pub struct CountQueueJobsQuery { all_workspaces: Option, + tags: Option, } async fn count_queue_jobs( @@ -1654,12 +1655,16 @@ async fn count_queue_jobs( Path(w_id): Path, Query(cq): Query, ) -> error::JsonResult { + let tags = cq + .tags + .map(|t| t.split(',').map(|s| s.to_string()).collect::>()); Ok(Json( sqlx::query_as!( QueueStats, - "SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM v2_as_queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now()", + "SELECT coalesce(COUNT(*) FILTER(WHERE suspend = 0 AND running = false), 0) as \"database_length!\", coalesce(COUNT(*) FILTER(WHERE suspend > 0), 0) as \"suspended!\" FROM v2_as_queue WHERE (workspace_id = $1 OR $2) AND scheduled_for <= now() AND ($3::text[] IS NULL OR tag = ANY($3))", w_id, w_id == "admins" && cq.all_workspaces.unwrap_or(false), + tags.as_ref().map(|v| v.as_slice()) ) .fetch_one(&db) .await?, @@ -1800,13 +1805,13 @@ async fn list_jobs( } sqlc.unwrap().limit(per_page).offset(offset).query()? }; - let mut tx = user_db.begin(&authed).await?; + let mut tx: Transaction<'_, Postgres> = user_db.begin(&authed).await?; #[cfg(feature = "prometheus")] let start = Instant::now(); #[cfg(feature = "prometheus")] - if _api_list_jobs_query_duration.is_some() { + if _api_list_jobs_query_duration.is_some() || true { tracing::info!("list_jobs query: {}", sql); } @@ -2681,7 +2686,7 @@ const CJ_FIELDS: &[&str] = &[ "v2_job.runnable_path as script_path", "null as args", "v2_job_completed.duration_ms", - "v2_job_completed.status = 'success' as success", + "v2_job_completed.status = 'success' OR v2_job_completed.status = 'skipped' as success", "false as deleted", "v2_job_completed.status = 'canceled' as canceled", "v2_job_completed.canceled_by", @@ -4695,6 +4700,7 @@ struct BatchInfo { flow_value: Option, path: Option, rawscript: Option, + tag: Option, } #[tracing::instrument(level = "trace", skip_all)] @@ -4863,6 +4869,8 @@ async fn add_batch_jobs( } else { format!("{}", language.as_str()) } + } else if let Some(tag) = batch_info.tag { + tag } else { format!("{}", language.as_str()) }; @@ -5472,7 +5480,7 @@ async fn list_completed_jobs( "v2_job.created_at", "v2_job_completed.started_at", "v2_job_completed.duration_ms", - "v2_job_completed.status = 'success' as success", + "v2_job_completed.status = 'success' OR v2_job_completed.status = 'skipped' as success", "v2_job.runnable_id as script_hash", "v2_job.runnable_path as script_path", "false as deleted", diff --git a/backend/windmill-api/src/lib.rs b/backend/windmill-api/src/lib.rs index 1fea6796f66d8..57a49dc724343 100644 --- a/backend/windmill-api/src/lib.rs +++ b/backend/windmill-api/src/lib.rs @@ -34,6 +34,7 @@ use http::HeaderValue; use reqwest::Client; #[cfg(feature = "oauth2")] use std::collections::HashMap; +use tokio::task::JoinHandle; use windmill_common::global_settings::load_value_from_global_settings; use windmill_common::global_settings::EMAIL_DOMAIN_SETTING; use windmill_common::worker::HUB_CACHE_DIR; @@ -669,7 +670,8 @@ async fn openapi_json() -> &'static str { include_str!("../openapi-deref.json") } -pub async fn migrate_db(db: &DB) -> anyhow::Result<()> { - db::migrate(db).await?; - Ok(()) +pub async fn migrate_db(db: &DB) -> anyhow::Result>> { + db::migrate(db) + .await + .map_err(|e| anyhow::anyhow!("Error migrating db: {e:#}")) } diff --git a/backend/windmill-api/src/scripts.rs b/backend/windmill-api/src/scripts.rs index cbeb13e10690b..0fd80d0fe4516 100644 --- a/backend/windmill-api/src/scripts.rs +++ b/backend/windmill-api/src/scripts.rs @@ -625,6 +625,19 @@ async fn create_script_internal<'c>( } else { ns.language.clone() }; + + let (no_main_func, has_preprocessor) = match lang { + ScriptLang::Bun | ScriptLang::Bunnative | ScriptLang::Deno | ScriptLang::Nativets => { + let args = windmill_parser_ts::parse_deno_signature(&ns.content, true, true, None)?; + (args.no_main_func, args.has_preprocessor) + } + ScriptLang::Python3 => { + let args = windmill_parser_py::parse_python_signature(&ns.content, None, true)?; + (args.no_main_func, args.has_preprocessor) + } + _ => (ns.no_main_func, ns.has_preprocessor), + }; + sqlx::query!( "INSERT INTO script (workspace_id, hash, path, parent_hashes, summary, description, \ content, created_by, schema, is_template, extra_perms, lock, language, kind, tag, \ @@ -660,9 +673,9 @@ async fn create_script_internal<'c>( ns.timeout, ns.concurrency_key, ns.visible_to_runner_only, - ns.no_main_func, + no_main_func.filter(|x| *x), // should be Some(true) or None codebase, - ns.has_preprocessor, + has_preprocessor.filter(|x| *x), // should be Some(true) or None if ns.on_behalf_of_email.is_some() { Some(&authed.email) } else { diff --git a/backend/windmill-common/src/lib.rs b/backend/windmill-common/src/lib.rs index 802af6196b4a4..1bbc89072856b 100644 --- a/backend/windmill-common/src/lib.rs +++ b/backend/windmill-common/src/lib.rs @@ -155,8 +155,6 @@ pub async fn shutdown_signal( } use tokio::sync::RwLock; -#[cfg(feature = "prometheus")] -use tokio::task::JoinHandle; use utils::rd_string; #[cfg(feature = "prometheus")] @@ -164,23 +162,31 @@ pub async fn serve_metrics( addr: SocketAddr, mut rx: tokio::sync::broadcast::Receiver<()>, ready_worker_endpoint: bool, -) -> JoinHandle<()> { - use std::sync::atomic::Ordering; - + metrics_endpoint: bool, +) -> anyhow::Result<()> { + if !metrics_endpoint && !ready_worker_endpoint { + return Ok(()); + } use axum::{ routing::{get, post}, Router, }; use hyper::StatusCode; - let router = Router::new() - .route("/metrics", get(metrics)) - .route("/reset", post(reset)); + let router = Router::new(); + + let router = if metrics_endpoint { + router + .route("/metrics", get(metrics)) + .route("/reset", post(reset)) + } else { + router + }; let router = if ready_worker_endpoint { router.route( "/ready", get(|| async { - if IS_READY.load(Ordering::Relaxed) { + if IS_READY.load(std::sync::atomic::Ordering::Relaxed) { (StatusCode::OK, "ready") } else { (StatusCode::INTERNAL_SERVER_ERROR, "not ready") @@ -193,8 +199,12 @@ pub async fn serve_metrics( tokio::spawn(async move { tracing::info!("Serving metrics at: {addr}"); - let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); - if let Err(e) = axum::serve(listener, router.into_make_service()) + let listener = tokio::net::TcpListener::bind(addr).await; + if let Err(e) = listener { + tracing::error!("Error binding to metrics address: {}", e); + return; + } + if let Err(e) = axum::serve(listener.unwrap(), router.into_make_service()) .with_graceful_shutdown(async move { rx.recv().await.ok(); tracing::info!("Graceful shutdown of metrics"); @@ -204,6 +214,8 @@ pub async fn serve_metrics( tracing::error!("Error serving metrics: {}", e); } }) + .await?; + Ok(()) } #[cfg(feature = "prometheus")] diff --git a/backend/windmill-common/src/utils.rs b/backend/windmill-common/src/utils.rs index 735c3d4a27afa..0a6117999afa3 100644 --- a/backend/windmill-common/src/utils.rs +++ b/backend/windmill-common/src/utils.rs @@ -47,8 +47,11 @@ lazy_static::lazy_static! { .connect_timeout(std::time::Duration::from_secs(10)) .build().unwrap(); pub static ref GIT_SEM_VERSION: Version = Version::parse( - // skip first `v` character. - GIT_VERSION.split_at(1).1 + if GIT_VERSION.starts_with('v') { + &GIT_VERSION[1..] + } else { + GIT_VERSION + } ).unwrap_or(Version::new(0, 1, 0)); } diff --git a/backend/windmill-common/src/worker.rs b/backend/windmill-common/src/worker.rs index 487a217d7fd4a..eb5bd1d6f1c4b 100644 --- a/backend/windmill-common/src/worker.rs +++ b/backend/windmill-common/src/worker.rs @@ -657,7 +657,7 @@ pub async fn update_min_version<'c, E: sqlx::Executor<'c, Database = sqlx::Postg let min_version = pings .iter() .filter(|x| !x.is_empty()) - .filter_map(|x| semver::Version::parse(x.split_at(1).1).ok()) + .filter_map(|x| semver::Version::parse(if x.starts_with('v') { &x[1..] } else { x }).ok()) .min() .unwrap_or_else(|| cur_version.clone()); diff --git a/backend/windmill-queue/src/jobs.rs b/backend/windmill-queue/src/jobs.rs index 2d2025da921f1..e582fa39dcb2a 100644 --- a/backend/windmill-queue/src/jobs.rs +++ b/backend/windmill-queue/src/jobs.rs @@ -566,6 +566,9 @@ pub async fn add_completed_job( let result_columns = result_columns.as_ref(); let _job_id = queued_job.id; let (opt_uuid, _duration, _skip_downstream_error_handlers) = (|| async { + + // let start = std::time::Instant::now(); + let mut tx = db.begin().await?; let job_id = queued_job.id; @@ -663,7 +666,7 @@ pub async fn add_completed_job( // tracing::error!("Added completed job {:#?}", queued_job); let mut _skip_downstream_error_handlers = false; - tx = delete_job(tx, &queued_job.workspace_id, job_id).await?; + tx = delete_job(tx, &job_id).await?; // tracing::error!("3 {:?}", start.elapsed()); if queued_job.is_flow_step { @@ -858,6 +861,7 @@ pub async fn add_completed_job( "inserted completed job: {} (success: {success})", queued_job.id ); + // tracing::info!("completed job: {:?}", start.elapsed().as_micros()); Ok((None, _duration, _skip_downstream_error_handlers)) as windmill_common::error::Result<(Option, i64, bool)> }) .retry( @@ -2108,12 +2112,15 @@ async fn pull_single_job_and_mark_as_running_no_concurrency_limit<'c>( for query in queries.iter() { // tracing::info!("Pulling job with query: {}", query); + // let instant = std::time::Instant::now(); let r = sqlx::query_as::<_, PulledJob>(query) .bind(worker_name) .fetch_optional(db) .await?; if let Some(pulled_job) = r { + // tracing::info!("pulled job: {:?}", instant.elapsed().as_micros()); + highest_priority_job = Some(pulled_job); break; } @@ -2594,21 +2601,17 @@ async fn extract_result_from_job_result( pub async fn delete_job<'c>( mut tx: Transaction<'c, Postgres>, - w_id: &str, - job_id: Uuid, + job_id: &Uuid, ) -> windmill_common::error::Result> { #[cfg(feature = "prometheus")] if METRICS_ENABLED.load(std::sync::atomic::Ordering::Relaxed) { QUEUE_DELETE_COUNT.inc(); } - let job_removed = sqlx::query_scalar!( - "DELETE FROM v2_job_queue WHERE workspace_id = $1 AND id = $2 RETURNING 1", - w_id, - job_id - ) - .fetch_optional(&mut *tx) - .await; + let job_removed = + sqlx::query_scalar!("DELETE FROM v2_job_queue WHERE id = $1 RETURNING 1", job_id,) + .fetch_optional(&mut *tx) + .await; if let Err(job_removed) = job_removed { tracing::error!( diff --git a/backend/windmill-worker/nsjail/run.bash.config.proto b/backend/windmill-worker/nsjail/run.bash.config.proto index 4f86c66a329ad..63018f7655e87 100644 --- a/backend/windmill-worker/nsjail/run.bash.config.proto +++ b/backend/windmill-worker/nsjail/run.bash.config.proto @@ -21,10 +21,24 @@ mount { is_bind: true } +mount { + src: "/proc/self/fd" + dst: "/dev/fd" + is_symlink: true + mandatory: false +} + +mount { + src: "/bin" + dst: "/bin" + is_bind: true +} + mount { src: "/opt/microsoft" dst: "/opt/microsoft" is_bind: true + mandatory: false } mount { diff --git a/backend/windmill-worker/nsjail/run.powershell.config.proto b/backend/windmill-worker/nsjail/run.powershell.config.proto index 27a36548b4275..93a48d4fec583 100644 --- a/backend/windmill-worker/nsjail/run.powershell.config.proto +++ b/backend/windmill-worker/nsjail/run.powershell.config.proto @@ -21,6 +21,13 @@ mount { is_bind: true } +mount { + src: "/proc/self/fd" + dst: "/dev/fd" + is_symlink: true + mandatory: false +} + mount { src: "/opt/microsoft" dst: "/opt/microsoft" diff --git a/backend/windmill-worker/src/bash_executor.rs b/backend/windmill-worker/src/bash_executor.rs index 7b536afdae6eb..da043052b7846 100644 --- a/backend/windmill-worker/src/bash_executor.rs +++ b/backend/windmill-worker/src/bash_executor.rs @@ -96,8 +96,10 @@ cleanup() {{ # Ignore SIGTERM and SIGINT trap '' SIGTERM SIGINT + rm -f bp 2>/dev/null + # Kill the process group of the script (negative PID value) - pkill -P $$ + pkill -P $$ 2>/dev/null || true exit }} @@ -110,16 +112,19 @@ mkfifo bp # Start background processes cat bp | tail -1 >> ./result2.out & +tail_pid=$! # Run main.sh in the same process group {bash} ./main.sh "$@" 2>&1 | tee bp & - pid=$! # Wait for main.sh to finish and capture its exit status wait $pid exit_status=$? +# Ensure tail has finished before cleanup +wait $tail_pid 2>/dev/null || true + # Clean up the named pipe and background processes rm -f bp pkill -P $$ || true diff --git a/backend/windmill-worker/src/bun_executor.rs b/backend/windmill-worker/src/bun_executor.rs index 134511472fd73..ede17da758d02 100644 --- a/backend/windmill-worker/src/bun_executor.rs +++ b/backend/windmill-worker/src/bun_executor.rs @@ -951,6 +951,7 @@ pub async fn handle_bun_job( let args = windmill_parser_ts::parse_deno_signature( inner_content, true, + false, main_override.map(ToString::to_string), )? .args; @@ -960,6 +961,7 @@ pub async fn handle_bun_job( windmill_parser_ts::parse_deno_signature( inner_content, true, + false, Some("preprocessor".to_string()), )? .args, @@ -1573,7 +1575,7 @@ pub async fn start_worker( { // let mut start = Instant::now(); - let args = windmill_parser_ts::parse_deno_signature(inner_content, true, None)?.args; + let args = windmill_parser_ts::parse_deno_signature(inner_content, true, false, None)?.args; let dates = args .iter() .filter_map(|x| { diff --git a/backend/windmill-worker/src/deno_executor.rs b/backend/windmill-worker/src/deno_executor.rs index 6a7bed5c38073..40350fdeee0ff 100644 --- a/backend/windmill-worker/src/deno_executor.rs +++ b/backend/windmill-worker/src/deno_executor.rs @@ -205,6 +205,7 @@ pub async fn handle_deno_job( let args = windmill_parser_ts::parse_deno_signature( inner_content, true, + false, main_override.map(ToString::to_string), )? .args; @@ -214,6 +215,7 @@ pub async fn handle_deno_job( windmill_parser_ts::parse_deno_signature( inner_content, true, + false, Some("preprocessor".to_string()), )? .args, @@ -533,7 +535,7 @@ pub async fn start_worker( { // let mut start = Instant::now(); - let args = windmill_parser_ts::parse_deno_signature(inner_content, true, None)?.args; + let args = windmill_parser_ts::parse_deno_signature(inner_content, true, false, None)?.args; let dates = args .iter() .filter_map(|x| { diff --git a/backend/windmill-worker/src/js_eval.rs b/backend/windmill-worker/src/js_eval.rs index 9aab14429667d..50f13788e7997 100644 --- a/backend/windmill-worker/src/js_eval.rs +++ b/backend/windmill-worker/src/js_eval.rs @@ -775,7 +775,7 @@ pub async fn eval_fetch_timeout( let (sender, mut receiver) = oneshot::channel::(); - let parsed_args = windmill_parser_ts::parse_deno_signature(&ts_expr, true, None)?.args; + let parsed_args = windmill_parser_ts::parse_deno_signature(&ts_expr, true, false, None)?.args; let spread = parsed_args .into_iter() .map(|x| { diff --git a/backend/windmill-worker/src/python_executor.rs b/backend/windmill-worker/src/python_executor.rs index d86c84dd0d440..531c41887a909 100644 --- a/backend/windmill-worker/src/python_executor.rs +++ b/backend/windmill-worker/src/python_executor.rs @@ -1296,12 +1296,14 @@ async fn prepare_wrapper( let sig = windmill_parser_py::parse_python_signature( inner_content, main_override.map(ToString::to_string), + false, )?; let pre_sig = if apply_preprocessor { Some(windmill_parser_py::parse_python_signature( inner_content, Some("preprocessor".to_string()), + false, )?) } else { None @@ -1661,7 +1663,7 @@ async fn spawn_uv_install( .replace("{TARGET_DIR}", &venv_p) .replace("{CLONE_NEWUSER}", &(!*DISABLE_NUSER).to_string()), )?; - + let mut nsjail_cmd = Command::new(NSJAIL_PATH.as_str()); nsjail_cmd .current_dir(job_dir) diff --git a/backend/windmill-worker/src/worker.rs b/backend/windmill-worker/src/worker.rs index 5592e0d722ae7..590b57227c19a 100644 --- a/backend/windmill-worker/src/worker.rs +++ b/backend/windmill-worker/src/worker.rs @@ -1277,7 +1277,7 @@ pub async fn run_worker( tokio::task::spawn( (async move { tracing::info!(worker = %worker_name, hostname = %hostname, "vacuuming queue"); - if let Err(e) = sqlx::query!("VACUUM (skip_locked) v2_job_queue, v2_job_runtime, v2_job_status") + if let Err(e) = sqlx::query!("VACUUM v2_job_queue, v2_job_runtime, v2_job_status") .execute(&db2) .await { diff --git a/backend/windmill-worker/src/worker_flow.rs b/backend/windmill-worker/src/worker_flow.rs index 864f3002b1743..50f6ee8607f57 100644 --- a/backend/windmill-worker/src/worker_flow.rs +++ b/backend/windmill-worker/src/worker_flow.rs @@ -615,6 +615,7 @@ pub async fn update_flow_status_after_job_completion_internal( "error while deleting parallel_monitor_lock: {e:#}" )) })?; + if r.is_some() { tracing::info!( "parallel flow has removed lock on its parent, last ping was {:?}", diff --git a/benchmarks/benchmark_oneoff.ts b/benchmarks/benchmark_oneoff.ts index 41321b3ec66b7..6685eae1c5cf2 100644 --- a/benchmarks/benchmark_oneoff.ts +++ b/benchmarks/benchmark_oneoff.ts @@ -26,7 +26,7 @@ async function verifyOutputs(uuids: string[], workspace: string) { incorrectResults++; } if (job.result !== uuid) { - console.log(`Job ${uuid} did not output the correct value`); + console.log(`Job ${uuid} did not output the correct value: ${JSON.stringify(job)}`); incorrectResults++; } } catch (_) { @@ -37,6 +37,7 @@ async function verifyOutputs(uuids: string[], workspace: string) { console.log(`Incorrect results: ${incorrectResults}`); } +export const NON_TEST_TAGS = ["deno", "python", "go", "bash", "dedicated", "bun", "nativets", "flow"] export async function main({ host, email, @@ -96,11 +97,11 @@ export async function main({ windmill.setClient(final_token, host); const enc = (s: string) => new TextEncoder().encode(s); - async function getQueueCount() { + async function getQueueCount(tags?: string[]) { return ( await ( await fetch( - config.server + "/api/w/" + config.workspace_id + "/jobs/queue/count", + config.server + "/api/w/" + config.workspace_id + "/jobs/queue/count" + (tags && tags.length > 0 ? "?tags=" + tags.join(",") : ""), { headers: { ["Authorization"]: "Bearer " + config.token } } ) ).json() @@ -132,11 +133,11 @@ export async function main({ } let pastJobs = 0; - async function getCompletedJobsCount(): Promise { + async function getCompletedJobsCount(tags?: string[]): Promise { const completedJobs = ( await ( await fetch( - host + "/api/w/" + config.workspace_id + "/jobs/completed/count", + host + "/api/w/" + config.workspace_id + "/jobs/completed/count" + (tags && tags.length > 0 ? "?tags=" + tags.join(",") : ""), { headers: { ["Authorization"]: "Bearer " + config.token } } ) ).json() @@ -152,7 +153,6 @@ export async function main({ await createBenchScript(kind, workspace); } - pastJobs = await getCompletedJobsCount(); const jobsSent = jobs; console.log(`Bulk creating ${jobsSent} jobs`); @@ -201,18 +201,51 @@ export async function main({ kind: "rawscript", rawscript: { language: api.RawScript.language.BASH, - content: "# let's bloat that bash script, 3.. 2.. 1.. BOOM\n".repeat(25000) + "echo \"$WM_FLOW_JOB_ID\"\n", + content: "# let's bloat that bash script, 3.. 2.. 1.. BOOM\n".repeat(100) + "echo \"$WM_FLOW_JOB_ID\"\n", }, }); } else { throw new Error("Unknown script pattern " + kind); } - const response = await fetch( - config.server + + let testOtherTag = false; + if (testOtherTag) { + const otherTagTodo = 2000000; + + let parsed = JSON.parse(body); + parsed.tag = "test"; + let nbody = JSON.stringify(parsed); + let response2 = await fetch( + config.server + "/api/w/" + config.workspace_id + - `/jobs/add_batch_jobs/${jobsSent}`, + `/jobs/add_batch_jobs/${otherTagTodo}`, + { + method: "POST", + headers: { + ["Authorization"]: "Bearer " + config.token, + "Content-Type": "application/json", + }, + body: nbody, + } + ); + if (!response2.ok) { + throw new Error( + "Failed to create jobs: " + + response2.statusText + + " " + + (await response2.text()) + ); + } + } + + pastJobs = await getCompletedJobsCount(NON_TEST_TAGS); + + const response = await fetch( + config.server + + "/api/w/" + + config.workspace_id + + `/jobs/add_batch_jobs/${jobsSent}`, { method: "POST", headers: { @@ -222,20 +255,24 @@ export async function main({ body, } ); + + + + + if (!response.ok) { throw new Error( "Failed to create jobs: " + - response.statusText + - " " + - (await response.text()) + response.statusText + + " " + + (await response.text()) ); } const uuids = await response.json(); const end_create = Date.now(); const create_duration = end_create - start_create; console.log( - `Jobs successfully added to the queue in ${ - create_duration / 1000 + `Jobs successfully added to the queue in ${create_duration / 1000 }s. Windmill will start pulling them\n` ); let start = Date.now(); @@ -248,14 +285,14 @@ export async function main({ while (completedJobs < jobsSent) { const loopStart = Date.now(); if (!didStart) { - const actual_queue = await getQueueCount(); + const actual_queue = await getQueueCount(NON_TEST_TAGS); if (actual_queue < jobsSent) { start = Date.now(); didStart = true; } } else { const elapsed = start ? Date.now() - start : 0; - completedJobs = await getCompletedJobsCount(); + completedJobs = await getCompletedJobsCount(NON_TEST_TAGS); if (nStepsFlow > 0) { completedJobs = Math.floor(completedJobs / (nStepsFlow + 1)); } @@ -263,9 +300,9 @@ export async function main({ const instThr = lastElapsed > 0 ? ( - ((completedJobs - lastCompletedJobs) / (elapsed - lastElapsed)) * - 1000 - ).toFixed(2) + ((completedJobs - lastCompletedJobs) / (elapsed - lastElapsed)) * + 1000 + ).toFixed(2) : 0; lastElapsed = elapsed; @@ -275,8 +312,7 @@ export async function main({ enc( `elapsed: ${(elapsed / 1000).toFixed( 2 - )} | jobs executed: ${completedJobs}/${jobsSent} (thr: inst ${instThr} - avg ${avgThr}) | remaining: ${ - jobsSent - completedJobs + )} | jobs executed: ${completedJobs}/${jobsSent} (thr: inst ${instThr} - avg ${avgThr}) | remaining: ${jobsSent - completedJobs } \r` ) ); @@ -294,7 +330,7 @@ export async function main({ console.log(`avg. throughput (jobs/time): ${jobsSent / total_duration_sec}`); console.log("completed jobs", completedJobs); - console.log("queue length:", await getQueueCount()); + console.log("queue length:", await getQueueCount(NON_TEST_TAGS)); if ( !noVerify && diff --git a/benchmarks/benchmark_suite.ts b/benchmarks/benchmark_suite.ts index e03148ce99934..f4840dda05265 100644 --- a/benchmarks/benchmark_suite.ts +++ b/benchmarks/benchmark_suite.ts @@ -39,6 +39,7 @@ async function main({ workspace, configPath, workers, + factor }: { host: string; email?: string; @@ -47,6 +48,7 @@ async function main({ workspace: string; configPath: string; workers: number; + factor?: number; }) { async function getConfig(configPath: string): Promise { if (configPath.startsWith("http")) { @@ -77,7 +79,7 @@ async function main({ token, workspace, kind: benchmark.kind, - jobs: benchmark.jobs, + jobs: benchmark.jobs * (factor ?? 1), }); if (benchmark.noSave) { @@ -153,6 +155,9 @@ await new Command() "Number of workers that are used to run the benchmarks (only affect graph title)", { default: 1 } ) + .option("--factor ", "Factor to multiply the number of jobs by.", { + default: 1, + }) .action(main) .command( "upgrade", diff --git a/benchmarks/lib.ts b/benchmarks/lib.ts index d55c7261398d2..7e143464cbced 100644 --- a/benchmarks/lib.ts +++ b/benchmarks/lib.ts @@ -2,7 +2,7 @@ import { sleep } from "https://deno.land/x/sleep@v1.2.1/mod.ts"; import * as windmill from "https://deno.land/x/windmill@v1.174.0/mod.ts"; import * as api from "https://deno.land/x/windmill@v1.174.0/windmill-api/index.ts"; -export const VERSION = "v1.462.3"; +export const VERSION = "v1.463.6"; export async function login(email: string, password: string): Promise { return await windmill.UserService.login({ @@ -25,7 +25,7 @@ async function waitForDeployment(workspace: string, hash: string) { if (resp.lock !== null) { return; } - } catch (err) {} + } catch (err) { } await sleep(0.5); } throw new Error("Script did not deploy in time"); @@ -246,7 +246,7 @@ export const getFlowPayload = (flowPattern: string): api.FlowPreview => { input_transforms: {}, language: api.RawScript.language.BASH, type: "rawscript", - content: "# let's bloat that bash script, 3.. 2.. 1.. BOOM\n".repeat(25000) + "echo \"$WM_FLOW_JOB_ID\"\n", + content: "# let's bloat that bash script, 3.. 2.. 1.. BOOM\n".repeat(100) + `if [[ -z $\{WM_FLOW_JOB_ID+x\} ]]; then\necho "not set"\nelif [[ -z "$WM_FLOW_JOB_ID" ]]; then\necho "empty"\nelse\necho "$WM_FLOW_JOB_ID"\nfi`, }, } ], diff --git a/cli/main.ts b/cli/main.ts index 1ae97653b6c91..f5959f40edfda 100644 --- a/cli/main.ts +++ b/cli/main.ts @@ -62,7 +62,7 @@ export { // } // }); -export const VERSION = "1.462.3"; +export const VERSION = "1.463.6"; const command = new Command() .name("wmill") diff --git a/cli/metadata.ts b/cli/metadata.ts index e78b0bf539b8b..d547cee29f8c8 100644 --- a/cli/metadata.ts +++ b/cli/metadata.ts @@ -313,10 +313,16 @@ export async function updateScriptSchema( path ); metadataContent.schema = result.schema; - if (result.has_preprocessor == true) + if (result.has_preprocessor) { metadataContent.has_preprocessor = result.has_preprocessor; - if (result.no_main_func === true) + } else { + delete metadataContent.has_preprocessor; + } + if (result.no_main_func) { metadataContent.no_main_func = result.no_main_func; + } else { + delete metadataContent.no_main_func; + } } async function updateScriptLock( @@ -441,7 +447,11 @@ export function inferSchema( content: string, currentSchema: any, path: string -) { +): { + schema: any; + has_preprocessor: boolean | undefined; + no_main_func: boolean | undefined; +} { let inferedSchema: any; if (language === "python3") { inferedSchema = JSON.parse(parse_python(content)); diff --git a/docker-compose.yml b/docker-compose.yml index df2a99b38d01c..a8ac7ba565fd7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,5 +1,12 @@ version: "3.7" +x-logging: &default-logging + driver: "json-file" + options: + max-size: "${LOG_MAX_SIZE:-20m}" + max-file: "${LOG_MAX_FILE:-10}" + compress: "true" + services: db: deploy: @@ -22,6 +29,7 @@ services: interval: 10s timeout: 5s retries: 5 + logging: *default-logging windmill_server: image: ${WM_IMAGE} @@ -40,6 +48,7 @@ services: condition: service_healthy volumes: - worker_logs:/tmp/windmill/logs + logging: *default-logging windmill_worker: image: ${WM_IMAGE} @@ -65,6 +74,7 @@ services: - /var/run/docker.sock:/var/run/docker.sock - worker_dependency_cache:/tmp/windmill/cache - worker_logs:/tmp/windmill/logs + logging: *default-logging ## This worker is specialized for "native" jobs. Native jobs run in-process and thus are much more lightweight than other jobs windmill_worker_native: @@ -90,6 +100,7 @@ services: condition: service_healthy volumes: - worker_logs:/tmp/windmill/logs + logging: *default-logging # This worker is specialized for reports or scraping jobs. It is assigned the "reports" worker group which has an init script that installs chromium and can be targeted by using the "chromium" worker tag. # windmill_worker_reports: # image: ${WM_IMAGE} @@ -135,6 +146,7 @@ services: volumes: - windmill_index:/tmp/windmill/search - worker_logs:/tmp/windmill/logs + logging: *default-logging lsp: image: ghcr.io/windmill-labs/windmill-lsp:latest @@ -144,6 +156,7 @@ services: - 3001 volumes: - lsp_cache:/pyls/.cache + logging: *default-logging multiplayer: image: ghcr.io/windmill-labs/windmill-multiplayer:latest @@ -152,6 +165,7 @@ services: restart: unless-stopped expose: - 3002 + logging: *default-logging caddy: image: ghcr.io/windmill-labs/caddy-l4:latest @@ -170,6 +184,7 @@ services: - BASE_URL=":80" # - BASE_URL=":443" # uncomment and comment line above to enable HTTPS via custom certificate and key files # - BASE_URL=mydomain.com # Uncomment and comment line above to enable HTTPS handling by Caddy + logging: *default-logging volumes: db_data: null diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 87f3664686b95..54f84d32a8784 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "windmill-components", - "version": "1.462.3", + "version": "1.463.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "windmill-components", - "version": "1.462.3", + "version": "1.463.6", "license": "AGPL-3.0", "dependencies": { "@anthropic-ai/sdk": "^0.32.1", diff --git a/frontend/package.json b/frontend/package.json index 14762e9b43a9e..d99d4ad864016 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "windmill-components", - "version": "1.462.3", + "version": "1.463.6", "scripts": { "dev": "vite dev", "build": "vite build", diff --git a/frontend/src/lib/components/ConnectionSection.svelte b/frontend/src/lib/components/ConnectionSection.svelte index 104d6527b54e6..c0ad6eea20eeb 100644 --- a/frontend/src/lib/components/ConnectionSection.svelte +++ b/frontend/src/lib/components/ConnectionSection.svelte @@ -35,7 +35,7 @@ isFetching = false } - $: workspaceStore && platform && $enterpriseLicense === 'teams' && loadTeams() + $: workspaceStore && platform && $enterpriseLicense && loadTeams() async function connectTeams() { const selectedTeam = teams.find((team) => team.team_id === selected_teams_team) diff --git a/frontend/src/lib/components/FlowJobResult.svelte b/frontend/src/lib/components/FlowJobResult.svelte index cd8337238989b..ca071370a4048 100644 --- a/frontend/src/lib/components/FlowJobResult.svelte +++ b/frontend/src/lib/components/FlowJobResult.svelte @@ -29,17 +29,21 @@ $: jobId != lastJobId && diffJobId() + let iteration = 0 + let logOffset = 0 + async function diffJobId() { if (jobId != lastJobId) { lastJobId = jobId logs = undefined logOffset = 0 + iteration = 0 getLogs() } } - let logOffset = 0 async function getLogs() { + iteration += 1 if (jobId) { const getUpdate = await JobService.getJobUpdates({ workspace: workspaceId ?? $workspaceStore!, @@ -51,11 +55,14 @@ logOffset = getUpdate.log_offset ?? 0 } if (refreshLog) { - setTimeout(() => { - if (refreshLog) { - getLogs() - } - }, 1000) + setTimeout( + () => { + if (refreshLog) { + getLogs() + } + }, + iteration < 10 ? 1000 : iteration < 20 ? 2000 : 5000 + ) } } @@ -69,7 +76,7 @@ class:border={!noBorder} class="grid {!col ? 'grid-cols-2' - : 'grid-rows-2'} shadow border border-tertiary-inverse grow overflow-hidden" + : 'grid-rows-2 max-h-screen'} shadow border border-tertiary-inverse grow overflow-hidden" >
Result diff --git a/frontend/src/lib/components/FlowStatusViewerInner.svelte b/frontend/src/lib/components/FlowStatusViewerInner.svelte index 5f9faa8ed9eff..d356196aa3006 100644 --- a/frontend/src/lib/components/FlowStatusViewerInner.svelte +++ b/frontend/src/lib/components/FlowStatusViewerInner.svelte @@ -88,7 +88,7 @@ flowJobIds?.flowJobs?.map((x, id) => `iter #${id + 1} not loaded by frontend yet`) ?? [] let retry_selected = '' - let timeout: NodeJS.Timeout + let timeout: NodeJS.Timeout | undefined = undefined let localModuleStates: Writable> = writable({}) let localDurationStatuses: Writable> = writable({}) @@ -403,7 +403,7 @@ } } - $: isForloopSelected && globalModuleStates && loadJobInProgress() + $: isForloopSelected && globalModuleStates && debounceLoadJobInProgress() async function getNewJob(jobId: string, initialJob: Job | undefined) { if ( @@ -421,10 +421,33 @@ } } + let debounceJobId: string | undefined = undefined + let lastRefreshed: Date | undefined = undefined + function debounceLoadJobInProgress() { + const pollingRate = reducedPolling ? 5000 : 1000 + if ( + lastRefreshed && + new Date().getTime() - lastRefreshed.getTime() < pollingRate && + debounceJobId == jobId + ) { + timeout && clearTimeout(timeout) + } + timeout = setTimeout(() => { + loadJobInProgress() + lastRefreshed = new Date() + debounceJobId = jobId + timeout = undefined + }, pollingRate) + } + let errorCount = 0 let notAnonynmous = false + let started = false async function loadJobInProgress() { - dispatch('start') + if (!started) { + started = true + dispatch('start') + } if (jobId != '00000000-0000-0000-0000-000000000000') { try { const newJob = await getNewJob(jobId, initialJob) @@ -447,7 +470,7 @@ } } if (job?.type !== 'CompletedJob' && errorCount < 4 && !destroyed) { - timeout = setTimeout(() => loadJobInProgress(), reducedPolling ? 5000 : 1000) + debounceLoadJobInProgress() } else { dispatch('done', job) } @@ -1286,7 +1309,7 @@ durationStatuses={localDurationStatuses} /> {:else if rightColumnSelect == 'node_status'} -
+
{#if selectedNode} {@const node = $localModuleStates[selectedNode]} @@ -1365,7 +1388,6 @@ />
{/if} - {#if $values[setting.key]} +
+
- {#if category == 'SMTP'} - {@const smtp = $values['smtp_settings']} -
-
- {/if} {/each} diff --git a/frontend/src/lib/components/ScheduleEditorInner.svelte b/frontend/src/lib/components/ScheduleEditorInner.svelte index 4d19aa19910c2..722354c8df72b 100644 --- a/frontend/src/lib/components/ScheduleEditorInner.svelte +++ b/frontend/src/lib/components/ScheduleEditorInner.svelte @@ -344,7 +344,6 @@ failedTimes = s.on_failure_times ?? 1 failedExact = s.on_failure_exact ?? false errorHandlerExtraArgs = s.on_failure_extra_args ?? {} - console.log('errorHandlerExtraArgs', errorHandlerExtraArgs) errorHandlerSelected = getHandlerType('error', errorHandlerPath) } else { errorHandlerPath = undefined diff --git a/frontend/src/lib/components/runs/JobLoader.svelte b/frontend/src/lib/components/runs/JobLoader.svelte index 66637842c565f..5789cdc76d48b 100644 --- a/frontend/src/lib/components/runs/JobLoader.svelte +++ b/frontend/src/lib/components/runs/JobLoader.svelte @@ -95,20 +95,7 @@ return jobKinds } if (jobKindsCat == 'all') { - let kinds: CompletedJob['job_kind'][] = [ - 'script', - 'flow', - 'dependencies', - 'flowdependencies', - 'appdependencies', - 'preview', - 'flowpreview', - 'script_hub', - 'flowscript', - 'flownode', - 'appscript' - ] - return kinds.join(',') + return '' } else if (jobKindsCat == 'dependencies') { let kinds: CompletedJob['job_kind'][] = [ 'dependencies', @@ -122,6 +109,9 @@ } else if (jobKindsCat == 'deploymentcallbacks') { let kinds: CompletedJob['job_kind'][] = ['deploymentcallback'] return kinds.join(',') + } else if (jobKindsCat == 'runs') { + let kinds: CompletedJob['job_kind'][] = ['script', 'flow', 'singlescriptflow'] + return kinds.join(',') } else { let kinds: CompletedJob['job_kind'][] = [ 'script', @@ -170,7 +160,7 @@ createdBefore, createdBy: user === null || user === '' ? undefined : user, scriptPathStart: scriptPathStart, - jobKinds, + jobKinds: jobKindsCat == 'all' || jobKinds == '' ? undefined : jobKinds, success: success == 'success' ? true : success == 'failure' ? false : undefined, running: success == 'running' || success == 'suspended' @@ -228,7 +218,7 @@ scriptPathExact: path === null || path === '' ? undefined : path, createdBy: user === null || user === '' ? undefined : user, scriptPathStart: folder === null || folder === '' ? undefined : `f/${folder}/`, - jobKinds, + jobKinds: jobKindsCat == 'all' || jobKinds == '' ? undefined : jobKinds, success: success == 'success' ? true : success == 'failure' ? false : undefined, running: success == 'running' ? true : undefined, isSkipped: isSkipped ? undefined : false, diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts index 71eecc14a342a..d32b18d594895 100644 --- a/frontend/src/lib/utils.ts +++ b/frontend/src/lib/utils.ts @@ -1099,6 +1099,14 @@ export function isFlowPreview(job_kind: Job['job_kind'] | undefined) { return !!job_kind && (job_kind === 'flowpreview' || job_kind === 'flownode') } +export function isNotFlow(job_kind: Job['job_kind'] | undefined) { + return ( + job_kind !== 'flow' && + job_kind !== 'singlescriptflow' && + !isFlowPreview(job_kind) + ) +} + export function isScriptPreview(job_kind: Job['job_kind'] | undefined) { return ( !!job_kind && (job_kind === 'preview' || job_kind === 'flowscript' || job_kind === 'appscript') diff --git a/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte b/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte index 7d9d8da47c63f..d7a8fdb365878 100644 --- a/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/run/[...run]/+page.svelte @@ -20,6 +20,7 @@ emptyString, encodeState, isFlowPreview, + isNotFlow, isScriptPreview, truncateHash, truncateRev @@ -119,7 +120,7 @@ let showExplicitProgressTip: boolean = (localStorage.getItem('hideExplicitProgressTip') ?? 'false') == 'false' - $: job?.logs == undefined && job && viewTab == 'logs' && getLogs?.() + $: job?.logs == undefined && job && viewTab == 'logs' && isNotFlow(job?.job_kind) && getLogs?.() let lastJobId: string | undefined = undefined let concurrencyKey: string | undefined = undefined @@ -222,24 +223,33 @@ }) } - if (job === undefined || job.job_kind !== 'script' || job.script_hash === undefined) { - return - } - const script = await ScriptService.getScriptByHash({ - workspace: $workspaceStore!, - hash: job.script_hash - }) - if (script.restart_unless_cancelled ?? false) { - persistentScriptDefinition = script + if ( + job && + job.job_kind === 'script' && + job.script_hash && + persistentScriptDefinition === undefined + ) { + const script = await ScriptService.getScriptByHash({ + workspace: $workspaceStore!, + hash: job.script_hash + }) + if (script.restart_unless_cancelled ?? false) { + persistentScriptDefinition = script + } } } - $: { - if ($workspaceStore && $page.params.run && testJobLoader) { - forceCancel = false - getJob() - } + function onRunsPageChangeWithLoader() { + forceCancel = false + getJob() + } + + function onRunsPageChange() { + job = undefined + persistentScriptDefinition = undefined } + $: $workspaceStore && $page.params.run && onRunsPageChange() + $: $workspaceStore && $page.params.run && testJobLoader && onRunsPageChangeWithLoader() $: selectedJobStep !== undefined && onSelectedJobStepChange() $: job && onJobLoaded() @@ -388,19 +398,20 @@ {/if} - - job?.['result'] != undefined && (viewTab = 'result')} - bind:this={testJobLoader} - bind:getLogs - bind:isLoading={testIsLoading} - bind:job - bind:jobUpdateLastFetch - workspaceOverride={$workspaceStore} - bind:notfound -/> +{#if !job || (job?.job_kind != 'flow' && job?.job_kind != 'flownode' && job?.job_kind != 'flowpreview')} + job?.['result'] != undefined && (viewTab = 'result')} + bind:this={testJobLoader} + bind:getLogs + bind:isLoading={testIsLoading} + bind:job + bind:jobUpdateLastFetch + workspaceOverride={$workspaceStore} + bind:notfound + /> +{/if} @@ -841,7 +852,7 @@

Scheduled to be executed later: {displayDate(job?.['scheduled_for'])}

{/if} - {#if job?.job_kind !== 'flow' && job?.job_kind !== 'singlescriptflow' && !isFlowPreview(job?.job_kind)} + {#if isNotFlow(job?.job_kind)} {#if ['python3', 'bun', 'deno'].includes(job?.language ?? '') && (job?.job_kind == 'script' || isScriptPreview(job?.job_kind))} {/if} @@ -922,6 +933,9 @@ on:jobsLoaded={({ detail }) => { job = detail }} + on:done={(e) => { + job = e.detail + }} initialJob={job} workspaceId={$workspaceStore} bind:selectedJobStep diff --git a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte index 55726138c0234..1a060debfb3b0 100644 --- a/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte +++ b/frontend/src/routes/(root)/(logged)/workspace_settings/+page.svelte @@ -447,11 +447,14 @@ if (emptyString($enterpriseLicense)) { errorHandlerSelected = 'custom' } else { - errorHandlerSelected = - emptyString(errorHandlerScriptPath) ? 'custom' : - (errorHandlerScriptPath.startsWith('hub/') && errorHandlerScriptPath.endsWith('/workspace-or-schedule-error-handler-slack')) ? 'slack' : - (errorHandlerScriptPath.endsWith('/workspace-or-schedule-error-handler-teams')) ? 'teams' : - 'custom' + errorHandlerSelected = emptyString(errorHandlerScriptPath) + ? 'custom' + : errorHandlerScriptPath.startsWith('hub/') && + errorHandlerScriptPath.endsWith('/workspace-or-schedule-error-handler-slack') + ? 'slack' + : errorHandlerScriptPath.endsWith('/workspace-or-schedule-error-handler-teams') + ? 'teams' + : 'custom' } errorHandlerExtraArgs = settings.error_handler_extra_args ?? {} workspaceDefaultAppPath = settings.default_app @@ -812,8 +815,8 @@ {#if !$enterpriseLicense}
- Workspace Teams commands is a Windmill EE feature. It enables using your current Slack / Teams - connection to run a custom script and send notifications. + Workspace Teams commands is a Windmill EE feature. It enables using your current Slack + / Teams connection to run a custom script and send notifications.
{/if} @@ -867,12 +870,7 @@
- {#if $superadmin} -

- When deleting the workspace, it will be archived for a short period of time and then - permanently deleted. -

- {:else} + {#if !$superadmin}

Only instance superadmins can delete a workspace.

{/if} {#if $workspaceStore === 'admins' || $workspaceStore === 'starter'} diff --git a/lsp/Pipfile b/lsp/Pipfile index 15339d6e59861..9a995b30c039a 100644 --- a/lsp/Pipfile +++ b/lsp/Pipfile @@ -4,8 +4,8 @@ verify_ssl = true name = "pypi" [packages] -wmill = ">=1.462.3" -wmill_pg = ">=1.462.3" +wmill = ">=1.463.6" +wmill_pg = ">=1.463.6" sendgrid = "*" mysql-connector-python = "*" pymongo = "*" diff --git a/openflow.openapi.yaml b/openflow.openapi.yaml index 18bc00e8476d9..28babee7c4499 100644 --- a/openflow.openapi.yaml +++ b/openflow.openapi.yaml @@ -1,7 +1,7 @@ openapi: "3.0.3" info: - version: 1.462.3 + version: 1.463.6 title: OpenFlow Spec contact: name: Ruben Fiszel diff --git a/powershell-client/WindmillClient/WindmillClient.psd1 b/powershell-client/WindmillClient/WindmillClient.psd1 index 13f17174b8622..6680bc5b846e9 100644 --- a/powershell-client/WindmillClient/WindmillClient.psd1 +++ b/powershell-client/WindmillClient/WindmillClient.psd1 @@ -12,7 +12,7 @@ RootModule = 'WindmillClient.psm1' # Version number of this module. - ModuleVersion = '1.462.3' + ModuleVersion = '1.463.6' # Supported PSEditions # CompatiblePSEditions = @() diff --git a/python-client/wmill/pyproject.toml b/python-client/wmill/pyproject.toml index 7b7cdcbd0bece..a19e6e3280371 100644 --- a/python-client/wmill/pyproject.toml +++ b/python-client/wmill/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill" -version = "1.462.3" +version = "1.463.6" description = "A client library for accessing Windmill server wrapping the Windmill client API" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/python-client/wmill_pg/pyproject.toml b/python-client/wmill_pg/pyproject.toml index 10fcb541c62db..78a5a89f9d359 100644 --- a/python-client/wmill_pg/pyproject.toml +++ b/python-client/wmill_pg/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "wmill-pg" -version = "1.462.3" +version = "1.463.6" description = "An extension client for the wmill client library focused on pg" license = "Apache-2.0" homepage = "https://windmill.dev" diff --git a/typescript-client/jsr.json b/typescript-client/jsr.json index 71c58a044dc77..15c80ae5339d9 100644 --- a/typescript-client/jsr.json +++ b/typescript-client/jsr.json @@ -1,6 +1,6 @@ { "name": "@windmill/windmill", - "version": "1.462.3", + "version": "1.463.6", "exports": "./src/index.ts", "publish": { "exclude": ["!src", "./s3Types.ts", "./client.ts"] diff --git a/typescript-client/package.json b/typescript-client/package.json index ed36b757b99b3..23a2b2a3c0238 100644 --- a/typescript-client/package.json +++ b/typescript-client/package.json @@ -1,7 +1,7 @@ { "name": "windmill-client", "description": "Windmill SDK client for browsers and Node.js", - "version": "1.462.3", + "version": "1.463.6", "author": "Ruben Fiszel", "license": "Apache 2.0", "devDependencies": { diff --git a/version.txt b/version.txt index 7cce9443de8d1..225d2d44c31e5 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.462.3 +1.463.6