2023-06-02 21:47:59 +02:00
using System ;
2019-10-10 00:52:42 -04:00
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
2022-01-26 13:23:24 -05:00
using System.Net.Http ;
2023-04-26 15:15:19 -04:00
using System.Net.Http.Headers ;
2021-09-29 15:49:31 -04:00
using System.Text ;
2019-10-10 00:52:42 -04:00
using System.Threading ;
using System.Threading.Tasks ;
2023-02-27 11:50:28 -05:00
using GitHub.DistributedTask.Pipelines ;
2022-01-26 13:23:24 -05:00
using GitHub.DistributedTask.WebApi ;
2019-10-10 00:52:42 -04:00
using GitHub.Runner.Common ;
2022-01-26 13:23:24 -05:00
using GitHub.Runner.Common.Util ;
2019-10-10 00:52:42 -04:00
using GitHub.Runner.Sdk ;
2022-01-26 13:23:24 -05:00
using GitHub.Services.Common ;
using GitHub.Services.WebApi ;
using Pipelines = GitHub . DistributedTask . Pipelines ;
2019-10-10 00:52:42 -04:00
namespace GitHub.Runner.Worker
{
[ServiceLocator(Default = typeof(JobRunner))]
public interface IJobRunner : IRunnerService
{
2023-02-27 11:50:28 -05:00
Task < TaskResult > RunAsync ( AgentJobRequestMessage message , CancellationToken jobRequestCancellationToken ) ;
2019-10-10 00:52:42 -04:00
}
public sealed class JobRunner : RunnerService , IJobRunner
{
private IJobServerQueue _jobServerQueue ;
2022-01-26 13:23:24 -05:00
private RunnerSettings _runnerSettings ;
2019-10-10 00:52:42 -04:00
private ITempDirectoryManager _tempDirectoryManager ;
2023-02-27 11:50:28 -05:00
public async Task < TaskResult > RunAsync ( AgentJobRequestMessage message , CancellationToken jobRequestCancellationToken )
2019-10-10 00:52:42 -04:00
{
// Validate parameters.
Trace . Entering ( ) ;
ArgUtil . NotNull ( message , nameof ( message ) ) ;
ArgUtil . NotNull ( message . Resources , nameof ( message . Resources ) ) ;
ArgUtil . NotNull ( message . Variables , nameof ( message . Variables ) ) ;
ArgUtil . NotNull ( message . Steps , nameof ( message . Steps ) ) ;
Trace . Info ( "Job ID {0}" , message . JobId ) ;
DateTime jobStartTimeUtc = DateTime . UtcNow ;
2023-02-01 16:18:31 -05:00
IRunnerService server = null ;
2019-10-10 00:52:42 -04:00
2023-04-26 15:15:19 -04:00
// add orchestration id to useragent for better correlation.
if ( message . Variables . TryGetValue ( Constants . Variables . System . OrchestrationId , out VariableValue orchestrationId ) & &
! string . IsNullOrEmpty ( orchestrationId . Value ) )
{
HostContext . UserAgents . Add ( new ProductInfoHeaderValue ( "OrchestrationId" , orchestrationId . Value ) ) ;
}
2019-10-10 00:52:42 -04:00
ServiceEndpoint systemConnection = message . Resources . Endpoints . Single ( x = > string . Equals ( x . Name , WellKnownServiceEndpointNames . SystemVssConnection , StringComparison . OrdinalIgnoreCase ) ) ;
2023-02-27 11:50:28 -05:00
if ( MessageUtil . IsRunServiceJob ( message . MessageType ) )
2023-02-01 16:18:31 -05:00
{
var runServer = HostContext . GetService < IRunServer > ( ) ;
VssCredentials jobServerCredential = VssUtil . GetVssCredential ( systemConnection ) ;
await runServer . ConnectAsync ( systemConnection . Url , jobServerCredential ) ;
server = runServer ;
2023-04-26 12:51:56 -04:00
2023-05-03 16:04:21 -04:00
message . Variables . TryGetValue ( "system.github.launch_endpoint" , out VariableValue launchEndpointVariable ) ;
var launchReceiverEndpoint = launchEndpointVariable ? . Value ;
if ( systemConnection ? . Authorization ! = null & &
systemConnection . Authorization . Parameters . TryGetValue ( "AccessToken" , out var accessToken ) & &
! string . IsNullOrEmpty ( accessToken ) & &
! string . IsNullOrEmpty ( launchReceiverEndpoint ) )
{
Trace . Info ( "Initializing launch client" ) ;
var launchServer = HostContext . GetService < ILaunchServer > ( ) ;
launchServer . InitializeLaunchClient ( new Uri ( launchReceiverEndpoint ) , accessToken ) ;
}
2023-04-26 12:51:56 -04:00
_jobServerQueue = HostContext . GetService < IJobServerQueue > ( ) ;
_jobServerQueue . Start ( message , resultServiceOnly : true ) ;
2023-02-01 16:18:31 -05:00
}
2023-02-27 11:50:28 -05:00
else
2023-02-01 16:18:31 -05:00
{
// Setup the job server and job server queue.
var jobServer = HostContext . GetService < IJobServer > ( ) ;
VssCredentials jobServerCredential = VssUtil . GetVssCredential ( systemConnection ) ;
Uri jobServerUrl = systemConnection . Url ;
2019-10-10 00:52:42 -04:00
2023-02-01 16:18:31 -05:00
Trace . Info ( $"Creating job server with URL: {jobServerUrl}" ) ;
// jobServerQueue is the throttling reporter.
_jobServerQueue = HostContext . GetService < IJobServerQueue > ( ) ;
VssConnection jobConnection = VssUtil . CreateConnection ( jobServerUrl , jobServerCredential , new DelegatingHandler [ ] { new ThrottlingReportHandler ( _jobServerQueue ) } ) ;
await jobServer . ConnectAsync ( jobConnection ) ;
2019-10-10 00:52:42 -04:00
2023-02-01 16:18:31 -05:00
_jobServerQueue . Start ( message ) ;
server = jobServer ;
}
2023-02-27 11:50:28 -05:00
2019-10-10 00:52:42 -04:00
HostContext . WritePerfCounter ( $"WorkerJobServerQueueStarted_{message.RequestId.ToString()}" ) ;
IExecutionContext jobContext = null ;
CancellationTokenRegistration ? runnerShutdownRegistration = null ;
try
{
// Create the job execution context.
jobContext = HostContext . CreateService < IExecutionContext > ( ) ;
jobContext . InitializeJob ( message , jobRequestCancellationToken ) ;
Trace . Info ( "Starting the job execution context." ) ;
jobContext . Start ( ) ;
jobContext . Debug ( $"Starting: {message.JobDisplayName}" ) ;
runnerShutdownRegistration = HostContext . RunnerShutdownToken . Register ( ( ) = >
{
// log an issue, then runner get shutdown by Ctrl-C or Ctrl-Break.
// the server will use Ctrl-Break to tells the runner that operating system is shutting down.
string errorMessage ;
switch ( HostContext . RunnerShutdownReason )
{
case ShutdownReason . UserCancelled :
errorMessage = "The runner has received a shutdown signal. This can happen when the runner service is stopped, or a manually started runner is canceled." ;
break ;
case ShutdownReason . OperatingSystemShutdown :
errorMessage = $"Operating system is shutting down for computer '{Environment.MachineName}'" ;
break ;
default :
throw new ArgumentException ( HostContext . RunnerShutdownReason . ToString ( ) , nameof ( HostContext . RunnerShutdownReason ) ) ;
}
2023-05-10 16:24:02 +02:00
var issue = new Issue ( ) { Type = IssueType . Error , Message = errorMessage } ;
jobContext . AddIssue ( issue , ExecutionContextLogOptions . Default ) ;
2019-10-10 00:52:42 -04:00
} ) ;
// Validate directory permissions.
string workDirectory = HostContext . GetDirectory ( WellKnownDirectory . Work ) ;
Trace . Info ( $"Validating directory permissions for: '{workDirectory}'" ) ;
try
{
Directory . CreateDirectory ( workDirectory ) ;
IOUtil . ValidateExecutePermission ( workDirectory ) ;
}
catch ( Exception ex )
{
Trace . Error ( ex ) ;
jobContext . Error ( ex ) ;
2023-02-01 16:18:31 -05:00
return await CompleteJobAsync ( server , jobContext , message , TaskResult . Failed ) ;
2019-10-10 00:52:42 -04:00
}
2020-07-19 19:05:47 -04:00
if ( jobContext . Global . WriteDebug )
2020-01-03 21:23:46 -05:00
{
jobContext . SetRunnerContext ( "debug" , "1" ) ;
}
2019-10-10 00:52:42 -04:00
jobContext . SetRunnerContext ( "os" , VarUtil . OS ) ;
2021-10-13 20:49:26 -07:00
jobContext . SetRunnerContext ( "arch" , VarUtil . OSArchitecture ) ;
2019-10-10 00:52:42 -04:00
2022-01-26 13:23:24 -05:00
_runnerSettings = HostContext . GetService < IConfigurationStore > ( ) . GetSettings ( ) ;
jobContext . SetRunnerContext ( "name" , _runnerSettings . AgentName ) ;
2021-09-16 15:25:51 +02:00
2023-05-26 18:08:41 +01:00
if ( jobContext . Global . Variables . TryGetValue ( WellKnownDistributedTaskVariables . RunnerEnvironment , out var runnerEnvironment ) )
{
jobContext . SetRunnerContext ( "environment" , runnerEnvironment ) ;
}
2019-10-10 00:52:42 -04:00
string toolsDirectory = HostContext . GetDirectory ( WellKnownDirectory . Tools ) ;
Directory . CreateDirectory ( toolsDirectory ) ;
jobContext . SetRunnerContext ( "tool_cache" , toolsDirectory ) ;
// Setup TEMP directories
_tempDirectoryManager = HostContext . GetService < ITempDirectoryManager > ( ) ;
_tempDirectoryManager . InitializeTempDirectory ( jobContext ) ;
// Get the job extension.
Trace . Info ( "Getting job extension." ) ;
IJobExtension jobExtension = HostContext . CreateService < IJobExtension > ( ) ;
List < IStep > jobSteps = null ;
try
{
Trace . Info ( "Initialize job. Getting all job steps." ) ;
jobSteps = await jobExtension . InitializeJob ( jobContext , message ) ;
}
catch ( OperationCanceledException ex ) when ( jobContext . CancellationToken . IsCancellationRequested )
{
2022-02-23 15:48:24 +01:00
// set the job to cancelled
2019-10-10 00:52:42 -04:00
// don't log error issue to job ExecutionContext, since server owns the job level issue
2022-02-23 15:48:24 +01:00
Trace . Error ( $"Job is cancelled during initialize." ) ;
2019-10-10 00:52:42 -04:00
Trace . Error ( $"Caught exception: {ex}" ) ;
2023-02-01 16:18:31 -05:00
return await CompleteJobAsync ( server , jobContext , message , TaskResult . Canceled ) ;
2019-10-10 00:52:42 -04:00
}
catch ( Exception ex )
{
// set the job to failed.
// don't log error issue to job ExecutionContext, since server owns the job level issue
Trace . Error ( $"Job initialize failed." ) ;
Trace . Error ( $"Caught exception from {nameof(jobExtension.InitializeJob)}: {ex}" ) ;
2023-02-01 16:18:31 -05:00
return await CompleteJobAsync ( server , jobContext , message , TaskResult . Failed ) ;
2019-10-10 00:52:42 -04:00
}
// trace out all steps
Trace . Info ( $"Total job steps: {jobSteps.Count}." ) ;
Trace . Verbose ( $"Job steps: '{string.Join(" , ", jobSteps.Select(x => x.DisplayName))}'" ) ;
HostContext . WritePerfCounter ( $"WorkerJobInitialized_{message.RequestId.ToString()}" ) ;
2021-09-09 21:55:15 -04:00
if ( systemConnection . Data . TryGetValue ( "GenerateIdTokenUrl" , out var generateIdTokenUrl ) & &
! string . IsNullOrEmpty ( generateIdTokenUrl ) )
{
// Server won't issue ID_TOKEN for non-inprogress job.
// If the job is trying to use OIDC feature, we want the job to be marked as in-progress before running any customer's steps as much as we can.
// Timeline record update background process runs every 500ms, so delay 1000ms is enough for most of the cases
Trace . Info ( $"Waiting for job to be marked as started." ) ;
await Task . WhenAny ( _jobServerQueue . JobRecordUpdated . Task , Task . Delay ( 1000 ) ) ;
}
2019-10-10 00:52:42 -04:00
// Run all job steps
Trace . Info ( "Run all job steps." ) ;
var stepsRunner = HostContext . GetService < IStepsRunner > ( ) ;
try
{
foreach ( var step in jobSteps )
{
2020-07-29 16:19:04 -04:00
jobContext . JobSteps . Enqueue ( step ) ;
2019-10-10 00:52:42 -04:00
}
await stepsRunner . RunAsync ( jobContext ) ;
}
catch ( Exception ex )
{
// StepRunner should never throw exception out.
// End up here mean there is a bug in StepRunner
// Log the error and fail the job.
Trace . Error ( $"Caught exception from job steps {nameof(StepsRunner)}: {ex}" ) ;
jobContext . Error ( ex ) ;
2023-02-01 16:18:31 -05:00
return await CompleteJobAsync ( server , jobContext , message , TaskResult . Failed ) ;
2019-10-10 00:52:42 -04:00
}
finally
{
Trace . Info ( "Finalize job." ) ;
2019-12-09 16:11:00 -05:00
jobExtension . FinalizeJob ( jobContext , message , jobStartTimeUtc ) ;
2019-10-10 00:52:42 -04:00
}
Trace . Info ( $"Job result after all job steps finish: {jobContext.Result ?? TaskResult.Succeeded}" ) ;
Trace . Info ( "Completing the job execution context." ) ;
2023-02-01 16:18:31 -05:00
return await CompleteJobAsync ( server , jobContext , message ) ;
2019-10-10 00:52:42 -04:00
}
finally
{
if ( runnerShutdownRegistration ! = null )
{
runnerShutdownRegistration . Value . Dispose ( ) ;
runnerShutdownRegistration = null ;
}
await ShutdownQueue ( throwOnFailure : false ) ;
}
}
2023-02-01 16:18:31 -05:00
private async Task < TaskResult > CompleteJobAsync ( IRunnerService server , IExecutionContext jobContext , Pipelines . AgentJobRequestMessage message , TaskResult ? taskResult = null )
{
if ( server is IRunServer runServer )
{
return await CompleteJobAsync ( runServer , jobContext , message , taskResult ) ;
}
else if ( server is IJobServer jobServer )
{
return await CompleteJobAsync ( jobServer , jobContext , message , taskResult ) ;
}
else
{
throw new NotSupportedException ( ) ;
}
}
private async Task < TaskResult > CompleteJobAsync ( IRunServer runServer , IExecutionContext jobContext , Pipelines . AgentJobRequestMessage message , TaskResult ? taskResult = null )
{
jobContext . Debug ( $"Finishing: {message.JobDisplayName}" ) ;
TaskResult result = jobContext . Complete ( taskResult ) ;
if ( jobContext . Global . Variables . TryGetValue ( "Node12ActionsWarnings" , out var node12Warnings ) )
{
var actions = string . Join ( ", " , StringUtil . ConvertFromJson < HashSet < string > > ( node12Warnings ) ) ;
jobContext . Warning ( string . Format ( Constants . Runner . Node12DetectedAfterEndOfLife , actions ) ) ;
}
// Make sure to clean temp after file upload since they may be pending fileupload still use the TEMP dir.
_tempDirectoryManager ? . CleanupTempDirectory ( ) ;
// Load any upgrade telemetry
LoadFromTelemetryFile ( jobContext . Global . JobTelemetry ) ;
// Make sure we don't submit secrets as telemetry
MaskTelemetrySecrets ( jobContext . Global . JobTelemetry ) ;
Trace . Info ( $"Raising job completed against run service" ) ;
var completeJobRetryLimit = 5 ;
var exceptions = new List < Exception > ( ) ;
while ( completeJobRetryLimit - - > 0 )
{
try
{
2023-05-01 08:33:03 -04:00
await runServer . CompleteJobAsync ( message . Plan . PlanId , message . JobId , result , jobContext . JobOutputs , jobContext . Global . StepsResult , jobContext . Global . JobAnnotations , default ) ;
2023-02-01 16:18:31 -05:00
return result ;
}
catch ( Exception ex )
{
Trace . Error ( $"Catch exception while attempting to complete job {message.JobId}, job request {message.RequestId}." ) ;
Trace . Error ( ex ) ;
exceptions . Add ( ex ) ;
}
// delay 5 seconds before next retry.
await Task . Delay ( TimeSpan . FromSeconds ( 5 ) ) ;
}
// rethrow exceptions from all attempts.
throw new AggregateException ( exceptions ) ;
}
2019-10-10 00:52:42 -04:00
private async Task < TaskResult > CompleteJobAsync ( IJobServer jobServer , IExecutionContext jobContext , Pipelines . AgentJobRequestMessage message , TaskResult ? taskResult = null )
{
jobContext . Debug ( $"Finishing: {message.JobDisplayName}" ) ;
TaskResult result = jobContext . Complete ( taskResult ) ;
2022-01-26 13:23:24 -05:00
if ( _runnerSettings . DisableUpdate = = true )
{
try
{
var currentVersion = new PackageVersion ( BuildConstants . RunnerPackage . Version ) ;
ServiceEndpoint systemConnection = message . Resources . Endpoints . Single ( x = > string . Equals ( x . Name , WellKnownServiceEndpointNames . SystemVssConnection , StringComparison . OrdinalIgnoreCase ) ) ;
VssCredentials serverCredential = VssUtil . GetVssCredential ( systemConnection ) ;
var runnerServer = HostContext . GetService < IRunnerServer > ( ) ;
await runnerServer . ConnectAsync ( systemConnection . Url , serverCredential ) ;
var serverPackages = await runnerServer . GetPackagesAsync ( "agent" , BuildConstants . RunnerPackage . PackageName , 5 , includeToken : false , cancellationToken : CancellationToken . None ) ;
if ( serverPackages . Count > 0 )
{
serverPackages = serverPackages . OrderByDescending ( x = > x . Version ) . ToList ( ) ;
Trace . Info ( $"Newer packages {StringUtil.ConvertToJson(serverPackages.Select(x => x.Version.ToString()))}" ) ;
var warnOnFailedJob = false ; // any minor/patch version behind.
var warnOnOldRunnerVersion = false ; // >= 2 minor version behind
if ( serverPackages . Any ( x = > x . Version . CompareTo ( currentVersion ) > 0 ) )
{
Trace . Info ( $"Current runner version {currentVersion} is behind the latest runner version {serverPackages[0].Version}." ) ;
warnOnFailedJob = true ;
}
if ( serverPackages . Where ( x = > x . Version . Major = = currentVersion . Major & & x . Version . Minor > currentVersion . Minor ) . Count ( ) > 1 )
{
Trace . Info ( $"Current runner version {currentVersion} is way behind the latest runner version {serverPackages[0].Version}." ) ;
warnOnOldRunnerVersion = true ;
}
if ( result = = TaskResult . Failed & & warnOnFailedJob )
{
jobContext . Warning ( $"This job failure may be caused by using an out of date self-hosted runner. You are currently using runner version {currentVersion}. Please update to the latest version {serverPackages[0].Version}" ) ;
}
else if ( warnOnOldRunnerVersion )
{
jobContext . Warning ( $"This self-hosted runner is currently using runner version {currentVersion}. This version is out of date. Please update to the latest version {serverPackages[0].Version}" ) ;
}
}
}
catch ( Exception ex )
{
// Ignore any error since suggest runner update is best effort.
Trace . Error ( $"Caught exception during runner version check: {ex}" ) ;
}
}
2022-11-02 09:40:19 -04:00
if ( jobContext . Global . Variables . TryGetValue ( "Node12ActionsWarnings" , out var node12Warnings ) )
2022-03-22 10:43:25 +01:00
{
2022-11-02 09:40:19 -04:00
var actions = string . Join ( ", " , StringUtil . ConvertFromJson < HashSet < string > > ( node12Warnings ) ) ;
2022-03-22 10:43:25 +01:00
jobContext . Warning ( string . Format ( Constants . Runner . Node12DetectedAfterEndOfLife , actions ) ) ;
}
2019-10-10 00:52:42 -04:00
try
{
await ShutdownQueue ( throwOnFailure : true ) ;
}
catch ( Exception ex )
{
Trace . Error ( $"Caught exception from {nameof(JobServerQueue)}.{nameof(_jobServerQueue.ShutdownAsync)}" ) ;
Trace . Error ( "This indicate a failure during publish output variables. Fail the job to prevent unexpected job outputs." ) ;
Trace . Error ( ex ) ;
result = TaskResultUtil . MergeTaskResults ( result , TaskResult . Failed ) ;
}
// Clean TEMP after finish process jobserverqueue, since there might be a pending fileupload still use the TEMP dir.
_tempDirectoryManager ? . CleanupTempDirectory ( ) ;
2020-07-19 19:05:47 -04:00
if ( ! jobContext . Global . Features . HasFlag ( PlanFeatures . JobCompletedPlanEvent ) )
2019-10-10 00:52:42 -04:00
{
Trace . Info ( $"Skip raise job completed event call from worker because Plan version is {message.Plan.Version}" ) ;
return result ;
}
2021-09-29 15:49:31 -04:00
// Load any upgrade telemetry
2022-02-11 16:18:41 -05:00
LoadFromTelemetryFile ( jobContext . Global . JobTelemetry ) ;
2021-09-29 15:49:31 -04:00
2021-09-20 14:44:50 +02:00
// Make sure we don't submit secrets as telemetry
2022-02-11 16:18:41 -05:00
MaskTelemetrySecrets ( jobContext . Global . JobTelemetry ) ;
2021-09-20 14:44:50 +02:00
2022-02-16 12:18:21 -05:00
Trace . Info ( $"Raising job completed event" ) ;
2022-02-11 16:18:41 -05:00
var jobCompletedEvent = new JobCompletedEvent ( message . RequestId , message . JobId , result , jobContext . JobOutputs , jobContext . ActionsEnvironment , jobContext . Global . StepsTelemetry , jobContext . Global . JobTelemetry ) ;
2019-10-10 00:52:42 -04:00
var completeJobRetryLimit = 5 ;
var exceptions = new List < Exception > ( ) ;
while ( completeJobRetryLimit - - > 0 )
{
try
{
await jobServer . RaisePlanEventAsync ( message . Plan . ScopeIdentifier , message . Plan . PlanType , message . Plan . PlanId , jobCompletedEvent , default ( CancellationToken ) ) ;
return result ;
}
catch ( TaskOrchestrationPlanNotFoundException ex )
{
Trace . Error ( $"TaskOrchestrationPlanNotFoundException received, while attempting to raise JobCompletedEvent for job {message.JobId}." ) ;
Trace . Error ( ex ) ;
return TaskResult . Failed ;
}
catch ( TaskOrchestrationPlanSecurityException ex )
{
Trace . Error ( $"TaskOrchestrationPlanSecurityException received, while attempting to raise JobCompletedEvent for job {message.JobId}." ) ;
Trace . Error ( ex ) ;
return TaskResult . Failed ;
}
2020-05-21 11:09:50 -04:00
catch ( TaskOrchestrationPlanTerminatedException ex )
{
Trace . Error ( $"TaskOrchestrationPlanTerminatedException received, while attempting to raise JobCompletedEvent for job {message.JobId}." ) ;
Trace . Error ( ex ) ;
return TaskResult . Failed ;
}
2019-10-10 00:52:42 -04:00
catch ( Exception ex )
{
Trace . Error ( $"Catch exception while attempting to raise JobCompletedEvent for job {message.JobId}, job request {message.RequestId}." ) ;
Trace . Error ( ex ) ;
exceptions . Add ( ex ) ;
}
// delay 5 seconds before next retry.
await Task . Delay ( TimeSpan . FromSeconds ( 5 ) ) ;
}
// rethrow exceptions from all attempts.
throw new AggregateException ( exceptions ) ;
}
2021-09-20 14:44:50 +02:00
private void MaskTelemetrySecrets ( List < JobTelemetry > jobTelemetry )
{
foreach ( var telemetryItem in jobTelemetry )
{
telemetryItem . Message = HostContext . SecretMasker . MaskSecrets ( telemetryItem . Message ) ;
}
}
2021-09-29 15:49:31 -04:00
private void LoadFromTelemetryFile ( List < JobTelemetry > jobTelemetry )
{
try
{
var telemetryFilePath = HostContext . GetConfigFile ( WellKnownConfigFile . Telemetry ) ;
if ( File . Exists ( telemetryFilePath ) )
{
var telemetryData = File . ReadAllText ( telemetryFilePath , Encoding . UTF8 ) ;
var telemetry = new JobTelemetry
{
Message = $"Runner File Telemetry:\n{telemetryData}" ,
Type = JobTelemetryType . General
} ;
jobTelemetry . Add ( telemetry ) ;
IOUtil . DeleteFile ( telemetryFilePath ) ;
}
}
catch ( Exception e )
{
Trace . Error ( "Error when trying to load telemetry from telemetry file" ) ;
Trace . Error ( e ) ;
}
}
2019-10-10 00:52:42 -04:00
private async Task ShutdownQueue ( bool throwOnFailure )
{
if ( _jobServerQueue ! = null )
{
try
{
Trace . Info ( "Shutting down the job server queue." ) ;
await _jobServerQueue . ShutdownAsync ( ) ;
}
catch ( Exception ex ) when ( ! throwOnFailure )
{
Trace . Error ( $"Caught exception from {nameof(JobServerQueue)}.{nameof(_jobServerQueue.ShutdownAsync)}" ) ;
Trace . Error ( ex ) ;
}
finally
{
_jobServerQueue = null ; // Prevent multiple attempts.
}
}
}
}
}