Skip to content

Commit 7207e18

Browse files
committed
subprocess_run: add timeout option
1 parent 6ec9b43 commit 7207e18

File tree

2 files changed

+44
-5
lines changed

2 files changed

+44
-5
lines changed

+stdlib/subprocess_run.m

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
%% SUBPROCESS_RUN run process with optional cwd, env. vars, stdin stream
1+
%% SUBPROCESS_RUN run process with optional cwd, env. vars, stdin, timeout
22
%
3-
% handle command lines with spaces
3+
% handles command lines with spaces
44
% input each segment of the command as an element in a string array
55
% this is how python subprocess.run works
66
%
@@ -9,8 +9,10 @@
99
% * opt.env: environment variable struct to set
1010
% * opt.cwd: working directory to use while running command
1111
% * opt.stdin: string to pass to subprocess stdin pipe
12+
% * opt.timeout: time to wait for process to complete before erroring (seconds)
1213
%%% Outputs
13-
% * status: 0 is success
14+
% * status: 0 is generally success. -1 if timeout. Other codes as per the
15+
% program / command run
1416
% * stdout: stdout from process
1517
% * stderr: stderr from process
1618
%
@@ -31,6 +33,7 @@
3133
opt.env (1,1) struct = struct()
3234
opt.cwd (1,1) string = ""
3335
opt.stdin (1,1) string = ""
36+
opt.timeout (1,1) int64 = 0
3437
end
3538

3639
%% process instantiation
@@ -67,8 +70,23 @@
6770
end
6871

6972
%% wait for process to complete
70-
% https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/lang/Process.html#waitFor()
71-
status = h.waitFor();
73+
% https://docs.oracle.com/en/java/javase/23/docs/api/java.base/java/lang/Process.html#waitFor()
74+
75+
tmsg = "";
76+
if opt.timeout > 0
77+
% returns true if process completed successfully
78+
% returns false if process did not complete within timeout
79+
b = h.waitFor(opt.timeout, java.util.concurrent.TimeUnit.SECONDS);
80+
if b
81+
status = 0;
82+
else
83+
tmsg = "Subprocess timeout";
84+
status = -1;
85+
end
86+
else
87+
% returns 0 if process completed successfully
88+
status = h.waitFor();
89+
end
7290

7391
%% read stdout, stderr pipes
7492
stdout = read_stream(h.getInputStream());
@@ -77,6 +95,8 @@
7795
%% close process
7896
h.destroy()
7997

98+
stderr = tmsg + stderr;
99+
80100
if nargout < 2 && strlength(stdout) > 0
81101
disp(stdout)
82102
end

test/TestSubprocess.m

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,25 @@ function test_env_run(tc)
7676

7777
end
7878

79+
80+
function test_timeout(tc)
81+
import matlab.unittest.constraints.StartsWithSubstring
82+
83+
timeout = 1;
84+
85+
if ispc
86+
c = ["powershell", "-command", "Start-Sleep -s 3"];
87+
else
88+
c = ["sleep", "3"];
89+
end
90+
91+
[ret, ~, err] = stdlib.subprocess_run(c, timeout=timeout);
92+
93+
tc.verifyNotEqual(ret, 0, err)
94+
tc.verifyThat(err, StartsWithSubstring("Subprocess timeout"))
95+
96+
end
97+
7998
end
8099

81100
end

0 commit comments

Comments
 (0)