NAME
Win32::ServiceManager - Manage Windows Services
VERSION
version 0.003000
SYNOPSIS
use Win32::ServiceManager;
my $sc = Win32::ServiceManager->new(
nssm_path => $your_nssm_path,
);
$sc->create_service(
name => 'GRWebServer01',
display => 'Giant Robot Web Server 1',
description => 'Handles Web Requests on port 3001',
command => 'your_script.pl --port 3001',
);
$sc->start_service('GRWebServer01', { non_blocking => 0 });
$sc->stop_service('GRWebServer01');
$sc->delete_service('GRWebServer01');
METHODS
create_service
$sc->create_service(
name => 'GRWeb1',
display => 'Giant Robot Web Worker 1',
description => 'Handles Giant Robot Web Requests on port 3001',
use_perl => 1,
use_nssm => 1,
command => 'C:\code\GR\script\server.pl -p 3001',
depends => [qw(MSSQL Apache2.4)],
start => 'delayed-auto',
user => 'DOMAIN\username',
password => 'hunter2',
);
Takes a hash of the following arguments:
name
(required) The name of the service (which is used when doing a
sc start
etc.)use_nssm
(defaults to the value of "use_nssm_default") Set this to start your service with "nssm"
use_perl
(defaults to the value of "use_perl_default") Set this to create perl services. Uses
$^X
. If for some reason you want to use a different perl you will have to setuse_perl
to false.display
(required) The display name to give the service
description
(optional) The description to give the service.
check_command
(defaults to the value of "check_command_default") This will check that the command you passed exists on the filesystem and if it does not exists it will die
command
(required) The command that is effectively your service
args
(optional) Arguments that get passed to the command above. XXX: do these even make sense?
depends
(optional) List of service names that must be started for your service to function. You may either pass a string or an array ref. A string gets passed on directly, the array reference gets properly joined together.
start
(optional) The start type for the service. If left blank, the default value is auto. Available start types are
boot
system
auto
demand
disabled
delayed-auto
.Note: The default value when using
sc
isdemand
. The default value in this package isauto
to maintain compatibility with previous versions.user
(optional) The user account under which to run the service. If left blank, the default value is LocalSystem.
password
(optional) The password credential for
user
. Required for any other user than LocalSystem. If a blank password is desired, use an empty string.idempotent
(defaults to the value of "idempotent_default") Set this to get errors if the service already exists. Note that unlike the other methods this one is not %100 idempotent. If a service has the exact same name but a different command it this will mask that problem. I am willing to resolve this if you have patches on how to read this information (preferably without diving into the registry.)
Note: there are many options that sc
can use to create and modify services. I have taken the few that we use in my project and forced the rest upon you, gentle user. For example, whether you like it or not these services will restart on failure. I am completely willing to add more options, but in 4 distinct projects we have never needed more than the above. Patches Welcome!
start_service
$sc->start_service('GRWeb1', { non_blocking => 1 });
Starts a service with the passed name. The second argument is an optional hashref with the following options:
non_blocking
(defaults to the value of "non_blocking_default") Set this to false if you want to block until the service starts.
idempotent
(defaults to the value of "idempotent_default") Set this to false if you want errors when the service is already started or starting.
stop_service
$sc->stop_service('GRWeb1', { non_blocking => 1 });
Stops a service with the passed name. The second argument is an optional hashref with the following options:
non_blocking
(defaults to the value of "non_blocking_default") Set this to false if you want to block until the service stops.
idempotent
(defaults to the value of "idempotent_default") Set this to false if you want errors when the service is already stopped or stopping
restart_service
$sc->restart_service('GRWeb1', { non_blocking => 1 });
Stops and starts a service with the passed name. The second argument is an optional hashref with the following options:
non_blocking
(defaults to the value of "non_blocking_default") Set this to false if you want to block until the service starts. (Note that the blocking until the service has stopped is required.)
idempotent
(defaults to the value of "idempotent_default") Set this to false if you want errors when the service is already stopped or stopping
get_status
$sc->start_service('GRWeb1')
unless $sc->get_status('GRWeb1')->{current_state} eq 'running';
Returns the status info about the specified service. The status info is a hash containing the following keys:
Note that for reasons unknown to me the underlying win32 GetStatus
call fails when restarting services, so I added a retry counter. If you are interested in finding out when and how seriously your services fail the count, turn on "warnings".
current_state
Can be any of the following
stopped
start pending
stop pending
running
continue pending
pause pending
paused
Note that there is much more information that could be included in get_status
, but I've only needed the current_state
so far. If you need something else I will gladly add more information to the returned hash, or better yet, send a patch.
get_services
my $services = $sc->get_services;
say "$_ is installed!" for keys %$services;
Returns a hashref of services. Keys are the display name, values are the real name.
delete_service
$sc->delete_service('GRWeb1', { idempotent => 0 });
Deletes a service
autostop
(defaults to false) Set this to true if you want the service to be stopped in addition to being deleted. If you set it to a hash reference the options will be passed along to "stop_service". For example a sensible thing to do is:
$sc->delete_service(GRWeb1 => { autostop => { non_blocking => 0 } });
as that should ensure that the service is truly gone after the code runs.
idempotent
(defaults to the value of "idempotent_default") Set this to false if you want errors when the service doesn't exist
ATTRIBUTES
check_command_default
The default value of check_command
for the "create_service" method. Default is true.
use_nssm_default
The default value of use_nssm
for the "create_service" method.
use_perl_default
The default value of use_perl
for the "create_service" method.
idempotent_default
Set this to true (default) to idempotently start, stop, delete, and create services.
non_blocking_default
Set this to true (default) to asyncronously to start or stop services. Sometimes blocking is better as it allows for restarts, for example.
nssm_path
Set this to the path to nssm (default is just nssm_64.exe
, or nssm_32.exe
if you set "nssm_bits" to 32).
nssm_bits
"nssm" comes in both 32 and 64 bit flavors. This specifies when of the bundled nssm
binaries to use. (default is 64)
warnings
Set this to true to get warnings for non-serious failures. Currently the only such warning is in "get_status".
nssm
nssm is a handy service wrapper for Windows. Instead of adding hooks directly to your program to handly Windows service signals, this program runs your program for you and intercepts the signals and acts appropriately. It is open source and clocks in at less than two megabytes of RAM. The code is at git://git.nssm.cc/nssm/nssm.git
.
PRO-TIPS
The best way to use this module is to subclass it for your software. So for example we have a subclass that looks something like the following:
package GiantRobot::ServiceManager;
use Moo;
extends 'Win32::ServiceManager';
our $DIR = file(__FILE__)->parent->absolute;
sub create_catalyst_service {
my ($self, $i) = @_;
$self->create_service(
name => "GRWebServer$i",
display => "GRWeb Server $i",
description => 'Handles Web Requests on port 3001',
command =>
$dir->file(qw( App script server.pl ))->stringify .
" -p 300$i",
);
}
sub start_catalyst_service { $_[0]->start_service("GRWebServer$_[1]", $_[2]) }
...
The above makes it very easy for use to start, stop, add, and remove catalyst services.
CAVEAT LECTOR
This module has been used in production from Windows Server 2008 - 2022. It should also work fine on desktop versions of Windows as long as the sc
interface stays the same. The included tests can do no better than ensure the generated strings are as expected, instead of ensuring that a service was correctly created or started or whatever.
Additionally, in my own work when I get an error from sc
I just report it and move forward. Because of this I have done very little to make exceptions useful. I am open to making them objects but again, I do not need that myself, so Patches Welcome!
AUTHORS
Arthur Axel "fREW" Schmidt <frioux+cpan@gmail.com>
Wes Malone <wesm@cpan.org>
COPYRIGHT AND LICENSE
This software is copyright (c) 2024 by Arthur Axel "fREW" Schmidt.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.