1

I am creating a build server right now and trying to run builds in parallel, however when a build fails I wish to send a global variable flag to tell other build servers to Finnish their build then stop without exiting the whole script half way. To do this I was hoping to use global variables however it doesn't seem to pickup changes to the value when i change it from another script. Here are the three example scripts I have to see if I can get this to work:

Here is the main script that calls the other two scripts in parallel

$global:BUILD_FAILED = $false

function failBuild
{
    $global:BUILD_FAILED = $true
}

function buildHasFailed
{
    if ($global:BUILD_FAILED -eq $false)
    {
        return $false
    }
    else
    {
        return $true
    }
}

$test1 = Start-Job -Name "test1" -FilePath "C:\Users\username\Desktop\Untitled2.ps1"
$test2 = Start-Job -Name "test2" -FilePath "C:\Users\username\Desktop\Untitled3.ps1"

while ($test1.State -eq "Running" -or $test2.State -eq "Running")
{
    Receive-Job $test1
    Receive-Job $test2
}

Write-Host "Test0 finnish:"
$global:BUILD_FAILED
if (buildHasFailed)
{
    Write-Host "Fail"
    Exit 1
}

Write-Host "Pass"
Exit 0

And here are the two scripts for testing how to change the value in one script and see a result:

function failBuild
{
    $global:BUILD_FAILED = $true
}

function buildHasFailed
{
    if ($global:BUILD_FAILED -eq $false)
    {
        return $false
    }
    else
    {
        return $true
    }
}

Write-Host "Test2 started, $global:BUILD_FAILED"
buildHasFailed
Write-Host "Test2 sleeping 10s"
Start-Sleep -Milliseconds 10000
Write-Host "Test2 $global:BUILD_FAILED"
buildHasFailed

Exit 0

and:

function failBuild
{
    $global:BUILD_FAILED = $true
}

function buildHasFailed
{
    if ($global:BUILD_FAILED -eq $false)
    {
        return $false
    }
    else
    {
        return $true
    }
}

Write-Host "Test1 started, $global:BUILD_FAILED, sleeping 5s"
Start-Sleep -Milliseconds 5000
failBuild
Write-Host "Test1 ending, Status:"
buildHasFailed
$global:BUILD_FAILED

Exit 0

My current output is:

Test1 started, , sleeping 5s
Test2 started, 
True
Test2 sleeping 10s
Test1 ending, Status:
True
True
Test2 
True
Test0 finnish:
False
Pass

and I'm expecting after test1 sets $global:BUILD_FAILED to true the rest of the outputs should be false however its not updating.

Any suggestions?

2
  • The first thing that I will point out that GLOBAL: is not really global. It is only global to the powershell session that the script is running in. I would suggest using a DB field or a semaphore file instead. Commented Jul 5, 2018 at 12:45
  • Each Job is a completely different enviroment, also note the additinal powerhsell.exe processes when creating Jobs, the best way to handle this is to monitor the Jobs en close the others when one failes, Wait-Job can do this, another option is to monitor a specific file. Commented Jul 5, 2018 at 12:47

2 Answers 2

3

In Powershell, each job runs in a new session. Every new session is created in a new global scope. Therefore you cannot use a global variable between jobs. One option would perhaps be to set a "Machine" system environment variable and use that?

[Environment]::SetEnvironmentVariable("BUILD_FAILED", "1", "Machine")

Then read out the value using

[Environment]::GetEnvironmentVariable("BUILD_FAILED", "Machine")

Remove this temporary system environment variable when done with

[Environment]::SetEnvironmentVariable("BUILD_FAILED", $null, "Machine")

Another option for you could be using "Runspaces". I have found this article for you here https://learn-powershell.net/2013/04/19/sharing-variables-and-live-objects-between-powershell-runspaces/

Finally you could opt for writing a file containing the global value?

Sign up to request clarification or add additional context in comments.

Comments

1

It might be better to monitor your jobs and terminate the others when a sinlge job is failed, see below for an example.

#Init
Clear-Host
$VerbosePreference = 'Continue'

#Special Function
Function Wait-BuildJob {
    Param(
        [Parameter(Mandatory=$true)]
        [ValidateNotNull()]
        $BuildJob
    )

    $BuildJob | Wait-Job -Any | ForEach-Object {

        if ($_.State -eq 'Failed') {
            # Show information about the 'Failed' Job.
            Write-Warning "Job $($_.Name) has $($_.State), stopping all remaining BuildJobs..."

            # Terminate all other Jobs.
            $BuildJob | Stop-Job


        }

        Else {
            # Show information about the current Job and remove the JobData.
            Write-Verbose "Job $($_.Name) retuned with state $($_.State)"
            $_ | Stop-Job -PassThru | Remove-Job
        }


        # Wait for further BuildJobs
        $RemainingBuildJobs = $BuildJob | Where-Object Id -ne $_.Id
        If ($RemainingBuildJobs) {

            Wait-BuildJob -BuildJob $RemainingBuildJobs
        }
    }

}

# ------------------------------------------------
#                    Script Start
# ------------------------------------------------
$ScriptStartDateTime = Get-Date

# A place to store the BuildJobs
$BuildJobs = @()

# Create a few dummy Jobs
1..4 | ForEach-Object {
    $BuildJobs += Start-Job -Name "Build$($_)" -ScriptBlock {
        Start-Sleep -Seconds 60
    }
}

# Create a Job that should fail
$BuildJobs += Start-Job -Name Build5 -ScriptBlock {
    Start-Sleep -Seconds 5
    throw "build failed somehow"
    Start-Sleep -Seconds 60
}

# Create some more dummy Jobs
6..10 | ForEach-Object {
    $BuildJobs += Start-Job -Name "Build$($_)" -ScriptBlock {
        Start-Sleep -Seconds 60
    }
}

# Wait for BuildJobs to complete.
Wait-BuildJob -BuildJob $BuildJobs

# Show Runtime for Build
$RunTime = (Get-date) - $ScriptStartDateTime
Write-Verbose "Total RunTime in Secconds: $($RunTime.TotalSeconds)"

Example Output with failed job:

WARNING: Job Build5 has Failed, stopping all remaining BuildJobs...
VERBOSE: Job Build1 retuned with state Stopped
VERBOSE: Job Build2 retuned with state Stopped
VERBOSE: Job Build3 retuned with state Stopped
VERBOSE: Job Build4 retuned with state Stopped
VERBOSE: Job Build6 retuned with state Stopped
VERBOSE: Job Build7 retuned with state Stopped
VERBOSE: Job Build8 retuned with state Stopped
VERBOSE: Job Build9 retuned with state Stopped
VERBOSE: Job Build10 retuned with state Stopped
VERBOSE: Total RunTime in Secconds: 5.943828

Example output without failed job:

VERBOSE: Job Build1 retuned with state Completed
VERBOSE: Job Build2 retuned with state Completed
VERBOSE: Job Build3 retuned with state Completed
VERBOSE: Job Build4 retuned with state Completed
VERBOSE: Job Build5 retuned with state Completed
VERBOSE: Job Build6 retuned with state Completed
VERBOSE: Job Build7 retuned with state Completed
VERBOSE: Job Build8 retuned with state Completed
VERBOSE: Job Build10 retuned with state Completed
VERBOSE: Job Build9 retuned with state Completed
VERBOSE: Total RunTime in Secconds: 61.9364418

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.