lib/Classes/Public/TMBrokerSubject.ps1
class TMBrokerSubject { #region Non-Static Properties [TMBrokerSubjectAction]$Action = [TMBrokerSubjectAction]::new() [Int32]$Order = 0 [TMTask]$Task = [TMTask]::new() [Int32]$ProjectId = $this.Task.Project.Id [TMBrokerSubjectAsset]$Asset = [TMBrokerSubjectAsset]::new() [Object]$ActionRequest #endregion Non-Static Properties #region Constructors TMBrokerSubject() {} TMBrokerSubject([TMTask]$task) { $this.ProjectId = $task.Project.Id $this.Task = $task $this.Asset = [TMBrokerSubjectAsset]::new($task.Asset) $this.Action = [TMBrokerSubjectAction]::new($task.Action) } TMBrokerSubject([TMTask]$task, [Nullable[Int32]]$order = 0) { $this.Order = $order $this.ProjectId = $task.Project.Id $this.Task = $task $this.Asset = [TMBrokerSubjectAsset]::new($task.Asset) $this.Action = [TMBrokerSubjectAction]::new($task.Action) } TMBrokerSubject([TMTask]$task, [PSCustomObject]$action, [Nullable[Int32]]$order = 0) { $this.Order = $order $this.ProjectId = $task.Project.Id $this.Task = $task $this.Asset = [TMBrokerSubjectAsset]::new($task.Asset) $this.Action = [TMBrokerSubjectAction]::new($action) } #endregion Constructors #region Non-Static Methods [void]UpdateActionSettings([Object]$MethodParams) { if ($MethodParams -is [String]) { $MethodParams = ($MethodParams | ConvertFrom-Json -Depth 5) } if (-not ($MethodParams -is [TMTaskActionMethodParam[]])) { $MethodParams = $MethodParams | ForEach-Object { [TMTaskActionMethodParam]::new($_) } } # See what settings were configured on the Action in TM $NewSettings = [TMBrokerSubjectActionSettings]::GetSettingsFromMethodParams($MethodParams) # Check if the retry settings need to be updated if ($this.Action.Settings.Retry.Count -ne $NewSettings.Retry.Count) { # Settings have been updated in TM. Apply them [TMBrokerOutput]::Verbose("Updating Retry settings for Task #: $($this.Task.TaskNumber)") $this.Action.Settings.Retry = $NewSettings.Retry } # Check if the timeout settings need to be updated if ($this.Action.Settings.Timeout.Seconds -ne $NewSettings.Timeout.Seconds) { # Settings have been updated in TM. Apply them [TMBrokerOutput]::Verbose("Updating Timeout settings for Task #: $($this.Task.TaskNumber)") $this.Action.Settings.Timeout = $NewSettings.Timeout } # Update the settings' timing based on the Task's last updated timestamp if ($this.Task.LastUpdated) { switch ($this.Task.Status) { 'Hold' { $this.Action.Settings.Retry.SetNextRetryDate($this.Task.LastUpdated.ToLocalTime()) } 'Started' { # If the LastUpdated time is newer, use it to set the timeout if ( (-not $this.Action.InvokedAt) -or (($null -ne $this.Action.InvokedAt) -and ($this.Task.LastUpdated.ToLocalTime() -gt $this.Action.InvokedAt))) { $this.Action.Settings.Timeout.SetTimeoutDate($this.Task.LastUpdated.ToLocalTime()) } } default {} } } } [void]QueueRetry([String]$TMSession) { $this.Action.Settings.Retry.RemainingRetries-- $this.Action.ExecutionStatus = 'Pending' try { [TMBrokerOutput]::Verbose("Resetting Task - Number: $($this.Task.TaskNumber), Id: $($this.Task.Id), Title: $($this.Task.Title)") Reset-TMTaskAction -TMSession $TMSession -TaskId $this.Task.Id } catch { [TMBrokerOutput]::Warning("Could not reset Task # $($this.Task.TaskNumber): $($_.Exception.Message)") } try { $TaskNote = "Action reset. Retry $($this.Action.Settings.Retry.Count - $this.Action.Settings.Retry.RemainingRetries) of $($this.Action.Settings.Retry.Count)" [TMBrokerOutput]::Verbose("Updating Task # $($this.Task.TaskNumber) with note: $TaskNote") $this.Task | Update-TMTask -TMSession $TMSession -Status 'Ready' -Note $TaskNote $this.Task.Status = 'Ready' } catch { [TMBrokerOutput]::Warning("Could not update Task # $($this.Task.TaskNumber): $($_.Exception.Message)") } } [void]Timeout([String]$TMSession) { $this.Action.ExecutionStatus = 'Failed' try { $TaskNote = "Action Timed out after $($this.Action.Settings.Timeout.Minutes) minutes" [TMBrokerOutput]::Verbose("Updating Task # $($this.Task.TaskNumber) with note: $TaskNote") $this.Task | Update-TMTask -TMSession $TMSession -Status 'Hold' -Note $TaskNote $this.Task.Status = 'Hold' } catch { [TMBrokerOutput]::Warning("Could not update Task # $($this.Task.TaskNumber): $($_.Exception.Message)") } } [void]Invoke([Object]$TMSession, [Object]$Cache) { try { [TMBrokerOutput]::Verbose("Invoking Task - Number: $($this.Task.TaskNumber), Id: $($this.Task.Id), Title: $($this.Task.Title)") Invoke-SubjectTaskAction -TMSession $TMSession -Subject $this -Cache $Cache } catch { $ErrorString = $_.Exception.Message if ($ErrorString -match 'The argument .*?Started.*? does not belong') { [TMBrokerOutput]::Info("This Subject Task has already been started elsewhere.", 'Magenta') return } else { [TMBrokerOutput]::Info("Invoking the Task failed: $($ErrorString)", 'Magenta') return } } } [void]Invoke([Object]$TMSession) { try { [TMBrokerOutput]::Verbose("Invoking Task - Number: $($this.Task.TaskNumber), Id: $($this.Task.Id), Title: $($this.Task.Title)") Invoke-SubjectTaskAction -TMSession $TMSession -Subject $this } catch { $ErrorString = $_.Exception.Message if ($ErrorString -match 'The argument .*?Started.*? does not belong') { [TMBrokerOutput]::Info("This Subject Task has already been started elsewhere.", 'Magenta') return } else { [TMBrokerOutput]::Info("Invoking the Task failed: $($ErrorString)", 'Magenta') return } } } [void]InvokeParallel([Object]$TMSession, [Object]$Cache) { ## Invoke Parallel execution tasks. This sends the ActionRequest to SessionManager for execution try { [TMBrokerOutput]::Verbose("Invoking Task - Number: $($this.Task.TaskNumber), Id: $($this.Task.Id), Title: $($this.Task.Title)") Invoke-SubjectTaskActionParallel -TMSession $TMSession -Subject $this -Cache $Cache } catch { $ErrorString = $_.Exception.Message if ($ErrorString -match 'The argument .*?Started.*? does not belong') { [TMBrokerOutput]::Info("This Subject Task has already been started elsewhere.", 'Magenta') return } else { [TMBrokerOutput]::Info("Invoking the Task failed: $($ErrorString)", 'Magenta') return } } } [void]InvokeParallel([Object]$TMSession) { try { [TMBrokerOutput]::Verbose("Invoking Task - Number: $($this.Task.TaskNumber), Id: $($this.Task.Id), Title: $($this.Task.Title)") Invoke-SubjectTaskActionParallel -TMSession $TMSession -Subject $this } catch { $ErrorString = $_.Exception.Message if ($ErrorString -match 'The argument .*?Started.*? does not belong') { [TMBrokerOutput]::Info("This Subject Task has already been started elsewhere.", 'Magenta') return } else { [TMBrokerOutput]::Info("Invoking the Task failed: $($ErrorString)", 'Magenta') return } } } #endregion Non-Static Methods } class TMBrokerSubjectAction { #region Non-Static Properties [Int32]$Id = 0 [String]$Script [TMTaskActionMethodParam[]]$Params = @() [String]$Name [TMBrokerSubjectActionSettings]$Settings = [TMBrokerSubjectActionSettings]::new() [ValidateSet('Started', 'Pending', 'Successful', 'Failed')] [String]$ExecutionStatus = 'Pending' #endregion Non-Static Properties #region Private Fields hidden [Nullable[DateTime]]$_invokedAt #endregion Private Fields #region Constructors TMBrokerSubjectAction() { $this.addPublicMembers() } TMBrokerSubjectAction([Int32]$id, [String]$script, [TMTaskActionMethodParam[]]$params, [String]$name) { $this.Id = $id $this.Params = $params $this.Name = $name $this.Settings = [TMBrokerSubjectActionSettings]::GetSettingsFromMethodParams($params) $this.addPublicMembers() } TMBrokerSubjectAction([Object]$object) { $this.Id = $object.Id $this.Script = $object.Script $this.Params = $object.methodParams $this.Name = $object.Name $this.Settings = [TMBrokerSubjectActionSettings]::GetSettingsFromMethodParams($object.methodParams) $this.addPublicMembers() } #endregion Constructors #region Private Methods hidden [void]addPublicMembers() { $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'ShouldTimeout', { # get return ( $this.Settings.Timeout.Enabled -and ((Get-Date) -ge $this.Settings.Timeout.TimeoutDate) ) } ) ) $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'ShouldRetry', { # get return ( $this.Settings.Retry.Enabled -and ($this.Settings.Retry.RemainingRetries -gt 0) -and ((Get-Date) -ge $this.Settings.Retry.NextRetryDate) ) } ) ) $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'InvokedAt', { # get return $this._invokedAt }, { # set param ($value) $this._invokedAt = $value $this.Settings.Timeout.SetTimeoutDate($value) } ) ) } #endregion Private Methods } class TMBrokerSubjectActionSettings { #region Non-Static Properties [TMBrokerSubjectActionRetrySetting]$Retry = [TMBrokerSubjectActionRetrySetting]::new() [TMBrokerSubjectActionTimeoutSetting]$Timeout = [TMBrokerSubjectActionTimeoutSetting]::new() #endregion Non-Static Properties #region Constructors TMBrokerSubjectActionSettings() {} TMBrokerSubjectActionSettings([Int32]$retryCount, [Int32]$retryWaitSeconds, [Int32]$timeoutSeconds) { $this.Retry = [TMBrokerSubjectActionRetrySetting]::new($retryCount, $retryWaitSeconds) $this.Timeout = [TMBrokerSubjectActionTimeoutSetting]::new($timeoutSeconds) } TMBrokerSubjectActionSettings([Object]$object) { $this.Retry = [TMBrokerSubjectActionRetrySetting]::new($object.RetryCount, $object.RetryWaitSeconds) $this.Timeout = [TMBrokerSubjectActionTimeoutSetting]::new($object.TimeoutSeconds) } #endregion Constructors #region Static Methods static [TMBrokerSubjectActionSettings]GetSettingsFromMethodParams([TMTaskActionMethodParam[]]$MethodParams) { $ActionSettings = [PSCustomObject]@{ RetryCount = 0 RetryWaitSeconds = 30 TimeoutSeconds = 0 } $SettingParams = $MethodParams | Where-Object { ($_.Context -eq 'USER_DEF') -and ($_.ParamName -match 'brokersetting_') -and (-not [String]::IsNullOrWhiteSpace($_.Value)) } foreach ($Param in $SettingParams) { switch (($Param.ParamName -split '_')[1]) { 'RetryCount' { $ActionSettings.RetryCount = [Int32]$Param.Value } { $_ -in 'RetryWaitSeconds', 'WaitSeconds' } { $ActionSettings.RetryWaitSeconds = [Int32]$Param.Value } { $_ -in 'RetryWaitMinutes', 'WaitMinutes' } { $ActionSettings.RetryWaitSeconds = [Int32]$Param.Value * 60 } { $_ -in 'Timeout', 'TimeoutMinutes' } { $ActionSettings.TimeoutSeconds = [Int32]$Param.Value * 60 } 'TimeoutSeconds' { $ActionSettings.TimeoutSeconds = [Int32]$Param.Value } default { } } } return [TMBrokerSubjectActionSettings]::new($ActionSettings) } #endregion Static Methods } class TMBrokerSubjectActionTimeoutSetting { #region Private Fields hidden [Nullable[DateTime]]$_timeoutDate hidden [Int32]$_seconds = 0 #endregion Private Fields #region Constructors TMBrokerSubjectActionTimeoutSetting() { $this.addPublicMembers() $this.SetTimeoutDate((Get-Date).AddYears(10)) } TMBrokerSubjectActionTimeoutSetting([Int32]$seconds) { $this.addPublicMembers() $this._seconds = $seconds $this.SetTimeoutDate((Get-Date)) } #endregion Constructors #region Non-Static Methods [void]SetTimeoutDate([Nullable[DateTime]]$LastUpdated) { if ($null -ne $lastUpdated) { $this._timeoutDate = $LastUpdated.AddSeconds($this._seconds) } } [String]ToString() { return "$($this._timeoutDate)" } #endregion Non-Static Methods #region Private Methods hidden [void]addPublicMembers() { $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'Seconds', { # get return $this._seconds } ) ) $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'Minutes', { # get return ($this._seconds -ge 60 ? [Math]::Round(($this._seconds / 60)) : [Math]::Round(($this._seconds / 60) , 1)) } ) ) $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'TimeoutDate', { # get return $this._timeoutDate } ) ) $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'Enabled', { # get return ($this._seconds -gt 0) } ) ) } #endregion Private Methods } class TMBrokerSubjectActionRetrySetting { #region Non-Static Properties [Int32]$RemainingRetries = 0 #endregion Non-Static Properties #region Private Fields hidden [Int32]$_count = 0 hidden [Int32]$_waitSeconds = 0 hidden [Nullable[DateTime]]$_nextRetryDate #endregion Private Fields #region Constructors TMBrokerSubjectActionRetrySetting() { $this.addPublicMembers() $this.SetNextRetryDate((Get-Date).AddYears(10)) } TMBrokerSubjectActionRetrySetting([Int32]$count, [Int32]$waitSeconds) { $this.addPublicMembers() $this._count = $count $this.RemainingRetries = $count $this._waitSeconds = $waitSeconds $this.SetNextRetryDate((Get-Date)) } TMBrokerSubjectActionRetrySetting([Object]$object) { $this.addPublicMembers() $this._count = $object.Count $this.RemainingRetries = $object.Count $this._waitSeconds = $object.WaitSeconds $this.SetNextRetryDate((Get-Date)) } #endregion Constructors #region Non-Static Methods [void]SetNextRetryDate([Nullable[DateTime]]$LastUpdated) { $this._nextRetryDate = ${LastUpdated}?.AddSeconds($this._waitSeconds) ?? (Get-Date).AddSeconds($this._waitSeconds) } [String]ToString() { return "$($this._nextRetryDate)" } #endregion Non-Static Methods #region Private Methods hidden [void]addPublicMembers() { $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'Count', { # get return $this._count } ) ) $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'WaitSeconds', { # get return $this._waitSeconds } ) ) $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'WaitMinutes', { # get return ($this._waitSeconds -ge 60 ? ([Math]::Round(($this._waitSeconds / 60))) : ([Math]::Round(($this._waitSeconds / 60), 1))) } ) ) $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'NextRetryDate', { # get return $this._nextRetryDate } ) ) $this.PSObject.Properties.Add( [PSScriptProperty]::new( 'Enabled', { # get return ($this._count -gt 0) } ) ) } #endregion Private Methods } class TMBrokerSubjectAsset { #region Non-Static Properties [Int32]$Id [String]$Name [String]$Class [String]$Type [TMReference]$Bundle #endregion Non-Static Properties #region Constructors TMBrokerSubjectAsset() {} TMBrokerSubjectAsset([Int32]$id, [String]$name, [String]$class, [String]$type, [TMReference]$bundle) { $this.Id = $id $this.Name = $name $this.Class = $class $this.Type = $type $this.Bundle = [TMReference]::new($bundle) } TMBrokerSubjectAsset([Object]$object) { $this.Id = $object.Id $this.Name = $object.Name $this.Class = $object.Class $this.Type = $object.Type $this.Bundle = [TMReference]::new($object.Bundle) } #endregion Constructors } |