/
Program.cs
93 lines (84 loc) · 3.69 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
using System;
using System.Globalization;
using System.Threading.Tasks;
using GitHub.Runner.Common;
using GitHub.Runner.Sdk;
using System.Diagnostics;
namespace GitHub.Runner.Worker
{
public static class Program
{
public static int Main(string[] args)
{
using (HostContext context = new("Worker"))
{
return MainAsync(context, args).GetAwaiter().GetResult();
}
}
public static async Task<int> MainAsync(IHostContext context, string[] args)
{
Tracing trace = context.GetTrace(nameof(GitHub.Runner.Worker));
if (StringUtil.ConvertToBoolean(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_ATTACH_DEBUGGER")))
{
await WaitForDebugger(trace);
}
// We may want to consider registering this handler in Worker.cs, similiar to the unloading/SIGTERM handler
//ITerminal registers a CTRL-C handler, which keeps the Runner.Worker process running
//and lets the Runner.Listener handle gracefully the exit.
var term = context.GetService<ITerminal>();
try
{
trace.Info($"Version: {BuildConstants.RunnerPackage.Version}");
trace.Info($"Commit: {BuildConstants.Source.CommitHash}");
trace.Info($"Culture: {CultureInfo.CurrentCulture.Name}");
trace.Info($"UI Culture: {CultureInfo.CurrentUICulture.Name}");
context.WritePerfCounter("WorkerProcessStarted");
// Validate args.
ArgUtil.NotNull(args, nameof(args));
ArgUtil.Equal(3, args.Length, nameof(args.Length));
ArgUtil.NotNullOrEmpty(args[0], $"{nameof(args)}[0]");
ArgUtil.Equal("spawnclient", args[0].ToLowerInvariant(), $"{nameof(args)}[0]");
ArgUtil.NotNullOrEmpty(args[1], $"{nameof(args)}[1]");
ArgUtil.NotNullOrEmpty(args[2], $"{nameof(args)}[2]");
var worker = context.GetService<IWorker>();
// Run the worker.
return await worker.RunAsync(
pipeIn: args[1],
pipeOut: args[2]);
}
catch (Exception ex)
{
// Populate any exception that cause worker failure back to runner.
Console.WriteLine(ex.ToString());
try
{
trace.Error(ex);
}
catch (Exception e)
{
// make sure we don't crash the app on trace error.
// since IOException will throw when we run out of disk space.
Console.WriteLine(e.ToString());
}
}
return 1;
}
/// <summary>
/// Runner.Worker is started by Runner.Listener in a separate process,
/// so the two can't be debugged in the same session.
/// This method halts the Runner.Worker process until a debugger is attached,
/// allowing a developer to debug Runner.Worker from start to finish.
/// </summary>
private static async Task WaitForDebugger(Tracing trace)
{
trace.Info($"Waiting for a debugger to be attached. Edit the 'GITHUB_ACTIONS_RUNNER_ATTACH_DEBUGGER' environment variable to toggle this feature.");
int waitInSeconds = 20;
while (!Debugger.IsAttached && waitInSeconds-- > 0)
{
trace.Info($"Waiting for a debugger to be attached. {waitInSeconds} seconds left.");
await Task.Delay(1000);
}
Debugger.Break();
}
}
}