Skip to content

Commit 2accae1

Browse files
committed
improve error handling
1 parent 45be790 commit 2accae1

3 files changed

Lines changed: 35 additions & 13 deletions

File tree

src/workflow/CommandExecutor.py

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def __init__(self, workflow_dir: Path, logger: Logger, parameter_manager: Parame
2727

2828
def run_multiple_commands(
2929
self, commands: list[str]
30-
) -> None:
30+
) -> bool:
3131
"""
3232
Executes multiple shell commands concurrently in separate threads.
3333
@@ -38,17 +38,28 @@ def run_multiple_commands(
3838
Args:
3939
commands (list[str]): A list where each element is a list representing
4040
a command and its arguments.
41+
42+
Returns:
43+
bool: True if all commands succeeded, False if any failed.
4144
"""
4245
# Log the start of command execution
4346
self.logger.log(f"Running {len(commands)} commands in parallel...", 1)
4447
start_time = time.time()
4548

49+
results = []
50+
lock = threading.Lock()
51+
52+
def run_and_track(cmd):
53+
success = self.run_command(cmd)
54+
with lock:
55+
results.append(success)
56+
4657
# Initialize a list to keep track of threads
4758
threads = []
4859

4960
# Start a new thread for each command
5061
for cmd in commands:
51-
thread = threading.Thread(target=self.run_command, args=(cmd,))
62+
thread = threading.Thread(target=run_and_track, args=(cmd,))
5263
thread.start()
5364
threads.append(thread)
5465

@@ -60,7 +71,9 @@ def run_multiple_commands(
6071
end_time = time.time()
6172
self.logger.log(f"Total time to run {len(commands)} commands: {end_time - start_time:.2f} seconds", 1)
6273

63-
def run_command(self, command: list[str]) -> None:
74+
return all(results)
75+
76+
def run_command(self, command: list[str]) -> bool:
6477
"""
6578
Executes a specified shell command and logs its execution details.
6679
@@ -110,7 +123,9 @@ def run_command(self, command: list[str]) -> None:
110123

111124
# Check for errors
112125
if process.returncode != 0:
113-
self.logger.log(f"ERRORS OCCURRED: Process exited with code {process.returncode}", 2)
126+
self.logger.log(f"ERROR: Command failed with exit code {process.returncode}: {command[0]}", 0)
127+
return False
128+
return True
114129

115130
def _stream_output(self, process: subprocess.Popen) -> None:
116131
"""
@@ -157,7 +172,7 @@ def read_stderr():
157172
stdout_thread.join()
158173
stderr_thread.join()
159174

160-
def run_topp(self, tool: str, input_output: dict, custom_params: dict = {}) -> None:
175+
def run_topp(self, tool: str, input_output: dict, custom_params: dict = {}) -> bool:
161176
"""
162177
Constructs and executes commands for the specified tool OpenMS TOPP tool based on the given
163178
input and output configurations. Ensures that all input/output file lists
@@ -176,6 +191,9 @@ def run_topp(self, tool: str, input_output: dict, custom_params: dict = {}) -> N
176191
input_output (dict): A dictionary specifying the input/output parameter names (as key) and their corresponding file paths (as value).
177192
custom_params (dict): A dictionary of custom parameters to pass to the tool.
178193
194+
Returns:
195+
bool: True if all commands succeeded, False if any failed.
196+
179197
Raises:
180198
ValueError: If the lengths of input/output file lists are inconsistent,
181199
except for single string inputs.
@@ -240,9 +258,9 @@ def run_topp(self, tool: str, input_output: dict, custom_params: dict = {}) -> N
240258

241259
# Run command(s)
242260
if len(commands) == 1:
243-
self.run_command(commands[0])
261+
return self.run_command(commands[0])
244262
elif len(commands) > 1:
245-
self.run_multiple_commands(commands)
263+
return self.run_multiple_commands(commands)
246264
else:
247265
raise Exception("No commands to execute.")
248266

src/workflow/StreamlitUI.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,9 @@ def execution_section(self, start_workflow_function) -> None:
11561156
with open(log_path, "r", encoding="utf-8") as f:
11571157
content = f.read()
11581158
# Check if workflow finished successfully
1159-
if not "WORKFLOW FINISHED" in content:
1159+
if "WORKFLOW FINISHED" in content:
1160+
st.success("**Workflow completed successfully.**")
1161+
else:
11601162
st.error("**Errors occurred, check log file.**")
11611163
st.code(content, language="neon", line_numbers=False)
11621164
elif pid_exists:

src/workflow/WorkflowManager.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ def workflow_process(self) -> None:
4646
if results_dir.exists():
4747
shutil.rmtree(results_dir)
4848
results_dir.mkdir(parents=True)
49-
self.execution()
50-
self.logger.log("WORKFLOW FINISHED")
49+
success = self.execution()
50+
if success:
51+
self.logger.log("WORKFLOW FINISHED")
5152
except Exception as e:
5253
self.logger.log(f"ERROR: {e}")
5354
self.logger.log("".join(traceback.format_exception(e)))
@@ -96,14 +97,15 @@ def configure(self) -> None:
9697
###################################
9798
pass
9899

99-
def execution(self) -> None:
100+
def execution(self) -> bool:
100101
"""
101-
Add your workflow steps here
102+
Add your workflow steps here.
103+
Returns True on success, False on error.
102104
"""
103105
###################################
104106
# Add your workflow steps here
105107
###################################
106-
pass
108+
return True
107109

108110
def results(self) -> None:
109111
"""

0 commit comments

Comments
 (0)