w4c-workflows-api/Services/Execution/SubprocessScriptExecutor.cs

56 lines
1.9 KiB
C#
Raw Normal View History

using System.Diagnostics;
namespace w4c_workflows.Services.Execution;
/// <summary>
/// Runs a language whose program is a single file executed by an interpreter
/// (shell → sh, python → python3, javascript → node). Input is written to stdin
/// as JSON; output follows the <see cref="ExecutionHelpers"/> stdout contract.
/// </summary>
public class SubprocessScriptExecutor : IScriptExecutor
{
private readonly string _language;
private readonly string _executable;
private readonly TimeSpan _timeout;
public SubprocessScriptExecutor(string language, string executable, IConfiguration config)
{
_language = language;
_executable = executable;
_timeout = TimeSpan.FromSeconds(ParseInt(config["Workflows:TaskTimeoutSeconds"], 60));
}
public string Language => _language;
public bool IsAvailable() => ProcessRunner.FindInPath(_executable) != null;
public async Task<ExecutionResult> ExecuteAsync(TaskInvocation invocation, CancellationToken ct)
{
var sw = Stopwatch.StartNew();
try
{
var workingDir = ExecutionHelpers.ResolveWorkingDir(invocation);
var entryPath = Path.Combine(workingDir, invocation.EntryFile);
var output = await ProcessRunner.RunAsync(
_executable,
new[] { entryPath },
workingDir,
ExecutionHelpers.BuildEnvironment(invocation),
invocation.Input,
_timeout,
ct);
return ExecutionHelpers.ToResult(output, sw.Elapsed);
}
catch (Exception ex)
{
sw.Stop();
return new ExecutionResult(false, -1, string.Empty, string.Empty, null, ex.Message, sw.Elapsed);
}
}
private static int ParseInt(string? text, int fallback)
=> int.TryParse(text, out var value) && value > 0 ? value : fallback;
}