How to Set Up NSSM Service Using an Idempotent Approach

Testing NSSM removal of service and introduce some consistency when performing mutable deployment

ยท

3 min read

How to Set Up NSSM Service Using an Idempotent Approach

Context

I was attempting to automate a mutable deployment for an application service on a Windows EC2 instance with NSSM. However, I faced difficulties trying to setup an idempotent workflow, whereby the service will be configured and running successfully for each execution.

Issues

I faced issues in removing the NSSM service in a clean manner, which includes issues such as:

  • The service has been marked for deletion: This means while NSSM has removed the service, hence out of its scope, Windows still interpret as the service exists as not all processes have been closed.

  • The installation step has been seemingly skipped. This subsequently affects the downstream steps using NSSM to reinstall the service with the same name.

This may be a race condition or side effects for mutable application deployments.

Insights

I read through the NSSM official documentation to understand how the underlying mechanism of removing a service. The "Service shutdown" section caught my attention.

It seems that there are four stages which NSSM can use to shut down the application and by default it will attempt all four in the following order:

  1. Generate Control-C event to application's console

  2. Enumerate all windows created by application and send a WM_CLOSE message

  3. Enumerate all threads created by the application and send WM_QUIT message.

  4. Call TerminateProcess() as the last resort to request for the operating system to forcibly terminate the application

The key information that got me thinking is as quoted below:

By default nssm will wait up to 1500 milliseconds for the application to exit after trying each of the methods describe above.

Perhaps, the key to idempotency is to stop the service then remove the service with NSSM.

Testing

Script to be executed as service

For simplicity, I am using a simple PowerShell script, hello-world.ps1 to output some messages at a periodical manner.

Write-Output "Hello World"

Write-Output "Now sleep for 20 seconds"

Start-Sleep 20

Write-Output "Hellow World, I am awake"

PowerShell Script to configure NSSM Serice

Below is the PowerShell script setup-nssm-svc.ps1, to configure the NSSM service:

# PowerShell script to setup the NSSM service

## To replace the target directory path with the appropriate local file path
$targetDirectory="/PATH/TO/DIR/WITH/SCRIPTFILE"
$scriptFile = "$targetDirectory\hello-world.ps1"

## Defining NSSM parameters
$powershell = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
$arguments = "powershell $scriptFile"
$stdinPath = "$targetDirectory\app.log"
$stdoutPath = "$targetDirectory\app.log"
$stderrPath = "$targetDirectory\app.log"

$serviceName = "test-svc"

## To check if the NSSM service already exists
if ( (Get-CimInstance win32_service | ?{$_.PathName -Like '*nssm*'}).Name ) {
    echo "Service already exists. Will stop the service before proceeding to re-installing the service again"
    ## Stop the service and give it time to process
    nssm stop $serviceName
    Start-Sleep 10

    ## Proceed to remove the NSSM service
    nssm remove $serviceName confirm
} else {
    echo "Service does not exist, will proceed to install the service"
}


## Setting up the target NSSM service
nssm install $serviceName $powershell $arguments
nssm set $serviceName AppDirectory "$targetDirectory"

nssm set $serviceName AppStdin "$stdinPath"
nssm set $serviceName AppStdout "$stdoutPath"
nssm set $serviceName AppStderr "$stderrPath"

echo "[Before] Service status"
nssm status $serviceName
nssm start $serviceName

echo "[After] Service status"
nssm status $serviceName

Results

  1. When running setup-nssm-svc.ps1 the first time, you can observe from the output that test-svc service has been configured successfully.

  2. Upon running setup-nssm-svc.ps1 again, the script detects that the service already exists, it will first stop the service before removing it. You can see that NSSM is able to install the same service again successfully.

Caveats

  • Considering that the application used is a simple PowerShell script, this workflow may still not work well for more complex applications.

  • You may still need to introduce Start-Sleep to give the Windows processes time to complete. In this case, perhaps the minimum wait duration should be at least 60 seconds for NSSM's 4 stages of shutting down of services.

Did you find this article valuable?

Support Nuggets of Wisdom by becoming a sponsor. Any amount is appreciated!

ย