From ef75ed3df7bf99e735a579291078f4ea9db4fcf6 Mon Sep 17 00:00:00 2001 From: dieriba Date: Tue, 23 Sep 2025 21:22:54 +0200 Subject: [PATCH] feat: websocket trigger send runnable result even if error (#6664) * done * nits * update sqlx --------- Co-authored-by: hugocasa --- ...1f7f387f5055c47f493271d26731336257384.json | 10 +-- ...cc6d6bf1df758b30e99bd661da866062ef14f.json | 23 ----- ...5f1a9036b6005764b79c415373a5d39c3211.json} | 4 +- ...94f91df7e588d4d2431bc85f4d8734920c8bf.json | 51 ----------- ...c38fc64deb1226aab9dc3bc4465324fce37d1.json | 16 ---- ...9e786fe78dd21721e8f54dc943dd571a7e08.json} | 5 +- ...ca3761d400391f1f46a8294da3e6c9af63887.json | 15 ---- ...5ef756b8e5c1955fbe111df9ee171dc262338.json | 89 ------------------- ...0cb549a34b96554ae1872355b90304f5dcb76.json | 4 +- ...212a5bd4039b57fab20b163617e33a4c9dd46.json | 14 --- ...e58936138d80a97b423c17338ba069b6a3aa.json} | 5 +- ...77afbd8b3a660b3be27514b517c077c63c238.json | 89 ------------------- ...websocket_can_return_error_result.down.sql | 2 + ...7_websocket_can_return_error_result.up.sql | 2 + backend/windmill-api/openapi.yaml | 9 ++ backend/windmill-api/src/jobs.rs | 11 ++- .../src/triggers/trigger_helpers.rs | 32 ++++++- .../src/triggers/websocket/handler.rs | 15 ++-- .../src/triggers/websocket/listener.rs | 16 +++- .../src/triggers/websocket/mod.rs | 7 +- .../WebsocketTriggerEditorInner.svelte | 23 +++++ .../components/triggers/websocket/utils.ts | 1 + 22 files changed, 118 insertions(+), 325 deletions(-) delete mode 100644 backend/.sqlx/query-16e4b1bead9fc77fd98658b8cb8cc6d6bf1df758b30e99bd661da866062ef14f.json rename backend/.sqlx/{query-d6f62e25faf271876874fc09ee460313159bb6ad91227f5dec37cd28006e2add.json => query-79d6b757c9556cfcf0c98f52035b5f1a9036b6005764b79c415373a5d39c3211.json} (54%) delete mode 100644 backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json delete mode 100644 backend/.sqlx/query-85705fc3d7f8ba5f1b12d5fb222c38fc64deb1226aab9dc3bc4465324fce37d1.json rename backend/.sqlx/{query-23eb4d45bf2df21e22fc6c9590b96b0a7dbdd27f85c7d886eded79b3af83731a.json => query-9ebf262393fc4a29e8f09b304dd99e786fe78dd21721e8f54dc943dd571a7e08.json} (65%) delete mode 100644 backend/.sqlx/query-a0b3e10e077d30c1da135dff9feca3761d400391f1f46a8294da3e6c9af63887.json delete mode 100644 backend/.sqlx/query-ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338.json delete mode 100644 backend/.sqlx/query-b4a9abcb38997587b28655b0f4a212a5bd4039b57fab20b163617e33a4c9dd46.json rename backend/.sqlx/{query-35b211d19e53da4b64b0bd097284de3236ab939e47a1fc2b15ffc9607b552f8d.json => query-b5f6870444fc97d8beab3cf61c91e58936138d80a97b423c17338ba069b6a3aa.json} (67%) delete mode 100644 backend/.sqlx/query-ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238.json create mode 100644 backend/migrations/20250923094837_websocket_can_return_error_result.down.sql create mode 100644 backend/migrations/20250923094837_websocket_can_return_error_result.up.sql diff --git a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json index d29a18c691..e7ed0aee65 100644 --- a/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json +++ b/backend/.sqlx/query-07168aaf14cb6beff0ad4274b441f7f387f5055c47f493271d26731336257384.json @@ -46,11 +46,11 @@ ] }, "nullable": [ - true, - true, - true, - true, - true, + false, + false, + false, + false, + false, true, true ] diff --git a/backend/.sqlx/query-16e4b1bead9fc77fd98658b8cb8cc6d6bf1df758b30e99bd661da866062ef14f.json b/backend/.sqlx/query-16e4b1bead9fc77fd98658b8cb8cc6d6bf1df758b30e99bd661da866062ef14f.json deleted file mode 100644 index 1af42ff529..0000000000 --- a/backend/.sqlx/query-16e4b1bead9fc77fd98658b8cb8cc6d6bf1df758b30e99bd661da866062ef14f.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "SELECT hash FROM script WHERE path = $1 AND workspace_id = $2", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "hash", - "type_info": "Int8" - } - ], - "parameters": { - "Left": [ - "Text", - "Text" - ] - }, - "nullable": [ - false - ] - }, - "hash": "16e4b1bead9fc77fd98658b8cb8cc6d6bf1df758b30e99bd661da866062ef14f" -} diff --git a/backend/.sqlx/query-d6f62e25faf271876874fc09ee460313159bb6ad91227f5dec37cd28006e2add.json b/backend/.sqlx/query-79d6b757c9556cfcf0c98f52035b5f1a9036b6005764b79c415373a5d39c3211.json similarity index 54% rename from backend/.sqlx/query-d6f62e25faf271876874fc09ee460313159bb6ad91227f5dec37cd28006e2add.json rename to backend/.sqlx/query-79d6b757c9556cfcf0c98f52035b5f1a9036b6005764b79c415373a5d39c3211.json index c4c138a886..7b0d64c691 100644 --- a/backend/.sqlx/query-d6f62e25faf271876874fc09ee460313159bb6ad91227f5dec37cd28006e2add.json +++ b/backend/.sqlx/query-79d6b757c9556cfcf0c98f52035b5f1a9036b6005764b79c415373a5d39c3211.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n result AS \"result: sqlx::types::Json>\",\n result_columns,\n status = 'success' AS \"success!\"\n FROM v2_job_completed\n WHERE id = $1 AND workspace_id = $2", + "query": "\n SELECT\n result AS \"result: sqlx::types::Json>\",\n result_columns,\n status = 'success' AS \"success!\"\n FROM \n v2_job_completed\n WHERE \n id = $1 AND \n workspace_id = $2\n ", "describe": { "columns": [ { @@ -31,5 +31,5 @@ null ] }, - "hash": "d6f62e25faf271876874fc09ee460313159bb6ad91227f5dec37cd28006e2add" + "hash": "79d6b757c9556cfcf0c98f52035b5f1a9036b6005764b79c415373a5d39c3211" } diff --git a/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json b/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json deleted file mode 100644 index 6f08d98113..0000000000 --- a/backend/.sqlx/query-804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO script (summary, description, dedicated_worker, content, workspace_id, path, hash, language, tag, created_by, lock) VALUES ('', '', true, $1, $2, $3, $4, $5, $6, $7, '') ON CONFLICT (workspace_id, hash) DO NOTHING", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "Text", - "Varchar", - "Varchar", - "Int8", - { - "Custom": { - "name": "script_lang", - "kind": { - "Enum": [ - "python3", - "deno", - "go", - "bash", - "postgresql", - "nativets", - "bun", - "mysql", - "bigquery", - "snowflake", - "graphql", - "powershell", - "mssql", - "php", - "bunnative", - "rust", - "ansible", - "csharp", - "oracledb", - "nu", - "java", - "duckdb", - "ruby" - ] - } - } - }, - "Varchar", - "Varchar" - ] - }, - "nullable": [] - }, - "hash": "804fc11e35f4afc0db194b6fe2594f91df7e588d4d2431bc85f4d8734920c8bf" -} diff --git a/backend/.sqlx/query-85705fc3d7f8ba5f1b12d5fb222c38fc64deb1226aab9dc3bc4465324fce37d1.json b/backend/.sqlx/query-85705fc3d7f8ba5f1b12d5fb222c38fc64deb1226aab9dc3bc4465324fce37d1.json deleted file mode 100644 index bce7324fb6..0000000000 --- a/backend/.sqlx/query-85705fc3d7f8ba5f1b12d5fb222c38fc64deb1226aab9dc3bc4465324fce37d1.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO v2_job_queue (id, workspace_id, scheduled_for, tag) SELECT unnest($1::uuid[]), $2, now(), $3", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "UuidArray", - "Varchar", - "Varchar" - ] - }, - "nullable": [] - }, - "hash": "85705fc3d7f8ba5f1b12d5fb222c38fc64deb1226aab9dc3bc4465324fce37d1" -} diff --git a/backend/.sqlx/query-23eb4d45bf2df21e22fc6c9590b96b0a7dbdd27f85c7d886eded79b3af83731a.json b/backend/.sqlx/query-9ebf262393fc4a29e8f09b304dd99e786fe78dd21721e8f54dc943dd571a7e08.json similarity index 65% rename from backend/.sqlx/query-23eb4d45bf2df21e22fc6c9590b96b0a7dbdd27f85c7d886eded79b3af83731a.json rename to backend/.sqlx/query-9ebf262393fc4a29e8f09b304dd99e786fe78dd21721e8f54dc943dd571a7e08.json index ecaefdeb62..53c7562d03 100644 --- a/backend/.sqlx/query-23eb4d45bf2df21e22fc6c9590b96b0a7dbdd27f85c7d886eded79b3af83731a.json +++ b/backend/.sqlx/query-9ebf262393fc4a29e8f09b304dd99e786fe78dd21721e8f54dc943dd571a7e08.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n INSERT INTO websocket_trigger (\n workspace_id,\n path,\n url,\n script_path,\n is_flow,\n enabled,\n filters,\n initial_messages,\n url_runnable_args,\n edited_by,\n can_return_message,\n email,\n edited_at,\n error_handler_path,\n error_handler_args,\n retry\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, now(), $13, $14, $15\n )\n ", + "query": "\n INSERT INTO websocket_trigger (\n workspace_id,\n path,\n url,\n script_path,\n is_flow,\n enabled,\n filters,\n initial_messages,\n url_runnable_args,\n edited_by,\n can_return_message,\n can_return_error_result,\n email,\n edited_at,\n error_handler_path,\n error_handler_args,\n retry\n ) VALUES (\n $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, now(), $14, $15, $16\n )\n ", "describe": { "columns": [], "parameters": { @@ -16,6 +16,7 @@ "Jsonb", "Varchar", "Bool", + "Bool", "Varchar", "Varchar", "Jsonb", @@ -24,5 +25,5 @@ }, "nullable": [] }, - "hash": "23eb4d45bf2df21e22fc6c9590b96b0a7dbdd27f85c7d886eded79b3af83731a" + "hash": "9ebf262393fc4a29e8f09b304dd99e786fe78dd21721e8f54dc943dd571a7e08" } diff --git a/backend/.sqlx/query-a0b3e10e077d30c1da135dff9feca3761d400391f1f46a8294da3e6c9af63887.json b/backend/.sqlx/query-a0b3e10e077d30c1da135dff9feca3761d400391f1f46a8294da3e6c9af63887.json deleted file mode 100644 index 1afc61978e..0000000000 --- a/backend/.sqlx/query-a0b3e10e077d30c1da135dff9feca3761d400391f1f46a8294da3e6c9af63887.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO v2_job_status (id, flow_status) SELECT unnest($1::uuid[]), $2", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "UuidArray", - "Jsonb" - ] - }, - "nullable": [] - }, - "hash": "a0b3e10e077d30c1da135dff9feca3761d400391f1f46a8294da3e6c9af63887" -} diff --git a/backend/.sqlx/query-ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338.json b/backend/.sqlx/query-ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338.json deleted file mode 100644 index e07a3ccdd7..0000000000 --- a/backend/.sqlx/query-ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO v2_job (id, runnable_id, runnable_path, kind, script_lang, tag, created_by, permissioned_as, permissioned_as_email, workspace_id, raw_flow) (SELECT gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9, $10 FROM generate_series(1, 1)) RETURNING id", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Uuid" - } - ], - "parameters": { - "Left": [ - "Int8", - "Varchar", - { - "Custom": { - "name": "job_kind", - "kind": { - "Enum": [ - "script", - "preview", - "flow", - "dependencies", - "flowpreview", - "script_hub", - "identity", - "flowdependencies", - "http", - "graphql", - "postgresql", - "noop", - "appdependencies", - "deploymentcallback", - "singlescriptflow", - "flowscript", - "flownode", - "appscript", - "aiagent" - ] - } - } - }, - { - "Custom": { - "name": "script_lang", - "kind": { - "Enum": [ - "python3", - "deno", - "go", - "bash", - "postgresql", - "nativets", - "bun", - "mysql", - "bigquery", - "snowflake", - "graphql", - "powershell", - "mssql", - "php", - "bunnative", - "rust", - "ansible", - "csharp", - "oracledb", - "nu", - "java", - "duckdb", - "ruby" - ] - } - } - }, - "Varchar", - "Varchar", - "Varchar", - "Varchar", - "Varchar", - "Jsonb" - ] - }, - "nullable": [ - false - ] - }, - "hash": "ab04cda71f8e2be9acbecabe1ee5ef756b8e5c1955fbe111df9ee171dc262338" -} diff --git a/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json b/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json index 99269c9851..54e94cfb8f 100644 --- a/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json +++ b/backend/.sqlx/query-b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76.json @@ -18,8 +18,8 @@ "Left": [] }, "nullable": [ - true, - false + false, + true ] }, "hash": "b3dbdfb50ee8118bdaed3164b210cb549a34b96554ae1872355b90304f5dcb76" diff --git a/backend/.sqlx/query-b4a9abcb38997587b28655b0f4a212a5bd4039b57fab20b163617e33a4c9dd46.json b/backend/.sqlx/query-b4a9abcb38997587b28655b0f4a212a5bd4039b57fab20b163617e33a4c9dd46.json deleted file mode 100644 index a49baeefaf..0000000000 --- a/backend/.sqlx/query-b4a9abcb38997587b28655b0f4a212a5bd4039b57fab20b163617e33a4c9dd46.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO v2_job_runtime (id) SELECT unnest($1::uuid[])", - "describe": { - "columns": [], - "parameters": { - "Left": [ - "UuidArray" - ] - }, - "nullable": [] - }, - "hash": "b4a9abcb38997587b28655b0f4a212a5bd4039b57fab20b163617e33a4c9dd46" -} diff --git a/backend/.sqlx/query-35b211d19e53da4b64b0bd097284de3236ab939e47a1fc2b15ffc9607b552f8d.json b/backend/.sqlx/query-b5f6870444fc97d8beab3cf61c91e58936138d80a97b423c17338ba069b6a3aa.json similarity index 67% rename from backend/.sqlx/query-35b211d19e53da4b64b0bd097284de3236ab939e47a1fc2b15ffc9607b552f8d.json rename to backend/.sqlx/query-b5f6870444fc97d8beab3cf61c91e58936138d80a97b423c17338ba069b6a3aa.json index aa52f752ae..1d8fa42e31 100644 --- a/backend/.sqlx/query-35b211d19e53da4b64b0bd097284de3236ab939e47a1fc2b15ffc9607b552f8d.json +++ b/backend/.sqlx/query-b5f6870444fc97d8beab3cf61c91e58936138d80a97b423c17338ba069b6a3aa.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "\n UPDATE \n websocket_trigger\n SET\n url = $1,\n script_path = $2,\n path = $3,\n is_flow = $4,\n filters = $5,\n initial_messages = $6,\n url_runnable_args = $7,\n edited_by = $8,\n email = $9,\n can_return_message = $10,\n edited_at = now(),\n server_id = NULL,\n error = NULL,\n error_handler_path = $13,\n error_handler_args = $14,\n retry = $15\n WHERE\n workspace_id = $11 AND path = $12\n ", + "query": "\n UPDATE \n websocket_trigger\n SET\n url = $1,\n script_path = $2,\n path = $3,\n is_flow = $4,\n filters = $5,\n initial_messages = $6,\n url_runnable_args = $7,\n edited_by = $8,\n email = $9,\n can_return_message = $10,\n can_return_error_result = $11,\n edited_at = now(),\n server_id = NULL,\n error = NULL,\n error_handler_path = $14,\n error_handler_args = $15,\n retry = $16\n WHERE\n workspace_id = $12 AND path = $13\n ", "describe": { "columns": [], "parameters": { @@ -15,6 +15,7 @@ "Varchar", "Varchar", "Bool", + "Bool", "Text", "Text", "Varchar", @@ -24,5 +25,5 @@ }, "nullable": [] }, - "hash": "35b211d19e53da4b64b0bd097284de3236ab939e47a1fc2b15ffc9607b552f8d" + "hash": "b5f6870444fc97d8beab3cf61c91e58936138d80a97b423c17338ba069b6a3aa" } diff --git a/backend/.sqlx/query-ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238.json b/backend/.sqlx/query-ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238.json deleted file mode 100644 index 0e42bd0fdb..0000000000 --- a/backend/.sqlx/query-ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "db_name": "PostgreSQL", - "query": "INSERT INTO v2_job (id, runnable_id, runnable_path, kind, script_lang, tag, created_by, permissioned_as, permissioned_as_email, workspace_id) (SELECT gen_random_uuid(), $1, $2, $3, $4, $5, $6, $7, $8, $9 FROM generate_series(1, $10)) RETURNING id", - "describe": { - "columns": [ - { - "ordinal": 0, - "name": "id", - "type_info": "Uuid" - } - ], - "parameters": { - "Left": [ - "Int8", - "Varchar", - { - "Custom": { - "name": "job_kind", - "kind": { - "Enum": [ - "script", - "preview", - "flow", - "dependencies", - "flowpreview", - "script_hub", - "identity", - "flowdependencies", - "http", - "graphql", - "postgresql", - "noop", - "appdependencies", - "deploymentcallback", - "singlescriptflow", - "flowscript", - "flownode", - "appscript", - "aiagent" - ] - } - } - }, - { - "Custom": { - "name": "script_lang", - "kind": { - "Enum": [ - "python3", - "deno", - "go", - "bash", - "postgresql", - "nativets", - "bun", - "mysql", - "bigquery", - "snowflake", - "graphql", - "powershell", - "mssql", - "php", - "bunnative", - "rust", - "ansible", - "csharp", - "oracledb", - "nu", - "java", - "duckdb", - "ruby" - ] - } - } - }, - "Varchar", - "Varchar", - "Varchar", - "Varchar", - "Varchar", - "Int4" - ] - }, - "nullable": [ - false - ] - }, - "hash": "ff0403790674cdb07022af71c2377afbd8b3a660b3be27514b517c077c63c238" -} diff --git a/backend/migrations/20250923094837_websocket_can_return_error_result.down.sql b/backend/migrations/20250923094837_websocket_can_return_error_result.down.sql new file mode 100644 index 0000000000..51456cbf29 --- /dev/null +++ b/backend/migrations/20250923094837_websocket_can_return_error_result.down.sql @@ -0,0 +1,2 @@ +-- Add down migration script here +ALTER TABLE websocket_trigger DROP COLUMN can_return_error_result; \ No newline at end of file diff --git a/backend/migrations/20250923094837_websocket_can_return_error_result.up.sql b/backend/migrations/20250923094837_websocket_can_return_error_result.up.sql new file mode 100644 index 0000000000..085a575e38 --- /dev/null +++ b/backend/migrations/20250923094837_websocket_can_return_error_result.up.sql @@ -0,0 +1,2 @@ +-- Add up migration script here +ALTER TABLE websocket_trigger ADD COLUMN can_return_error_result BOOLEAN NOT NULL DEFAULT FALSE; \ No newline at end of file diff --git a/backend/windmill-api/openapi.yaml b/backend/windmill-api/openapi.yaml index be92a76234..ba53fb2c37 100644 --- a/backend/windmill-api/openapi.yaml +++ b/backend/windmill-api/openapi.yaml @@ -16426,6 +16426,8 @@ components: $ref: "#/components/schemas/ScriptArgs" can_return_message: type: boolean + can_return_error_result: + type: boolean error_handler_path: type: string error_handler_args: @@ -16438,6 +16440,7 @@ components: - enabled - filters - can_return_message + - can_return_error_result NewWebsocketTrigger: type: object @@ -16471,6 +16474,8 @@ components: $ref: "#/components/schemas/ScriptArgs" can_return_message: type: boolean + can_return_error_result: + type: boolean error_handler_path: type: string error_handler_args: @@ -16485,6 +16490,7 @@ components: - is_flow - filters - can_return_message + - can_return_error_result EditWebsocketTrigger: type: object @@ -16516,6 +16522,8 @@ components: $ref: "#/components/schemas/ScriptArgs" can_return_message: type: boolean + can_return_error_result: + type: boolean error_handler_path: type: string error_handler_args: @@ -16530,6 +16538,7 @@ components: - is_flow - filters - can_return_message + - can_return_error_result WebsocketTriggerInitialMessage: anyOf: - type: object diff --git a/backend/windmill-api/src/jobs.rs b/backend/windmill-api/src/jobs.rs index 5bd8410ff7..596e404629 100644 --- a/backend/windmill-api/src/jobs.rs +++ b/backend/windmill-api/src/jobs.rs @@ -4523,12 +4523,17 @@ pub async fn run_wait_result_internal( if result.is_none() { let row = sqlx::query!( - "SELECT + " + SELECT result AS \"result: sqlx::types::Json>\", result_columns, status = 'success' AS \"success!\" - FROM v2_job_completed - WHERE id = $1 AND workspace_id = $2", + FROM + v2_job_completed + WHERE + id = $1 AND + workspace_id = $2 + ", uuid, &w_id ) diff --git a/backend/windmill-api/src/triggers/trigger_helpers.rs b/backend/windmill-api/src/triggers/trigger_helpers.rs index c95b74761e..a1a5f62e50 100644 --- a/backend/windmill-api/src/triggers/trigger_helpers.rs +++ b/backend/windmill-api/src/triggers/trigger_helpers.rs @@ -623,7 +623,7 @@ pub async fn trigger_runnable_and_wait_for_raw_result( error_handler_path: Option<&str>, error_handler_args: Option<&sqlx::types::Json>>, trigger_path: String, -) -> Result> { +) -> Result<(Box, bool)> { let username = authed.username.clone(); let (uuid, delete_after_use, early_return) = trigger_runnable_inner( db, @@ -656,6 +656,36 @@ pub async fn trigger_runnable_and_wait_for_raw_result( delete_job_metadata_after_use(&db, uuid).await?; } + Ok((result, success)) +} + +pub async fn trigger_runnable_and_wait_for_raw_result_with_error_ctx( + db: &DB, + user_db: Option, + authed: ApiAuthed, + workspace_id: &str, + runnable_path: &str, + is_flow: bool, + args: PushArgsOwned, + retry: Option<&sqlx::types::Json>, + error_handler_path: Option<&str>, + error_handler_args: Option<&sqlx::types::Json>>, + trigger_path: String, +) -> Result> { + let (result, success) = trigger_runnable_and_wait_for_raw_result( + db, + user_db, + authed, + workspace_id, + runnable_path, + is_flow, + args, + retry, + error_handler_path, + error_handler_args, + trigger_path, + ).await?; + if !success { Err(windmill_common::error::Error::internal_err(format!( "{} {runnable_path} failed: {:?}", diff --git a/backend/windmill-api/src/triggers/websocket/handler.rs b/backend/windmill-api/src/triggers/websocket/handler.rs index 0a321a450c..827367e195 100644 --- a/backend/windmill-api/src/triggers/websocket/handler.rs +++ b/backend/windmill-api/src/triggers/websocket/handler.rs @@ -40,6 +40,7 @@ impl TriggerCrud for WebsocketTrigger { "initial_messages", "url_runnable_args", "can_return_message", + "can_return_error_result", ]; const IS_ALLOWED_ON_CLOUD: bool = false; @@ -105,13 +106,14 @@ impl TriggerCrud for WebsocketTrigger { url_runnable_args, edited_by, can_return_message, + can_return_error_result, email, edited_at, error_handler_path, error_handler_args, retry ) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, now(), $13, $14, $15 + $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, now(), $14, $15, $16 ) "#, w_id, @@ -128,6 +130,7 @@ impl TriggerCrud for WebsocketTrigger { .map(|v| SqlxJson(serde_json::value::to_raw_value(&v).unwrap())) as _, authed.username, trigger.config.can_return_message, + trigger.config.can_return_error_result, authed.email, trigger.error_handling.error_handler_path, trigger.error_handling.error_handler_args as _, @@ -177,14 +180,15 @@ impl TriggerCrud for WebsocketTrigger { edited_by = $8, email = $9, can_return_message = $10, + can_return_error_result = $11, edited_at = now(), server_id = NULL, error = NULL, - error_handler_path = $13, - error_handler_args = $14, - retry = $15 + error_handler_path = $14, + error_handler_args = $15, + retry = $16 WHERE - workspace_id = $11 AND path = $12 + workspace_id = $12 AND path = $13 ", trigger.config.url, trigger.base.script_path, @@ -200,6 +204,7 @@ impl TriggerCrud for WebsocketTrigger { &authed.username, &authed.email, trigger.config.can_return_message, + trigger.config.can_return_error_result, w_id, path, trigger.error_handling.error_handler_path, diff --git a/backend/windmill-api/src/triggers/websocket/listener.rs b/backend/windmill-api/src/triggers/websocket/listener.rs index 7fb22f2b08..9a3f83a016 100644 --- a/backend/windmill-api/src/triggers/websocket/listener.rs +++ b/backend/windmill-api/src/triggers/websocket/listener.rs @@ -1,7 +1,10 @@ use super::WebsocketTrigger; use crate::triggers::{ listener::ListeningTrigger, - trigger_helpers::{trigger_runnable, trigger_runnable_and_wait_for_raw_result, TriggerJobArgs}, + trigger_helpers::{ + trigger_runnable, trigger_runnable_and_wait_for_raw_result, + trigger_runnable_and_wait_for_raw_result_with_error_ctx, TriggerJobArgs, + }, websocket::WebsocketConfig, Listener, }; @@ -42,7 +45,7 @@ impl ListeningTrigger { self.trigger_config.url_runnable_args.as_ref().map(|r| &r.0), )?; - let result = trigger_runnable_and_wait_for_raw_result( + let result = trigger_runnable_and_wait_for_raw_result_with_error_ctx( db, None, authed, @@ -116,7 +119,7 @@ impl ListeningTrigger { } let authed = authed_o.clone().unwrap(); - let result = trigger_runnable_and_wait_for_raw_result( + let result = trigger_runnable_and_wait_for_raw_result_with_error_ctx( db, None, authed.clone(), @@ -404,6 +407,7 @@ impl Listener for WebsocketTrigger { let error_handler_path = error_handler_path.map(|s| s.to_string()); let error_handler_args = error_handler_args.cloned(); let trigger_path = path.clone(); + let can_return_error_result = trigger_config.can_return_error_result; let handle_response_f = async move { tokio::select! { _ = killpill_rx.recv() => { @@ -422,7 +426,11 @@ impl Listener for WebsocketTrigger { error_handler_args.as_ref(), format!("websocket_trigger/{}", trigger_path), ) => { - if let Ok(result) = result.map(|r| r.get().to_owned()) { + if let Ok((result, success)) = result { + if !success && !can_return_error_result { + return; + } + let result = result.get().to_owned(); // only send the result if it's not null if result != "null" { tracing::info!("Sending job result to WebSocket {}", url); diff --git a/backend/windmill-api/src/triggers/websocket/mod.rs b/backend/windmill-api/src/triggers/websocket/mod.rs index 7ed67e1565..86d3bd735b 100644 --- a/backend/windmill-api/src/triggers/websocket/mod.rs +++ b/backend/windmill-api/src/triggers/websocket/mod.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use crate::{ db::ApiAuthed, - triggers::trigger_helpers::{trigger_runnable_and_wait_for_raw_result, TriggerJobArgs}, + triggers::trigger_helpers::{trigger_runnable_and_wait_for_raw_result_with_error_ctx, TriggerJobArgs}, }; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; @@ -40,6 +40,8 @@ pub struct WebsocketConfig { pub url_runnable_args: Option>>, #[serde(default)] pub can_return_message: bool, + #[serde(default)] + pub can_return_error_result: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -49,6 +51,7 @@ pub struct WebsocketConfigRequest { initial_messages: Option>, url_runnable_args: Option, can_return_message: bool, + can_return_error_result: bool, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -97,7 +100,7 @@ pub async fn get_url_from_runnable_value( let args = value_to_args_hashmap(args)?; - let result = trigger_runnable_and_wait_for_raw_result( + let result = trigger_runnable_and_wait_for_raw_result_with_error_ctx( db, None, authed, diff --git a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte index 19c156fc8c..92f4778cc5 100644 --- a/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte +++ b/frontend/src/lib/components/triggers/websocket/WebsocketTriggerEditorInner.svelte @@ -92,6 +92,7 @@ let initial_messages: WebsocketTriggerInitialMessage[] = $state([]) let url_runnable_args: Record | undefined = $state({}) let can_return_message = $state(false) + let can_return_error_result = $state(false) let dirtyPath = $state(false) let can_write = $state(true) let drawerLoading = $state(true) @@ -128,6 +129,12 @@ is_flow = itemKind === 'flow' }) + $effect(() => { + if (!can_return_message) { + can_return_error_result = false + } + }) + export async function openEdit( ePath: string, isFlow: boolean, @@ -183,6 +190,7 @@ url_runnable_args = defaultValues?.url_runnable_args ?? {} dirtyPath = false can_return_message = false + can_return_error_result = false error_handler_path = defaultValues?.error_handler_path ?? undefined error_handler_args = defaultValues?.error_handler_args ?? {} retry = defaultValues?.retry ?? undefined @@ -205,6 +213,7 @@ initial_messages = cfg?.initial_messages ?? [] url_runnable_args = cfg?.url_runnable_args can_return_message = cfg?.can_return_message + can_return_error_result = cfg?.can_return_error_result can_write = canWrite(path, cfg?.extra_perms, $userStore) error_handler_path = cfg?.error_handler_path error_handler_args = cfg?.error_handler_args ?? {} @@ -223,6 +232,7 @@ initial_messages, url_runnable_args, can_return_message, + can_return_error_result, enabled, error_handler_path, error_handler_args, @@ -463,6 +473,19 @@ }} disabled={!can_write} /> + + { + can_return_error_result = !can_return_error_result + }} + options={{ + right: 'Send result on error', + rightTooltip: + 'Allows the runnable result to be sent as a message to the WebSocket server if the result is a non-null error.' + }} + disabled={!can_write || !can_return_message} + />