diff options
| author | Melodi <62381002+Melodi17@users.noreply.github.com> | 2026-10-28 00:04:17 +1000 |
|---|---|---|
| committer | Melodi <62381002+Melodi17@users.noreply.github.com> | 2026-10-28 00:04:17 +1000 |
| commit | e566edc0442330c11906da384d589c47f836de37 (patch) | |
| tree | 55697bf60d402beeae06ea9258a827a931a359e4 /src | |
| parent | 64172b677f699b816d76ab1ea13264b4f91bfb46 (diff) | |
fix: file name; move into loop and uow
Diffstat (limited to 'src')
| -rw-r--r-- | src/marlin.agents.shell/CommandRunner.cs | 5 | ||||
| -rw-r--r-- | src/marlin.agents.shell/JobUnitOfWork.cs | 55 | ||||
| -rw-r--r-- | src/marlin.agents.shell/Program.cs | 42 | ||||
| -rw-r--r-- | src/marlin.agents.shell/SlaveLoop.cs | 69 |
4 files changed, 109 insertions, 62 deletions
diff --git a/src/marlin.agents.shell/CommandRunner.cs b/src/marlin.agents.shell/CommandRunner.cs index d4fcbb3..90c0a58 100644 --- a/src/marlin.agents.shell/CommandRunner.cs +++ b/src/marlin.agents.shell/CommandRunner.cs @@ -2,7 +2,7 @@ using System.Diagnostics; public static class CommandRunner { - public static async Task<int> RunAsync(string command, Action<string> onStdout, Action<string> onStderr) + public static async Task<int> RunAsync(string command, string workingDir, Action<string> onStdout, Action<string> onStderr) { var psi = new ProcessStartInfo { @@ -11,7 +11,8 @@ public static class CommandRunner RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, - CreateNoWindow = true + CreateNoWindow = true, + WorkingDirectory = workingDir }; var process = new Process { StartInfo = psi }; diff --git a/src/marlin.agents.shell/JobUnitOfWork.cs b/src/marlin.agents.shell/JobUnitOfWork.cs index 85df806..5d639c0 100644 --- a/src/marlin.agents.shell/JobUnitOfWork.cs +++ b/src/marlin.agents.shell/JobUnitOfWork.cs @@ -12,38 +12,27 @@ using ProtoBuf.Grpc.Client; public class JobUnitOfWork { - private static string _jobInstanceDir = Path.Combine(CommonPaths.AgentRoot, "instance"); + private readonly IInstanceService _instanceService; + private readonly Channel<LogEventRequest> _logQueue; - private readonly MarlinApiClient _apiClient; - private readonly IGitClient _gitClient; - private readonly DispatchJob _job; - private readonly string _checkoutPath; + protected readonly string _workingDir; + protected readonly string _recipe; - private GrpcChannel _channel; - private IInstanceService _instanceService; - - private Channel<LogEventRequest> _logQueue; - - public JobUnitOfWork(DispatchJob job, MarlinApiClient apiClient, IGitClient gitClient) + public JobUnitOfWork(IInstanceService instanceService, string workingDir, string recipe) { - this._job = job; - this._apiClient = apiClient; - this._gitClient = gitClient; + this._instanceService = instanceService; + this._logQueue = Channel.CreateUnbounded<LogEventRequest>(); - this._checkoutPath = Path.Combine(_jobInstanceDir, job.Id.ToString("N")); + this._workingDir = workingDir; + this._recipe = recipe; } public async Task Run() { - this._channel = this._apiClient.CreateJobScopedRpc(this._job); - this._instanceService = this._channel.CreateGrpcService<IInstanceService>(); - this._logQueue = Channel.CreateUnbounded<LogEventRequest>(); - var drainTask = Task.Run(this.DrainLogEvents); await StatusUpdate(JobStatus.Active); - await this.CheckoutSource(); var plan = await this.BuildPlan(); var success = await this.ExecutePlan(plan); @@ -53,28 +42,13 @@ public class JobUnitOfWork await drainTask; } - private async Task CheckoutSource() - { - Directory.CreateDirectory(_jobInstanceDir); - if (Path.Exists(this._checkoutPath)) - Directory.Delete(this._checkoutPath, true); - - await this._gitClient.Checkout(this._checkoutPath, this._job.Vcs, this._job.Ref, this._job.Commit); - } - - private async Task DrainLogEvents() - { - await foreach (var evt in this._logQueue.Reader.ReadAllAsync()) - await this._instanceService.SendLogEvent(evt); - } - private async Task<ExecutionPlan> BuildPlan() { WorkflowBuilder builder = new(); - builder.LoadFromDirectory(Path.Join(this._checkoutPath, ".marlin")); + builder.LoadFromDirectory(Path.Join(this._workingDir, ".marlin")); Workflow workflow = builder.Build(); - Recipe recipe = workflow.Recipes[this._job.Recipe]; + Recipe recipe = workflow.Recipes[this._recipe]; ExecutionPlan plan = ExecutionPlan.Create(workflow, recipe); return plan; @@ -101,6 +75,7 @@ public class JobUnitOfWork Console.WriteLine(component); Task<int> run = CommandRunner.RunAsync( component.Command, + this._workingDir, o => Log(o, false, component), o => Log(o, true, component)); @@ -111,6 +86,12 @@ public class JobUnitOfWork return results.All(x => x.Value == CommandResult.Success); } + private async Task DrainLogEvents() + { + await foreach (var evt in this._logQueue.Reader.ReadAllAsync()) + await this._instanceService.SendLogEvent(evt); + } + private void Log(string message, bool error, ExecutionCommand component) { this._logQueue.Writer.TryWrite( diff --git a/src/marlin.agents.shell/Program.cs b/src/marlin.agents.shell/Program.cs index 75ea8ad..c895e8d 100644 --- a/src/marlin.agents.shell/Program.cs +++ b/src/marlin.agents.shell/Program.cs @@ -8,36 +8,32 @@ using marlin.core.models; using marlin.core.models.meta; using marlin.core.models.plan; using marlin.core.util; +using ProtoBuf.Grpc; using ProtoBuf.Grpc.Client; DotNetEnv.Env.NoClobber().TraversePath().Load(); -var jobInstanceDir = Path.Combine(CommonPaths.AgentRoot, "instance"); -Directory.CreateDirectory(jobInstanceDir); - -var client = MarlinApiClient.FromEnvironment(); - -var capabilities = new CapabilitySet(); -capabilities.Items.Add(KnownCapabilities.Architecture, RuntimeInformation.OSArchitecture.ToString()); -capabilities.Items.Add(KnownCapabilities.CoreCount, Environment.ProcessorCount.ToString()); -capabilities.Items.Add(KnownCapabilities.Memory, (GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / (1024 * 1024)).ToString()); -var status = new AgentStatus(capabilities); +if (args.Length == 0) +{ + SlaveLoop loop = new(); + await loop.Start(); +} +else +{ + string recipe = args[0]; + string repoPath = args.Length > 1 ? args[1] : Environment.CurrentDirectory; -AgentConfiguration config = await client.Handshake(status); -Console.WriteLine($"IAM: {config.Name}"); -Console.WriteLine($"MCJ: {config.MaxConcurrentJobs}"); + JobUnitOfWork uow = new(new LocalInstanceService(), repoPath, recipe); + await uow.Run(); +} -while (true) +public class LocalInstanceService : IInstanceService { - var job = await client.QueueNextJob(); - Console.WriteLine(job == null ? "No pending jobs." : $"Claimed job {job.Id}: {job.Recipe}"); - - if (job != null) + public async Task SendLogEvent(LogEventRequest request, CallContext context = default) { - GitBinaryClient gitClient = new(); - var uow = new JobUnitOfWork(job, client, gitClient); - await uow.Run(); + TextWriter writer = request.Error ? Console.Error : Console.Out; + await writer.WriteLineAsync(request.Message); } - - await Task.Delay(TimeSpan.FromSeconds(5)); + + public Task SendStatusUpdate(StatusUpdateRequest request, CallContext context = default) => Task.CompletedTask; }
\ No newline at end of file diff --git a/src/marlin.agents.shell/SlaveLoop.cs b/src/marlin.agents.shell/SlaveLoop.cs new file mode 100644 index 0000000..82f6ff5 --- /dev/null +++ b/src/marlin.agents.shell/SlaveLoop.cs @@ -0,0 +1,69 @@ +namespace marlin.agents.shell; + +using System.Runtime.InteropServices; +using core.contracts; +using core.functional; +using core.models; +using core.util; +using ProtoBuf.Grpc.Client; + +public class SlaveLoop +{ + private static readonly string _jobInstanceDir = Path.Combine(CommonPaths.AgentRoot, "instance"); + private readonly MarlinApiClient _client; + + public SlaveLoop() + { + this._client = MarlinApiClient.FromEnvironment(); + } + + public async Task Start() + { + AgentConfiguration config = await Handshake(); + Console.WriteLine($"IAM: {config.Name}"); + Console.WriteLine($"MCJ: {config.MaxConcurrentJobs}"); + + while (true) + { + var job = await this._client.QueueNextJob(); + if (job == null) + { + await Task.Delay(TimeSpan.FromSeconds(5)); + continue; + } + + Console.WriteLine($"Claimed job {job.Id}: {job.Recipe}"); + await FireJob(job); + } + } + + private async Task<AgentConfiguration> Handshake() + { + var capabilities = new CapabilitySet(); + capabilities.Items.Add(KnownCapabilities.Architecture, RuntimeInformation.OSArchitecture.ToString()); + capabilities.Items.Add(KnownCapabilities.CoreCount, Environment.ProcessorCount.ToString()); + capabilities.Items.Add(KnownCapabilities.Memory, (GC.GetGCMemoryInfo().TotalAvailableMemoryBytes / (1024 * 1024)).ToString()); + var status = new AgentStatus(capabilities); + + AgentConfiguration config = await _client.Handshake(status); + return config; + } + + private async Task FireJob(DispatchJob job) + { + GitBinaryClient gitClient = new(); + var channel = this._client.CreateJobScopedRpc(job); + var instanceService = channel.CreateGrpcService<IInstanceService>(); + + string workingDir = Path.Combine(_jobInstanceDir, job.Id.ToString("N")); + + Directory.CreateDirectory(_jobInstanceDir); + if (Path.Exists(workingDir)) + Directory.Delete(workingDir, true); + + await gitClient.Checkout(workingDir, job.Vcs, job.Ref, job.Commit); + + var uow = new JobUnitOfWork(instanceService, workingDir, job.Recipe); + await uow.Run(); + } +}
\ No newline at end of file |
