-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Event driven script orchestrator (#1058)
Event driven script orchestrator Co-authored-by: Luke Butters <[email protected]> Co-authored-by: Samdanae Imran <[email protected]>
- Loading branch information
1 parent
930b260
commit 67b07ca
Showing
20 changed files
with
648 additions
and
459 deletions.
There are no files selected for viewing
26 changes: 26 additions & 0 deletions
26
source/Octopus.Tentacle.Client/EventDriven/CommandContext.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using Octopus.Tentacle.Client.Scripts; | ||
using Octopus.Tentacle.Contracts; | ||
|
||
namespace Octopus.Tentacle.Client.EventDriven | ||
{ | ||
/// <summary> | ||
/// This class holds the context of where we are up to within the script execution life cycle. | ||
/// When executing a script, there are several stages it goes through (e.g. starting the script, periodically checking status for completion, completing the script). | ||
/// To be able to progress through these cycles in an event-driven environment, we need to remember some state, and then keep passing that state back into the script executor. | ||
/// </summary> | ||
public class CommandContext | ||
{ | ||
public CommandContext(ScriptTicket scriptTicket, | ||
long nextLogSequence, | ||
ScriptServiceVersion scripServiceVersionUsed) | ||
{ | ||
ScriptTicket = scriptTicket; | ||
NextLogSequence = nextLogSequence; | ||
ScripServiceVersionUsed = scripServiceVersionUsed; | ||
} | ||
|
||
public ScriptTicket ScriptTicket { get; } | ||
public long NextLogSequence { get; } | ||
public ScriptServiceVersion ScripServiceVersionUsed { get; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Octopus.Tentacle.Client.EventDriven; | ||
using Octopus.Tentacle.Client.Execution; | ||
using Octopus.Tentacle.Client.Observability; | ||
using Octopus.Tentacle.Client.Scripts; | ||
using Octopus.Tentacle.Client.Scripts.Models; | ||
using Octopus.Tentacle.Client.ServiceHelpers; | ||
using Octopus.Tentacle.Contracts; | ||
using Octopus.Tentacle.Contracts.Logging; | ||
using Octopus.Tentacle.Contracts.Observability; | ||
|
||
namespace Octopus.Tentacle.Client | ||
{ | ||
/// <summary> | ||
/// Executes scripts, on the best available script service. | ||
/// </summary> | ||
public class ScriptExecutor : IScriptExecutor | ||
{ | ||
readonly ITentacleClientTaskLog logger; | ||
readonly ClientOperationMetricsBuilder operationMetricsBuilder; | ||
readonly TentacleClientOptions clientOptions; | ||
readonly AllClients allClients; | ||
readonly RpcCallExecutor rpcCallExecutor; | ||
readonly TimeSpan onCancellationAbandonCompleteScriptAfter; | ||
|
||
public ScriptExecutor(AllClients allClients, | ||
ITentacleClientTaskLog logger, | ||
ITentacleClientObserver tentacleClientObserver, | ||
TentacleClientOptions clientOptions, | ||
TimeSpan onCancellationAbandonCompleteScriptAfter) | ||
: this( | ||
allClients, | ||
logger, | ||
tentacleClientObserver, | ||
// For now, we do not support operation based metrics when used outside the TentacleClient. So just plug in a builder to discard. | ||
ClientOperationMetricsBuilder.Start(), | ||
clientOptions, | ||
onCancellationAbandonCompleteScriptAfter) | ||
{ | ||
} | ||
|
||
internal ScriptExecutor(AllClients allClients, | ||
ITentacleClientTaskLog logger, | ||
ITentacleClientObserver tentacleClientObserver, | ||
ClientOperationMetricsBuilder operationMetricsBuilder, | ||
TentacleClientOptions clientOptions, | ||
TimeSpan onCancellationAbandonCompleteScriptAfter) | ||
{ | ||
this.allClients = allClients; | ||
this.logger = logger; | ||
this.clientOptions = clientOptions; | ||
this.onCancellationAbandonCompleteScriptAfter = onCancellationAbandonCompleteScriptAfter; | ||
this.operationMetricsBuilder = operationMetricsBuilder; | ||
rpcCallExecutor = RpcCallExecutorFactory.Create(this.clientOptions.RpcRetrySettings.RetryDuration, tentacleClientObserver); | ||
} | ||
|
||
public async Task<ScriptOperationExecutionResult> StartScript(ExecuteScriptCommand executeScriptCommand, | ||
StartScriptIsBeingReAttempted startScriptIsBeingReAttempted, | ||
CancellationToken cancellationToken) | ||
{ | ||
var scriptServiceVersionToUse = await DetermineScriptServiceVersionToUse(cancellationToken); | ||
|
||
var scriptExecutorFactory = CreateScriptExecutorFactory(); | ||
var scriptExecutor = scriptExecutorFactory.CreateScriptExecutor(scriptServiceVersionToUse); | ||
|
||
return await scriptExecutor.StartScript(executeScriptCommand, startScriptIsBeingReAttempted, cancellationToken); | ||
} | ||
|
||
public async Task<ScriptOperationExecutionResult> GetStatus(CommandContext ticketForNextNextStatus, CancellationToken cancellationToken) | ||
{ | ||
var scriptExecutorFactory = CreateScriptExecutorFactory(); | ||
var scriptExecutor = scriptExecutorFactory.CreateScriptExecutor(ticketForNextNextStatus.ScripServiceVersionUsed); | ||
|
||
return await scriptExecutor.GetStatus(ticketForNextNextStatus, cancellationToken); | ||
} | ||
|
||
public async Task<ScriptOperationExecutionResult> CancelScript(CommandContext ticketForNextNextStatus) | ||
{ | ||
var scriptExecutorFactory = CreateScriptExecutorFactory(); | ||
var scriptExecutor = scriptExecutorFactory.CreateScriptExecutor(ticketForNextNextStatus.ScripServiceVersionUsed); | ||
|
||
return await scriptExecutor.CancelScript(ticketForNextNextStatus); | ||
} | ||
|
||
public async Task<ScriptStatus?> CompleteScript(CommandContext ticketForNextNextStatus, CancellationToken cancellationToken) | ||
{ | ||
var scriptExecutorFactory = CreateScriptExecutorFactory(); | ||
var scriptExecutor = scriptExecutorFactory.CreateScriptExecutor(ticketForNextNextStatus.ScripServiceVersionUsed); | ||
|
||
return await scriptExecutor.CompleteScript(ticketForNextNextStatus, cancellationToken); | ||
} | ||
|
||
ScriptExecutorFactory CreateScriptExecutorFactory() | ||
{ | ||
return new ScriptExecutorFactory(allClients, | ||
rpcCallExecutor, | ||
operationMetricsBuilder, | ||
onCancellationAbandonCompleteScriptAfter, | ||
clientOptions, | ||
logger); | ||
} | ||
|
||
async Task<ScriptServiceVersion> DetermineScriptServiceVersionToUse(CancellationToken cancellationToken) | ||
{ | ||
try | ||
{ | ||
var scriptServiceVersionSelector = new ScriptServiceVersionSelector(allClients.CapabilitiesServiceV2, logger, rpcCallExecutor, clientOptions, operationMetricsBuilder); | ||
return await scriptServiceVersionSelector.DetermineScriptServiceVersionToUse(cancellationToken); | ||
} | ||
catch (Exception ex) when (cancellationToken.IsCancellationRequested) | ||
{ | ||
throw new OperationCanceledException("Script execution was cancelled", ex); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
using System; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Octopus.Tentacle.Client.EventDriven; | ||
using Octopus.Tentacle.Client.Scripts.Models; | ||
using Octopus.Tentacle.Contracts; | ||
|
||
namespace Octopus.Tentacle.Client.Scripts | ||
{ | ||
public interface IScriptExecutor | ||
{ | ||
/// <summary> | ||
/// Start the script. | ||
/// </summary> | ||
/// <returns>The result, which includes the CommandContext for the next command</returns> | ||
Task<ScriptOperationExecutionResult> StartScript(ExecuteScriptCommand command, | ||
StartScriptIsBeingReAttempted startScriptIsBeingReAttempted, | ||
CancellationToken scriptExecutionCancellationToken); | ||
|
||
/// <summary> | ||
/// Get the status. | ||
/// </summary> | ||
/// <param name="commandContext">The CommandContext from the previous command</param> | ||
/// <param name="scriptExecutionCancellationToken"></param> | ||
/// <returns>The result, which includes the CommandContext for the next command</returns> | ||
Task<ScriptOperationExecutionResult> GetStatus(CommandContext commandContext, CancellationToken scriptExecutionCancellationToken); | ||
|
||
/// <summary> | ||
/// Cancel the script. | ||
/// </summary> | ||
/// <param name="commandContext">The CommandContext from the previous command</param> | ||
/// <returns>The result, which includes the CommandContext for the next command</returns> | ||
Task<ScriptOperationExecutionResult> CancelScript(CommandContext commandContext); | ||
|
||
/// <summary> | ||
/// Complete the script. | ||
/// </summary> | ||
/// <param name="commandContext">The CommandContext from the previous command</param> | ||
/// <param name="scriptExecutionCancellationToken"></param> | ||
Task<ScriptStatus?> CompleteScript(CommandContext commandContext, CancellationToken scriptExecutionCancellationToken); | ||
} | ||
} |
12 changes: 0 additions & 12 deletions
12
source/Octopus.Tentacle.Client/Scripts/IScriptOrchestrator.cs
This file was deleted.
Oops, something went wrong.
11 changes: 0 additions & 11 deletions
11
source/Octopus.Tentacle.Client/Scripts/IScriptOrchestratorFactory.cs
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.