mirror of https://github.com/winsw/winsw
* #183 - Add core logic for the DelayedStart option support * #183 - Add unit tests * #183 - Update documentation and the configuration sample * #183 - Use API calls to set the DelayedAutoStart flag as @jtnord proposed * #183 - Refactor the project to use `delayedAutoStart`pull/209/head
parent
5c71911e7b
commit
d192c03638
|
@ -53,12 +53,24 @@ This gets displayed in Windows service manager when the service is selected.
|
|||
This element specifies the executable to be launched.
|
||||
It can be either absolute path, or you can just specify the executable name and let it be searched from `PATH` (although note that the services often run in a different user account and therefore it might have different `PATH` than your shell does.)
|
||||
|
||||
### startmode - Optional Element
|
||||
### startmode
|
||||
This element specifies the start mode of the Windows service.
|
||||
It can be one of the following values: Boot, System, Automatic, or Manual.
|
||||
See [MSDN](https://msdn.microsoft.com/en-us/library/aa384896%28v=vs.85%29.aspx) for details.
|
||||
The default value is `Automatic`.
|
||||
|
||||
### delayedAutoStart
|
||||
|
||||
This Boolean option enables the delayed start mode if the `Automatic` start mode is defined.
|
||||
More information about this mode is provided [here](https://blogs.technet.microsoft.com/askperf/2008/02/02/ws2008-startup-processes-and-delayed-automatic-start/).
|
||||
|
||||
Please note that this startup mode will not take affect on old Windows versions older than Windows 7 and Windows Server 2008.
|
||||
Windows service installation may fail in such case.
|
||||
|
||||
```xml
|
||||
<delayedAutoStart/>
|
||||
```
|
||||
|
||||
### depend
|
||||
Specify IDs of other services that this service depends on.
|
||||
When service `X` depends on service `Y`, `X` can only run if `Y` is running.
|
||||
|
|
|
@ -162,6 +162,13 @@ SECTION: Service management
|
|||
-->
|
||||
<startmode>Automatic</startmode>
|
||||
|
||||
<!--
|
||||
OPTION: delayedAutoStart
|
||||
Enables the Delayed Automatic Start if 'Automatic' is specified in the 'startmode' field.
|
||||
See the WinSW documentation to get info about supported platform versions and limitations.
|
||||
-->
|
||||
<!--<delayedAutoStart/>-->
|
||||
|
||||
<!--
|
||||
OPTION: depend
|
||||
Optionally specifies services that must start before this service starts.
|
||||
|
|
|
@ -606,13 +606,24 @@ namespace winsw
|
|||
.OpenSubKey(d.Id, true).SetValue("Description", d.Description);
|
||||
|
||||
var actions = d.FailureActions;
|
||||
if (actions.Count > 0)
|
||||
{// set the failure actions
|
||||
var isDelayedAutoStart = d.StartMode == StartMode.Automatic && d.DelayedAutoStart;
|
||||
if (actions.Count > 0 || isDelayedAutoStart)
|
||||
{
|
||||
using (ServiceManager scm = new ServiceManager())
|
||||
{
|
||||
using (Service sc = scm.Open(d.Id))
|
||||
{
|
||||
sc.ChangeConfig(d.ResetFailureAfter, actions);
|
||||
// Delayed auto start
|
||||
if (isDelayedAutoStart)
|
||||
{
|
||||
sc.SetDelayedAutoStart(true);
|
||||
}
|
||||
|
||||
// Set the failure actions
|
||||
if (actions.Count > 0)
|
||||
{
|
||||
sc.ChangeConfig(d.ResetFailureAfter, actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ namespace winsw.Configuration
|
|||
|
||||
// Service management
|
||||
public StartMode StartMode { get { return StartMode.Automatic; } }
|
||||
public bool DelayedAutoStart { get { return false; } }
|
||||
public string[] ServiceDependencies { get { return new string[0]; } }
|
||||
public TimeSpan WaitHint { get { return TimeSpan.FromSeconds(15); } }
|
||||
public TimeSpan SleepTime { get { return TimeSpan.FromSeconds(1); } }
|
||||
|
|
|
@ -79,6 +79,26 @@ namespace winsw.Native
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the DelayedAutoStart flag.
|
||||
/// It will be applioed to services with Automatic startup mode only.
|
||||
/// If the platform does not support this flag, an exception may be thrown.
|
||||
/// </summary>
|
||||
/// <param name="enabled">Value to set</param>
|
||||
/// <exception cref="Exception">Operation failure, e.g. the OS does not support this flag</exception>
|
||||
public void SetDelayedAutoStart(bool enabled)
|
||||
{
|
||||
SERVICE_DELAYED_AUTO_START settings = new SERVICE_DELAYED_AUTO_START
|
||||
{
|
||||
fDelayedAutostart = enabled
|
||||
};
|
||||
|
||||
if (!Advapi32.ChangeServiceConfig2(Handle, SERVICE_CONFIG_INFOLEVEL.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, ref settings))
|
||||
{
|
||||
throw new Exception("Failed to change the DelayedAutoStart setting", new Win32Exception());
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (Handle!=IntPtr.Zero)
|
||||
|
@ -261,6 +281,10 @@ namespace winsw.Native
|
|||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, ref SERVICE_FAILURE_ACTIONS sfa);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, ref SERVICE_DELAYED_AUTO_START sfa);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern IntPtr OpenSCManager(string machineName, string databaseName, uint dwAccess);
|
||||
|
||||
|
@ -569,4 +593,12 @@ namespace winsw.Native
|
|||
public int cActions;
|
||||
public IntPtr/*SC_ACTION[]*/ lpsaActions;
|
||||
}
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms685155(v=vs.85).aspx
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct SERVICE_DELAYED_AUTO_START
|
||||
{
|
||||
[MarshalAs(UnmanagedType.Bool)]
|
||||
public bool fDelayedAutostart;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -475,6 +475,18 @@ namespace winsw
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the service should be installed with the DelayedAutoStart flag.
|
||||
/// This setting will be applyed only during the install command and only when the Automatic start mode is configured.
|
||||
/// </summary>
|
||||
public bool DelayedAutoStart
|
||||
{
|
||||
get
|
||||
{
|
||||
return dom.SelectSingleNode("//delayedAutoStart") != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// True if the service should beep when finished on shutdown.
|
||||
/// This doesn't work on some OSes. See http://msdn.microsoft.com/en-us/library/ms679277%28VS.85%29.aspx
|
||||
|
|
|
@ -355,5 +355,17 @@ namespace winswTests
|
|||
.ToServiceDescriptor(true);
|
||||
Assert.That(sd.Arguments, Is.EqualTo(" --arg2=123 --arg3=null"));
|
||||
}
|
||||
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
public void DelayedStart_RoundTrip(bool enabled)
|
||||
{
|
||||
var bldr = ConfigXmlBuilder.create();
|
||||
if (enabled) {
|
||||
bldr = bldr.WithDelayedAutoStart();
|
||||
}
|
||||
var sd = bldr.ToServiceDescriptor();
|
||||
Assert.That(sd.DelayedAutoStart, Is.EqualTo(enabled));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,5 +144,10 @@ namespace winswTests.Util
|
|||
|
||||
return WithRawEntry(str.ToString());
|
||||
}
|
||||
|
||||
public ConfigXmlBuilder WithDelayedAutoStart()
|
||||
{
|
||||
return WithRawEntry("<delayedAutoStart/>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue