ULSAlgorithms 1.1.0-g3e5595996d
High-performance exact and heuristic algorithms for uncapacitated lot sizing
Loading...
Searching...
No Matches
ExternalSolverProcessRunner.cs
Go to the documentation of this file.
1using System.Diagnostics;
2
4
5/// <summary>
6/// Runs a solver command-line process with cancellation and captured output.
7/// </summary>
8internal sealed class ExternalSolverProcessRunner
9{
10 internal async ValueTask<ExternalSolverProcessResult> RunAsync(
11 string executablePath,
12 IEnumerable<string> arguments,
13 string workingDirectory,
14 string? standardInput,
15 CancellationToken cancellationToken)
16 {
17 ArgumentException.ThrowIfNullOrWhiteSpace(
18 executablePath);
19
20 ArgumentNullException.ThrowIfNull(arguments);
21
22 var startInfo =
23 new ProcessStartInfo
24 {
25 FileName = executablePath,
26 WorkingDirectory =
27 string.IsNullOrWhiteSpace(workingDirectory)
28 ? Environment.CurrentDirectory
29 : workingDirectory,
30 UseShellExecute = false,
31 RedirectStandardOutput = true,
32 RedirectStandardError = true,
33 RedirectStandardInput =
34 standardInput is not null,
35 CreateNoWindow = true
36 };
37
38 foreach (string argument in arguments)
39 {
40 startInfo.ArgumentList.Add(argument);
41 }
42
43 using var process =
44 new Process
45 {
46 StartInfo = startInfo,
47 EnableRaisingEvents = true
48 };
49
50 if (!process.Start())
51 {
52 throw new InvalidOperationException(
53 $"Unable to start solver executable '{executablePath}'.");
54 }
55
56 Task<string> stdoutTask =
57 process.StandardOutput.ReadToEndAsync(
58 cancellationToken);
59
60 Task<string> stderrTask =
61 process.StandardError.ReadToEndAsync(
62 cancellationToken);
63
64 if (standardInput is not null)
65 {
66 await process.StandardInput.WriteAsync(
67 standardInput);
68
69 process.StandardInput.Close();
70 }
71
72 try
73 {
74 await process.WaitForExitAsync(
75 cancellationToken);
76 }
77 catch (OperationCanceledException)
78 {
79 TryKill(process);
80 throw;
81 }
82
84 process.ExitCode,
85 await stdoutTask,
86 await stderrTask);
87 }
88
89 private static void TryKill(
90 Process process)
91 {
92 try
93 {
94 if (!process.HasExited)
95 {
96 process.Kill(
97 entireProcessTree: true);
98 }
99 }
100 catch
101 {
102 // Best-effort cancellation cleanup.
103 }
104 }
105}
106
107internal sealed record ExternalSolverProcessResult(
108 int ExitCode,
109 string StandardOutput,
110 string StandardError)
111{
112 internal string CombinedOutput =>
113 string.Join(
114 Environment.NewLine,
115 new[]
116 {
117 StandardOutput,
118 StandardError
119 }.Where(
120 static text =>
121 !string.IsNullOrWhiteSpace(text)));
122}
Runs a solver command-line process with cancellation and captured output.
async ValueTask< ExternalSolverProcessResult > RunAsync(string executablePath, IEnumerable< string > arguments, string workingDirectory, string? standardInput, CancellationToken cancellationToken)
record ExternalSolverProcessResult(int ExitCode, string StandardOutput, string StandardError)