I recently encountered a client with a Windows Service that was slowly leaking memory. The Windows Service was developed in .NET (hence managed code) but it used third-party, unmanaged C++ DLLs from another vendor and hence the leak. There was no way to upgrade to the latest version of the vendor's unmanaged DLLs so the simply way to address the memory leak was to restart the service every three days.
.NET provides a method so an application can stop a Windows service and a method so an application can start a Windows service. .NET does not provide a Windows service restart method. A Windows service can stop itself but once stopped it does not have a means by which to start itself. Specifically the ServiceController class (assembly: System.ServiceProcess.dll, namespace: System.ServiceProcess) can manage a specific Windows Service and this class contains a Start and Stop method.
Since the service cannot restart itself, Windows Scheduler will be used to run a task that stops and starts the service, hence a Windows service restart. The command used to stop and start the server will be NET STOP and NET START respectively. Windows Scheduler will also be configured to run the task every three days.
For demonstration purposes, the Windows service acted against will be "SQL Server VSS Writer". This service was selected because it is only used when a SQL Server database is backup and and a backup device takes a backup snapshot (hence not used on my development machine). The SQL Server VSS Writer is show below where the service is started and set to automatically start:
NET START/STOP
To start the service using NET START:
1) Run a console window as an administrator:
1.1) In the Windows 10 search field enter CMD (this step will differ depending on the version of Windows you are running) and right click on "Command Prompt" and select "Run as administrator":
1.2) In the Windows 7 search field enter CMD and right click on "cmd.exe" and select "Run as administrator":
2) In order to stop the Windows service, NET STOP will be invoked.In the Console Window enter NET STOP <windows service name> which for the SQL Server VSS Writer service is as follows:
3) When NET STOP is run successfully it behaves as follows:
Starting a service is simply a matter of invoking NET START <windows service name>:
To make creating a restart task simpler, create a batch file names LeakRestart.bat and include the following two commands:
Windows Scheduler
To run Windows Task Schedule type "Task" in the Windows' search field select "Task Scheduler" or to be exact type in Taskschd.msc and select "Task Scheduler":
Additionally Task Scheduler can be reached from Control Panel | System and Maintenance | Administrative Tools | Task Scheduler.
Task Scheduler appears as follows:
In order to create a task, click on "Create Task" from the Actions panel:
The Windows service needs to restart even if a user is not logged in. Additionally, administrative privileges are required to stop and start a service.
The user "When running the task" should be changed to a local local administrators as opposed to an active user. In order to change the user account for the task click on "Change User or Group..."
Select Object Types which displays:
In the Object Types dialog insure that only Groups is checked the click on OK which closes the "Object Types" dialog and displays the Select User or Group dialog but with "Object Types" set to Groups (see below):
From the "Select User or Group" dialog select the "Advanced" button:
The "Advanced" button displays the "Select User or Group" with advanced options showing. Click on the "Find Now" button:
Notice the local Administrators group was selected for the local machine. This is the local Administrators group because the "In Folder" column is the local machine as opposed to the domain. The selected group is the exact group we want to select. Click on "OK" which displays the less-advanced version of "the Select User or Group" dialog:
Click on OK to close the dialog thus returning to the "Create Task" dialog:
Notice in the previous screenshot that the "use the following account' is set to BUILTIN\Administrators.
Under the General tab enter:
- Name: set value to Restart to Handle Leak
- Checked "Run with highest privileges.
- Under Configure for set to the current operating system (which for this example is Windows 7)
The final Create Task | General tab screen shout appear as follows:
Note: the task will fail if "Run with highest priveleges" is not set.
Select the Triggers tab from the Create Task dialog:
Select the New button to create a trigger that will run the task once every three days:
In order to create a once every three days trigger select "Daily" under "Settings":
Set "Recur every" to 3 day. Note the "Start" date/time can specified to a convenient start date and a time when it is appropriate to restart the Windows service.
Once the recurrence has be specified to Daily, recur every 3 days, click on "OK" from the New Trigger dialog which closes the New Trigger dialog:
Closing the New Trigger dialog displays the "Create Task" dialog again which now contains the newly created trigger (see below):
Select the Actions tab which is where we will specify the action which invokes the LeakRestart.bat batch file. The Create Task | Actions tab is as follows:
Click on New to create a new action via the New Action dialog:
Select "Browse..." which displays the Open dialog and from this dialog (see below) navigate to the location of the LeakRestart.bat batch file and select said file:
Click on Open closes the Open dialog return to the Create Task | Actions screen which now includes the newly created Action:
Click OK to create the task return to Create Task | Actions:
Testing
It is possible to run a task manually from Window Scheduler.in order to test of said task works. The "gotch ya" with this task is that is stops and restarts a Windows service so simply running the task does not show a change. In order to test, the batch file should be tweaked to only stop the Windows service (for testing purposes only) because this will verify if the batch file can run and has the correct permissions, etc.
The steps to test are:
1) Edit the LeakRestart.bat such that it only stops the Windows service and then save this batch file. This edit is simply a matter of placing a REM in front of the NET START command as follows:
NET STOP "SQL Server VSS Writer"
REM NET START "SQL Server VSS Writer"
2) Open Windows Scheduler and under "Task Scheduler (Local)"select "Task Scheduler Library":
Notice that the "Restart to Handle Leak" task is listed.
3) Right click on the "Restart to Handle Leak" task and select Run:
4) To verify that the task execute successfully check the Control Panel | System and Security | Administrative Tools | Services. The Windows Service should be stopped:
Notice in the Service windows that the selected Windows Service is not "Started" hence it is stopped.
In order to restore normal behavior post testing:
1) Started the Windows service from the Services dialog.
2) Remote the REM before NET START from LeakRestart.bat. The correct version of the batch file is as follows:
NET STOP "SQL Server VSS Writer"
NET START "SQL Server VSS Writer"