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 $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 $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' Reset-TMTaskAction -TMSession $TMSession -TaskId $this.Task.Id $this.Task | Update-TMTask -TMSession $TMSession -Status 'Ready' -Note "Action reset. Retry $($this.Action.Settings.Retry.Count - $this.Action.Settings.Retry.RemainingRetries) of $($this.Action.Settings.Retry.Count)" $this.Task.Status = 'Ready' } [void]Timeout([String]$TMSession) { $this.Action.ExecutionStatus = 'Failed' $this.Task | Update-TMTask -TMSession $TMSession -Status 'Hold' -Note "Action Timed out after $($this.Action.Settings.Timeout.Minutes) minutes" $this.Task.Status = 'Hold' } [void]Invoke([String]$TMSession, [Object]$Cache) { try { Invoke-SubjectTaskAction -TMSession $TMSession -Subject $this -Cache $Cache } catch { $ErrorString = $_.Exception.Message if ($ErrorString -match 'The argument .*?Started.*? does not belong') { Write-Host "[$(Get-Date -Format "HH:mm:ss.ffff")] This Subject Task has already been started elsewhere." -ForegroundColor Magenta return } else { Write-Host "[$(Get-Date -Format "HH:mm:ss.ffff")] Invoking the Task failed: [$($ErrorString)]" -ForegroundColor Magenta return } } } [void]Invoke([String]$TMSession) { try { Invoke-SubjectTaskAction -TMSession $TMSession -Subject $this } catch { $ErrorString = $_.Exception.Message if ($ErrorString -match '"The argument "Started" does not belong') { Write-Host "[$(Get-Date -Format "HH:mm:ss.ffff")] This Subject Task has already been started elsewhere." -ForegroundColor Magenta return } else { Write-Host "[$(Get-Date -Format "HH:mm:ss.ffff")] Invoking the Task failed: [$($ErrorString)]" -ForegroundColor Magenta return } } } [void]InvokeParallel([String]$TMSession, [Object]$Cache) { ## Invoke Parallel execution tasks. This sends the ActionRequest to SessionManager for execution try { Invoke-SubjectTaskActionParallel -TMSession $TMSession -Subject $this -Cache $Cache } catch { $ErrorString = $_.Exception.Message if ($ErrorString -match '"The argument "Started" does not belong') { Write-Host "[$(Get-Date -Format "HH:mm:ss.ffff")] This Subject Task has already been started elsewhere." -ForegroundColor Magenta return } else { Write-Host "[$(Get-Date -Format "HH:mm:ss.ffff")] Invoking the Task failed: [$($ErrorString)]" -ForegroundColor Magenta return } } } [void]InvokeParallel([String]$TMSession) { try { Invoke-SubjectTaskActionParallel -TMSession $TMSession -Subject $this } catch { $ErrorString = $_.Exception.Message if ($ErrorString -match '"The argument "Started" does not belong') { Write-Host "[$(Get-Date -Format "HH:mm:ss.ffff")] This Subject Task has already been started elsewhere." -ForegroundColor Magenta return } else { Write-Host "[$(Get-Date -Format "HH:mm:ss.ffff")] Invoking the Task failed: [$($ErrorString)]" -ForegroundColor 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' hidden [Nullable[DateTime]]$_invokedAt #endregion Non-Static Properties #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 Non-Static Methods hidden addPublicMembers() { $MemberSplat = @{ Name = 'ShouldTimeout' MemberType = 'ScriptProperty' Value = { return ( $this.Settings.Timeout.Enabled -and ((Get-Date) -ge $this.Settings.Timeout.TimeoutDate) ) } SecondValue = { Write-Warning "This is a readonly property" } } $this | Add-Member @MemberSplat $MemberSplat = @{ Name = 'ShouldRetry' MemberType = 'ScriptProperty' Value = { return ( $this.Settings.Retry.Enabled -and ($this.Settings.Retry.RemainingRetries -gt 0) -and ((Get-Date) -ge $this.Settings.Retry.NextRetryDate) ) } SecondValue = { Write-Warning "This is a readonly property" } } $this | Add-Member @MemberSplat $MemberSplat = @{ Name = 'InvokedAt' MemberType = 'ScriptProperty' Value = { return $this._invokedAt } SecondValue = { param($value) $this._invokedAt = $value $this.Settings.Timeout.SetTimeoutDate($value) } } $this | Add-Member @MemberSplat } #endregion Non-Static 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 Non-Static Properties #endregion Non-Static Properties #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 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 } |