mirror of
https://github.com/actions/runner.git
synced 2025-12-10 20:36:49 +00:00
start calling run service for job completion (#2412)
* start calling run service for job completion * cleanup * nit: lines Co-authored-by: Tingluo Huang <tingluohuang@github.com> * clean up * give sanity back to thboop Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com> * add clean up back * clean up * clean up more * oops * copied from existing, but :thumb: Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com> --------- Co-authored-by: Tingluo Huang <tingluohuang@github.com> Co-authored-by: Thomas Boop <52323235+thboop@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
24a27efd4f
commit
e6e5f36dd0
@@ -5,7 +5,6 @@ using GitHub.DistributedTask.Pipelines;
|
|||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Sdk;
|
using GitHub.Runner.Sdk;
|
||||||
using GitHub.Services.Common;
|
using GitHub.Services.Common;
|
||||||
using GitHub.Services.WebApi;
|
|
||||||
using Sdk.WebApi.WebApi.RawClient;
|
using Sdk.WebApi.WebApi.RawClient;
|
||||||
|
|
||||||
namespace GitHub.Runner.Common
|
namespace GitHub.Runner.Common
|
||||||
@@ -16,6 +15,8 @@ namespace GitHub.Runner.Common
|
|||||||
Task ConnectAsync(Uri serverUrl, VssCredentials credentials);
|
Task ConnectAsync(Uri serverUrl, VssCredentials credentials);
|
||||||
|
|
||||||
Task<AgentJobRequestMessage> GetJobMessageAsync(string id, CancellationToken token);
|
Task<AgentJobRequestMessage> GetJobMessageAsync(string id, CancellationToken token);
|
||||||
|
|
||||||
|
Task CompleteJobAsync(Guid planId, Guid jobId, CancellationToken token);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class RunServer : RunnerService, IRunServer
|
public sealed class RunServer : RunnerService, IRunServer
|
||||||
@@ -55,5 +56,11 @@ namespace GitHub.Runner.Common
|
|||||||
return jobMessage;
|
return jobMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task CompleteJobAsync(Guid planId, Guid jobId, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
CheckConnection();
|
||||||
|
return RetryRequest(
|
||||||
|
async () => await _runServiceHttpClient.CompleteJobAsync(requestUri, planId, jobId, cancellationToken), cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,19 @@ namespace GitHub.Runner.Common
|
|||||||
throw new InvalidOperationException(nameof(EstablishVssConnection));
|
throw new InvalidOperationException(nameof(EstablishVssConnection));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected async Task RetryRequest(Func<Task> func,
|
||||||
|
CancellationToken cancellationToken,
|
||||||
|
int maxRetryAttemptsCount = 5
|
||||||
|
)
|
||||||
|
{
|
||||||
|
async Task<Unit> wrappedFunc()
|
||||||
|
{
|
||||||
|
await func();
|
||||||
|
return Unit.Value;
|
||||||
|
}
|
||||||
|
await RetryRequest<Unit>(wrappedFunc, cancellationToken, maxRetryAttemptsCount);
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task<T> RetryRequest<T>(Func<Task<T>> func,
|
protected async Task<T> RetryRequest<T>(Func<Task<T>> func,
|
||||||
CancellationToken cancellationToken,
|
CancellationToken cancellationToken,
|
||||||
int maxRetryAttemptsCount = 5
|
int maxRetryAttemptsCount = 5
|
||||||
@@ -85,7 +98,7 @@ namespace GitHub.Runner.Common
|
|||||||
// TODO: Add handling of non-retriable exceptions: https://github.com/github/actions-broker/issues/122
|
// TODO: Add handling of non-retriable exceptions: https://github.com/github/actions-broker/issues/122
|
||||||
catch (Exception ex) when (retryCount < maxRetryAttemptsCount)
|
catch (Exception ex) when (retryCount < maxRetryAttemptsCount)
|
||||||
{
|
{
|
||||||
Trace.Error("Catch exception during get full job message");
|
Trace.Error("Catch exception during request");
|
||||||
Trace.Error(ex);
|
Trace.Error(ex);
|
||||||
var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(15));
|
var backOff = BackoffTimerHelper.GetRandomBackoff(TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(15));
|
||||||
Trace.Warning($"Back off {backOff.TotalSeconds} seconds before next retry. {maxRetryAttemptsCount - retryCount} attempt left.");
|
Trace.Warning($"Back off {backOff.TotalSeconds} seconds before next retry. {maxRetryAttemptsCount - retryCount} attempt left.");
|
||||||
|
|||||||
8
src/Runner.Common/Unit.cs
Normal file
8
src/Runner.Common/Unit.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
// Represents absence of value.
|
||||||
|
namespace GitHub.Runner.Common
|
||||||
|
{
|
||||||
|
public readonly struct Unit
|
||||||
|
{
|
||||||
|
public static readonly Unit Value = default;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -116,7 +116,7 @@ namespace GitHub.Runner.Sdk
|
|||||||
// settings are applied to an HttpRequestMessage.
|
// settings are applied to an HttpRequestMessage.
|
||||||
settings.AcceptLanguages.Remove(CultureInfo.InvariantCulture);
|
settings.AcceptLanguages.Remove(CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
RawConnection connection = new(serverUri, new RawHttpMessageHandler(credentials.ToOAuthCredentials(), settings), additionalDelegatingHandler);
|
RawConnection connection = new(serverUri, new RawHttpMessageHandler(credentials.Federated, settings), additionalDelegatingHandler);
|
||||||
return connection;
|
return connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ using System.Net.Http;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using GitHub.DistributedTask.Pipelines.ContextData;
|
|
||||||
using GitHub.DistributedTask.WebApi;
|
using GitHub.DistributedTask.WebApi;
|
||||||
using GitHub.Runner.Common;
|
using GitHub.Runner.Common;
|
||||||
using GitHub.Runner.Common.Util;
|
using GitHub.Runner.Common.Util;
|
||||||
@@ -40,21 +39,34 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Info("Job ID {0}", message.JobId);
|
Trace.Info("Job ID {0}", message.JobId);
|
||||||
|
|
||||||
DateTime jobStartTimeUtc = DateTime.UtcNow;
|
DateTime jobStartTimeUtc = DateTime.UtcNow;
|
||||||
|
IRunnerService server = null;
|
||||||
|
|
||||||
ServiceEndpoint systemConnection = message.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
ServiceEndpoint systemConnection = message.Resources.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (string.Equals(message.MessageType, JobRequestMessageTypes.RunnerJobRequest, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var runServer = HostContext.GetService<IRunServer>();
|
||||||
|
VssCredentials jobServerCredential = VssUtil.GetVssCredential(systemConnection);
|
||||||
|
await runServer.ConnectAsync(systemConnection.Url, jobServerCredential);
|
||||||
|
server = runServer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Setup the job server and job server queue.
|
||||||
|
var jobServer = HostContext.GetService<IJobServer>();
|
||||||
|
VssCredentials jobServerCredential = VssUtil.GetVssCredential(systemConnection);
|
||||||
|
Uri jobServerUrl = systemConnection.Url;
|
||||||
|
|
||||||
// Setup the job server and job server queue.
|
Trace.Info($"Creating job server with URL: {jobServerUrl}");
|
||||||
var jobServer = HostContext.GetService<IJobServer>();
|
// jobServerQueue is the throttling reporter.
|
||||||
VssCredentials jobServerCredential = VssUtil.GetVssCredential(systemConnection);
|
_jobServerQueue = HostContext.GetService<IJobServerQueue>();
|
||||||
Uri jobServerUrl = systemConnection.Url;
|
VssConnection jobConnection = VssUtil.CreateConnection(jobServerUrl, jobServerCredential, new DelegatingHandler[] { new ThrottlingReportHandler(_jobServerQueue) });
|
||||||
|
await jobServer.ConnectAsync(jobConnection);
|
||||||
|
|
||||||
Trace.Info($"Creating job server with URL: {jobServerUrl}");
|
_jobServerQueue.Start(message);
|
||||||
// jobServerQueue is the throttling reporter.
|
server = jobServer;
|
||||||
_jobServerQueue = HostContext.GetService<IJobServerQueue>();
|
}
|
||||||
VssConnection jobConnection = VssUtil.CreateConnection(jobServerUrl, jobServerCredential, new DelegatingHandler[] { new ThrottlingReportHandler(_jobServerQueue) });
|
|
||||||
await jobServer.ConnectAsync(jobConnection);
|
|
||||||
|
|
||||||
_jobServerQueue.Start(message);
|
|
||||||
HostContext.WritePerfCounter($"WorkerJobServerQueueStarted_{message.RequestId.ToString()}");
|
HostContext.WritePerfCounter($"WorkerJobServerQueueStarted_{message.RequestId.ToString()}");
|
||||||
|
|
||||||
IExecutionContext jobContext = null;
|
IExecutionContext jobContext = null;
|
||||||
@@ -99,7 +111,7 @@ namespace GitHub.Runner.Worker
|
|||||||
{
|
{
|
||||||
Trace.Error(ex);
|
Trace.Error(ex);
|
||||||
jobContext.Error(ex);
|
jobContext.Error(ex);
|
||||||
return await CompleteJobAsync(jobServer, jobContext, message, TaskResult.Failed);
|
return await CompleteJobAsync(server, jobContext, message, TaskResult.Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (jobContext.Global.WriteDebug)
|
if (jobContext.Global.WriteDebug)
|
||||||
@@ -136,7 +148,7 @@ namespace GitHub.Runner.Worker
|
|||||||
// don't log error issue to job ExecutionContext, since server owns the job level issue
|
// don't log error issue to job ExecutionContext, since server owns the job level issue
|
||||||
Trace.Error($"Job is cancelled during initialize.");
|
Trace.Error($"Job is cancelled during initialize.");
|
||||||
Trace.Error($"Caught exception: {ex}");
|
Trace.Error($"Caught exception: {ex}");
|
||||||
return await CompleteJobAsync(jobServer, jobContext, message, TaskResult.Canceled);
|
return await CompleteJobAsync(server, jobContext, message, TaskResult.Canceled);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -144,7 +156,7 @@ namespace GitHub.Runner.Worker
|
|||||||
// don't log error issue to job ExecutionContext, since server owns the job level issue
|
// don't log error issue to job ExecutionContext, since server owns the job level issue
|
||||||
Trace.Error($"Job initialize failed.");
|
Trace.Error($"Job initialize failed.");
|
||||||
Trace.Error($"Caught exception from {nameof(jobExtension.InitializeJob)}: {ex}");
|
Trace.Error($"Caught exception from {nameof(jobExtension.InitializeJob)}: {ex}");
|
||||||
return await CompleteJobAsync(jobServer, jobContext, message, TaskResult.Failed);
|
return await CompleteJobAsync(server, jobContext, message, TaskResult.Failed);
|
||||||
}
|
}
|
||||||
|
|
||||||
// trace out all steps
|
// trace out all steps
|
||||||
@@ -181,7 +193,7 @@ namespace GitHub.Runner.Worker
|
|||||||
// Log the error and fail the job.
|
// Log the error and fail the job.
|
||||||
Trace.Error($"Caught exception from job steps {nameof(StepsRunner)}: {ex}");
|
Trace.Error($"Caught exception from job steps {nameof(StepsRunner)}: {ex}");
|
||||||
jobContext.Error(ex);
|
jobContext.Error(ex);
|
||||||
return await CompleteJobAsync(jobServer, jobContext, message, TaskResult.Failed);
|
return await CompleteJobAsync(server, jobContext, message, TaskResult.Failed);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -192,7 +204,7 @@ namespace GitHub.Runner.Worker
|
|||||||
Trace.Info($"Job result after all job steps finish: {jobContext.Result ?? TaskResult.Succeeded}");
|
Trace.Info($"Job result after all job steps finish: {jobContext.Result ?? TaskResult.Succeeded}");
|
||||||
|
|
||||||
Trace.Info("Completing the job execution context.");
|
Trace.Info("Completing the job execution context.");
|
||||||
return await CompleteJobAsync(jobServer, jobContext, message);
|
return await CompleteJobAsync(server, jobContext, message);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -206,6 +218,66 @@ namespace GitHub.Runner.Worker
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
{
|
||||||
|
await runServer.CompleteJobAsync(message.Plan.PlanId, message.JobId, default);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<TaskResult> CompleteJobAsync(IJobServer jobServer, IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message, TaskResult? taskResult = null)
|
private async Task<TaskResult> CompleteJobAsync(IJobServer jobServer, IExecutionContext jobContext, Pipelines.AgentJobRequestMessage message, TaskResult? taskResult = null)
|
||||||
{
|
{
|
||||||
jobContext.Debug($"Finishing: {message.JobDisplayName}");
|
jobContext.Debug($"Finishing: {message.JobDisplayName}");
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
using GitHub.Services.OAuth;
|
|
||||||
|
|
||||||
namespace GitHub.Services.Common
|
|
||||||
{
|
|
||||||
public static class VssCredentialsExtension
|
|
||||||
{
|
|
||||||
public static VssOAuthCredential ToOAuthCredentials(
|
|
||||||
this VssCredentials credentials)
|
|
||||||
{
|
|
||||||
if (credentials.Federated.CredentialType == VssCredentialsType.OAuth)
|
|
||||||
{
|
|
||||||
return credentials.Federated as VssOAuthCredential;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -12,20 +12,20 @@ namespace GitHub.Services.Common
|
|||||||
public class RawHttpMessageHandler: HttpMessageHandler
|
public class RawHttpMessageHandler: HttpMessageHandler
|
||||||
{
|
{
|
||||||
public RawHttpMessageHandler(
|
public RawHttpMessageHandler(
|
||||||
VssOAuthCredential credentials)
|
FederatedCredential credentials)
|
||||||
: this(credentials, new RawClientHttpRequestSettings())
|
: this(credentials, new RawClientHttpRequestSettings())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public RawHttpMessageHandler(
|
public RawHttpMessageHandler(
|
||||||
VssOAuthCredential credentials,
|
FederatedCredential credentials,
|
||||||
RawClientHttpRequestSettings settings)
|
RawClientHttpRequestSettings settings)
|
||||||
: this(credentials, settings, new HttpClientHandler())
|
: this(credentials, settings, new HttpClientHandler())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public RawHttpMessageHandler(
|
public RawHttpMessageHandler(
|
||||||
VssOAuthCredential credentials,
|
FederatedCredential credentials,
|
||||||
RawClientHttpRequestSettings settings,
|
RawClientHttpRequestSettings settings,
|
||||||
HttpMessageHandler innerHandler)
|
HttpMessageHandler innerHandler)
|
||||||
{
|
{
|
||||||
@@ -56,7 +56,7 @@ namespace GitHub.Services.Common
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the credentials associated with this handler.
|
/// Gets the credentials associated with this handler.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public VssOAuthCredential Credentials
|
public FederatedCredential Credentials
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
private set;
|
private set;
|
||||||
@@ -111,7 +111,7 @@ namespace GitHub.Services.Common
|
|||||||
// Ensure that we attempt to use the most appropriate authentication mechanism by default.
|
// Ensure that we attempt to use the most appropriate authentication mechanism by default.
|
||||||
if (m_tokenProvider == null)
|
if (m_tokenProvider == null)
|
||||||
{
|
{
|
||||||
m_tokenProvider = this.Credentials.GetTokenProvider(request.RequestUri);
|
m_tokenProvider = this.Credentials.CreateTokenProvider(request.RequestUri, null, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +254,7 @@ namespace GitHub.Services.Common
|
|||||||
private CredentialWrapper m_credentialWrapper;
|
private CredentialWrapper m_credentialWrapper;
|
||||||
private object m_thisLock;
|
private object m_thisLock;
|
||||||
private const Int32 m_maxAuthRetries = 3;
|
private const Int32 m_maxAuthRetries = 3;
|
||||||
private VssOAuthTokenProvider m_tokenProvider;
|
private IssuedTokenProvider m_tokenProvider;
|
||||||
|
|
||||||
//.Net Core does not attempt NTLM schema on Linux, unless ICredentials is a CredentialCache instance
|
//.Net Core does not attempt NTLM schema on Linux, unless ICredentials is a CredentialCache instance
|
||||||
//This workaround may not be needed after this corefx fix is consumed: https://github.com/dotnet/corefx/pull/7923
|
//This workaround may not be needed after this corefx fix is consumed: https://github.com/dotnet/corefx/pull/7923
|
||||||
|
|||||||
@@ -42,9 +42,10 @@ namespace GitHub.DistributedTask.Pipelines
|
|||||||
IList<String> fileTable,
|
IList<String> fileTable,
|
||||||
TemplateToken jobOutputs,
|
TemplateToken jobOutputs,
|
||||||
IList<TemplateToken> defaults,
|
IList<TemplateToken> defaults,
|
||||||
ActionsEnvironmentReference actionsEnvironment)
|
ActionsEnvironmentReference actionsEnvironment,
|
||||||
|
String messageType = JobRequestMessageTypes.PipelineAgentJobRequest)
|
||||||
{
|
{
|
||||||
this.MessageType = JobRequestMessageTypes.PipelineAgentJobRequest;
|
this.MessageType = messageType;
|
||||||
this.Plan = plan;
|
this.Plan = plan;
|
||||||
this.JobId = jobId;
|
this.JobId = jobId;
|
||||||
this.JobDisplayName = jobDisplayName;
|
this.JobDisplayName = jobDisplayName;
|
||||||
|
|||||||
@@ -62,14 +62,38 @@ namespace GitHub.DistributedTask.WebApi
|
|||||||
StreamID = messageId
|
StreamID = messageId
|
||||||
};
|
};
|
||||||
|
|
||||||
|
requestUri = new Uri(requestUri, "acquirejob");
|
||||||
|
|
||||||
var payloadJson = JsonUtility.ToString(payload);
|
var payloadJson = JsonUtility.ToString(payload);
|
||||||
var requestContent = new StringContent(payloadJson, System.Text.Encoding.UTF8, "application/json");
|
var requestContent = new StringContent(payloadJson, System.Text.Encoding.UTF8, "application/json");
|
||||||
return SendAsync<Pipelines.AgentJobRequestMessage>(
|
return SendAsync<Pipelines.AgentJobRequestMessage>(
|
||||||
httpMethod,
|
httpMethod,
|
||||||
additionalHeaders: null,
|
|
||||||
requestUri: requestUri,
|
requestUri: requestUri,
|
||||||
content: requestContent,
|
content: requestContent,
|
||||||
cancellationToken: cancellationToken);
|
cancellationToken: cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task CompleteJobAsync(
|
||||||
|
Uri requestUri,
|
||||||
|
Guid planId,
|
||||||
|
Guid jobId,
|
||||||
|
CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
HttpMethod httpMethod = new HttpMethod("POST");
|
||||||
|
var payload = new {
|
||||||
|
PlanId = planId,
|
||||||
|
JobId = jobId
|
||||||
|
};
|
||||||
|
|
||||||
|
requestUri = new Uri(requestUri, "completejob");
|
||||||
|
|
||||||
|
var payloadJson = JsonUtility.ToString(payload);
|
||||||
|
var requestContent = new StringContent(payloadJson, System.Text.Encoding.UTF8, "application/json");
|
||||||
|
return SendAsync(
|
||||||
|
httpMethod,
|
||||||
|
requestUri,
|
||||||
|
content: requestContent,
|
||||||
|
cancellationToken: cancellationToken);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,6 +101,17 @@ namespace Sdk.WebApi.WebApi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Task<T> SendAsync<T>(
|
||||||
|
HttpMethod method,
|
||||||
|
Uri requestUri,
|
||||||
|
HttpContent content = null,
|
||||||
|
IEnumerable<KeyValuePair<String, String>> queryParameters = null,
|
||||||
|
Object userState = null,
|
||||||
|
CancellationToken cancellationToken = default(CancellationToken))
|
||||||
|
{
|
||||||
|
return SendAsync<T>(method, null, requestUri, content, queryParameters, userState, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
protected async Task<T> SendAsync<T>(
|
protected async Task<T> SendAsync<T>(
|
||||||
HttpMethod method,
|
HttpMethod method,
|
||||||
IEnumerable<KeyValuePair<String, String>> additionalHeaders,
|
IEnumerable<KeyValuePair<String, String>> additionalHeaders,
|
||||||
|
|||||||
@@ -16,9 +16,10 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
private IExecutionContext _jobEc;
|
private IExecutionContext _jobEc;
|
||||||
private JobRunner _jobRunner;
|
private JobRunner _jobRunner;
|
||||||
private List<IStep> _initResult = new();
|
private List<IStep> _initResult = new();
|
||||||
private Pipelines.AgentJobRequestMessage _message;
|
|
||||||
private CancellationTokenSource _tokenSource;
|
private CancellationTokenSource _tokenSource;
|
||||||
private Mock<IJobServer> _jobServer;
|
private Mock<IJobServer> _jobServer;
|
||||||
|
|
||||||
|
private Mock<IRunServer> _runServer;
|
||||||
private Mock<IJobServerQueue> _jobServerQueue;
|
private Mock<IJobServerQueue> _jobServerQueue;
|
||||||
private Mock<IConfigurationStore> _config;
|
private Mock<IConfigurationStore> _config;
|
||||||
private Mock<IExtensionManager> _extensions;
|
private Mock<IExtensionManager> _extensions;
|
||||||
@@ -38,6 +39,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_extensions = new Mock<IExtensionManager>();
|
_extensions = new Mock<IExtensionManager>();
|
||||||
_jobExtension = new Mock<IJobExtension>();
|
_jobExtension = new Mock<IJobExtension>();
|
||||||
_jobServer = new Mock<IJobServer>();
|
_jobServer = new Mock<IJobServer>();
|
||||||
|
_runServer = new Mock<IRunServer>();
|
||||||
_jobServerQueue = new Mock<IJobServerQueue>();
|
_jobServerQueue = new Mock<IJobServerQueue>();
|
||||||
_stepRunner = new Mock<IStepsRunner>();
|
_stepRunner = new Mock<IStepsRunner>();
|
||||||
_logger = new Mock<IPagingLogger>();
|
_logger = new Mock<IPagingLogger>();
|
||||||
@@ -55,33 +57,6 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_jobRunner = new JobRunner();
|
_jobRunner = new JobRunner();
|
||||||
_jobRunner.Initialize(hc);
|
_jobRunner.Initialize(hc);
|
||||||
|
|
||||||
TaskOrchestrationPlanReference plan = new();
|
|
||||||
TimelineReference timeline = new Timeline(Guid.NewGuid());
|
|
||||||
Guid jobId = Guid.NewGuid();
|
|
||||||
_message = new Pipelines.AgentJobRequestMessage(plan, timeline, jobId, testName, testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null);
|
|
||||||
_message.Variables[Constants.Variables.System.Culture] = "en-US";
|
|
||||||
_message.Resources.Endpoints.Add(new ServiceEndpoint()
|
|
||||||
{
|
|
||||||
Name = WellKnownServiceEndpointNames.SystemVssConnection,
|
|
||||||
Url = new Uri("https://pipelines.actions.githubusercontent.com"),
|
|
||||||
Authorization = new EndpointAuthorization()
|
|
||||||
{
|
|
||||||
Scheme = "Test",
|
|
||||||
Parameters = {
|
|
||||||
{"AccessToken", "token"}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
_message.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
|
||||||
{
|
|
||||||
Alias = Pipelines.PipelineConstants.SelfAlias,
|
|
||||||
Id = "github",
|
|
||||||
Version = "sha1"
|
|
||||||
});
|
|
||||||
_message.ContextData.Add("github", new Pipelines.ContextData.DictionaryContextData());
|
|
||||||
|
|
||||||
_initResult.Clear();
|
_initResult.Clear();
|
||||||
|
|
||||||
_jobExtension.Setup(x => x.InitializeJob(It.IsAny<IExecutionContext>(), It.IsAny<Pipelines.AgentJobRequestMessage>())).
|
_jobExtension.Setup(x => x.InitializeJob(It.IsAny<IExecutionContext>(), It.IsAny<Pipelines.AgentJobRequestMessage>())).
|
||||||
@@ -102,6 +77,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
|
|
||||||
hc.SetSingleton(_config.Object);
|
hc.SetSingleton(_config.Object);
|
||||||
hc.SetSingleton(_jobServer.Object);
|
hc.SetSingleton(_jobServer.Object);
|
||||||
|
hc.SetSingleton(_runServer.Object);
|
||||||
hc.SetSingleton(_jobServerQueue.Object);
|
hc.SetSingleton(_jobServerQueue.Object);
|
||||||
hc.SetSingleton(_stepRunner.Object);
|
hc.SetSingleton(_stepRunner.Object);
|
||||||
hc.SetSingleton(_extensions.Object);
|
hc.SetSingleton(_extensions.Object);
|
||||||
@@ -113,6 +89,43 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
return hc;
|
return hc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Pipelines.AgentJobRequestMessage GetMessage(String messageType = JobRequestMessageTypes.PipelineAgentJobRequest, [CallerMemberName] String testName = "")
|
||||||
|
{
|
||||||
|
TaskOrchestrationPlanReference plan = new();
|
||||||
|
TimelineReference timeline = new Timeline(Guid.NewGuid());
|
||||||
|
Guid jobId = Guid.NewGuid();
|
||||||
|
var message = new Pipelines.AgentJobRequestMessage(
|
||||||
|
plan,
|
||||||
|
timeline,
|
||||||
|
jobId,
|
||||||
|
testName,
|
||||||
|
testName, null, null, null, new Dictionary<string, VariableValue>(), new List<MaskHint>(), new Pipelines.JobResources(), new Pipelines.ContextData.DictionaryContextData(), new Pipelines.WorkspaceOptions(), new List<Pipelines.ActionStep>(), null, null, null, null,
|
||||||
|
messageType: messageType);
|
||||||
|
message.Variables[Constants.Variables.System.Culture] = "en-US";
|
||||||
|
message.Resources.Endpoints.Add(new ServiceEndpoint()
|
||||||
|
{
|
||||||
|
Name = WellKnownServiceEndpointNames.SystemVssConnection,
|
||||||
|
Url = new Uri("https://pipelines.actions.githubusercontent.com"),
|
||||||
|
Authorization = new EndpointAuthorization()
|
||||||
|
{
|
||||||
|
Scheme = "Test",
|
||||||
|
Parameters = {
|
||||||
|
{"AccessToken", "token"}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
message.Resources.Repositories.Add(new Pipelines.RepositoryResource()
|
||||||
|
{
|
||||||
|
Alias = Pipelines.PipelineConstants.SelfAlias,
|
||||||
|
Id = "github",
|
||||||
|
Version = "sha1"
|
||||||
|
});
|
||||||
|
message.ContextData.Add("github", new Pipelines.ContextData.DictionaryContextData());
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
[Trait("Level", "L0")]
|
[Trait("Level", "L0")]
|
||||||
[Trait("Category", "Worker")]
|
[Trait("Category", "Worker")]
|
||||||
@@ -123,7 +136,7 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
_jobExtension.Setup(x => x.InitializeJob(It.IsAny<IExecutionContext>(), It.IsAny<Pipelines.AgentJobRequestMessage>()))
|
_jobExtension.Setup(x => x.InitializeJob(It.IsAny<IExecutionContext>(), It.IsAny<Pipelines.AgentJobRequestMessage>()))
|
||||||
.Throws(new Exception());
|
.Throws(new Exception());
|
||||||
|
|
||||||
await _jobRunner.RunAsync(_message, _tokenSource.Token);
|
await _jobRunner.RunAsync(GetMessage(), _tokenSource.Token);
|
||||||
|
|
||||||
Assert.Equal(TaskResult.Failed, _jobEc.Result);
|
Assert.Equal(TaskResult.Failed, _jobEc.Result);
|
||||||
_stepRunner.Verify(x => x.RunAsync(It.IsAny<IExecutionContext>()), Times.Never);
|
_stepRunner.Verify(x => x.RunAsync(It.IsAny<IExecutionContext>()), Times.Never);
|
||||||
@@ -141,11 +154,24 @@ namespace GitHub.Runner.Common.Tests.Worker
|
|||||||
.Throws(new OperationCanceledException());
|
.Throws(new OperationCanceledException());
|
||||||
_tokenSource.Cancel();
|
_tokenSource.Cancel();
|
||||||
|
|
||||||
await _jobRunner.RunAsync(_message, _tokenSource.Token);
|
await _jobRunner.RunAsync(GetMessage(), _tokenSource.Token);
|
||||||
|
|
||||||
Assert.Equal(TaskResult.Canceled, _jobEc.Result);
|
Assert.Equal(TaskResult.Canceled, _jobEc.Result);
|
||||||
_stepRunner.Verify(x => x.RunAsync(It.IsAny<IExecutionContext>()), Times.Never);
|
_stepRunner.Verify(x => x.RunAsync(It.IsAny<IExecutionContext>()), Times.Never);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
[Trait("Level", "L0")]
|
||||||
|
[Trait("Category", "Worker")]
|
||||||
|
public async Task WorksWithRunnerJobRequestMessageType()
|
||||||
|
{
|
||||||
|
using (TestHostContext hc = CreateTestContext())
|
||||||
|
{
|
||||||
|
var message = GetMessage(JobRequestMessageTypes.RunnerJobRequest);
|
||||||
|
await _jobRunner.RunAsync(message, _tokenSource.Token);
|
||||||
|
Assert.Equal(TaskResult.Succeeded, _jobEc.Result);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user