mirror of https://github.com/winsw/winsw
Integrated failure action.
Also improved the timespan support. Defaulting to ms for backward compatibility.pull/18/head
parent
becb2d249a
commit
0eaa554ed3
|
@ -46,7 +46,7 @@ namespace Advapi32
|
|||
Handle = service;
|
||||
}
|
||||
|
||||
public void ChangeConfig(TimeSpan failureResetPeriod, SC_ACTION[] actions)
|
||||
public void ChangeConfig(TimeSpan failureResetPeriod, List<SC_ACTION> actions)
|
||||
{
|
||||
SERVICE_FAILURE_ACTIONS sfa = new SERVICE_FAILURE_ACTIONS();
|
||||
sfa.dwResetPeriod = failureResetPeriod.Seconds;
|
||||
|
@ -55,11 +55,11 @@ namespace Advapi32
|
|||
|
||||
int len = Marshal.SizeOf(typeof(SC_ACTION));
|
||||
|
||||
sfa.cActions = actions.Length;
|
||||
sfa.lpsaActions = Marshal.AllocHGlobal(len * actions.Length);
|
||||
sfa.cActions = actions.Count;
|
||||
sfa.lpsaActions = Marshal.AllocHGlobal(len * actions.Count);
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < actions.Length; i++)
|
||||
for (int i = 0; i < actions.Count; i++)
|
||||
{
|
||||
Marshal.StructureToPtr(actions[i], new IntPtr(sfa.lpsaActions.ToInt64() + i * len), false);
|
||||
}
|
||||
|
|
28
Main.cs
28
Main.cs
|
@ -336,7 +336,7 @@ namespace winsw
|
|||
{
|
||||
// WriteEvent("WaitForProcessToExit [start]");
|
||||
|
||||
while (!process.WaitForExit(descriptor.SleepTime))
|
||||
while (!process.WaitForExit(descriptor.SleepTime.Milliseconds))
|
||||
{
|
||||
SignalShutdownPending();
|
||||
// WriteEvent("WaitForProcessToExit [repeat]");
|
||||
|
@ -354,7 +354,7 @@ namespace winsw
|
|||
{
|
||||
IntPtr handle = this.ServiceHandle;
|
||||
wrapperServiceStatus.checkPoint++;
|
||||
wrapperServiceStatus.waitHint = descriptor.WaitHint;
|
||||
wrapperServiceStatus.waitHint = descriptor.WaitHint.Milliseconds;
|
||||
// WriteEvent("SignalShutdownPending " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
|
||||
wrapperServiceStatus.currentState = (int)State.SERVICE_STOP_PENDING;
|
||||
SetServiceStatus(handle, ref wrapperServiceStatus);
|
||||
|
@ -500,6 +500,18 @@ namespace winsw
|
|||
// so using a classic method to set the description. Ugly.
|
||||
Registry.LocalMachine.OpenSubKey("System").OpenSubKey("CurrentControlSet").OpenSubKey("Services")
|
||||
.OpenSubKey(d.Id, true).SetValue("Description", d.Description);
|
||||
|
||||
var actions = d.FailureActions;
|
||||
if (actions.Count > 0)
|
||||
{// set the failure actions
|
||||
using (Advapi32.ServiceManager scm = new Advapi32.ServiceManager())
|
||||
{
|
||||
using (Advapi32.Service sc = scm.Open(d.Id))
|
||||
{
|
||||
sc.ChangeConfig(d.ResetFailureAfter, actions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (args[0] == "uninstall")
|
||||
{
|
||||
|
@ -551,18 +563,6 @@ namespace winsw
|
|||
else
|
||||
Console.WriteLine("Stopped");
|
||||
}
|
||||
if (args[0] == "autorestart")
|
||||
{// debug only. to be removed.
|
||||
using (Advapi32.ServiceManager scm = new Advapi32.ServiceManager())
|
||||
{
|
||||
using (Advapi32.Service sc = scm.Open(d.Id))
|
||||
{
|
||||
SC_ACTION[] lpsaActions = new SC_ACTION[1];
|
||||
lpsaActions[0] = new SC_ACTION(SC_ACTION_TYPE.SC_ACTION_RESTART, 1000);
|
||||
sc.ChangeConfig(TimeSpan.FromHours(48),lpsaActions);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (args[0] == "test")
|
||||
{
|
||||
WrapperService wsvc = new WrapperService();
|
||||
|
|
|
@ -13,6 +13,8 @@ using WMI;
|
|||
using System.Xml;
|
||||
using System.Threading;
|
||||
using Microsoft.Win32;
|
||||
using Advapi32;
|
||||
|
||||
namespace winsw
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -96,6 +98,41 @@ namespace winsw
|
|||
}
|
||||
}
|
||||
|
||||
private TimeSpan SingleTimeSpanElement(XmlNode parent, string tagName, TimeSpan defaultValue)
|
||||
{
|
||||
var e = parent.SelectSingleNode(tagName);
|
||||
|
||||
if (e == null)
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
string v = e.InnerText;
|
||||
foreach (var s in SUFFIX) {
|
||||
if (v.EndsWith(s.Key))
|
||||
{
|
||||
return TimeSpan.FromMilliseconds(int.Parse(v.Substring(0,v.Length-s.Key.Length).Trim())*s.Value);
|
||||
}
|
||||
}
|
||||
return TimeSpan.FromMilliseconds(int.Parse(v));
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string,long> SUFFIX = new Dictionary<string,long> {
|
||||
{ "ms", 1 },
|
||||
{ "sec", 1000L },
|
||||
{ "secs", 1000L },
|
||||
{ "min", 1000L*60L },
|
||||
{ "mins", 1000L*60L },
|
||||
{ "hr", 1000L*60L*60L },
|
||||
{ "hrs", 1000L*60L*60L },
|
||||
{ "hour", 1000L*60L*60L },
|
||||
{ "hours", 1000L*60L*60L },
|
||||
{ "day", 1000L*60L*60L*24L },
|
||||
{ "days", 1000L*60L*60L*24L }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Path to the executable.
|
||||
/// </summary>
|
||||
|
@ -356,29 +393,29 @@ namespace winsw
|
|||
|
||||
|
||||
/// <summary>
|
||||
/// The estimated time required for a pending stop operation, in milliseconds (default 15 secs).
|
||||
/// The estimated time required for a pending stop operation (default 15 secs).
|
||||
/// Before the specified amount of time has elapsed, the service should make its next call to the SetServiceStatus function
|
||||
/// with either an incremented checkPoint value or a change in currentState. (see http://msdn.microsoft.com/en-us/library/ms685996.aspx)
|
||||
/// </summary>
|
||||
public int WaitHint
|
||||
public TimeSpan WaitHint
|
||||
{
|
||||
get
|
||||
{
|
||||
return SingleIntElement(dom, "waithint", 15000);
|
||||
return SingleTimeSpanElement(dom, "waithint", TimeSpan.FromSeconds(15));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The time, in milliseconds (default 1 sec), before the service should make its next call to the SetServiceStatus function
|
||||
/// with an incremented checkPoint value.
|
||||
/// The time before the service should make its next call to the SetServiceStatus function
|
||||
/// with an incremented checkPoint value (default 1 sec).
|
||||
/// Do not wait longer than the wait hint. A good interval is one-tenth of the wait hint but not less than 1 second and not more than 10 seconds.
|
||||
/// </summary>
|
||||
public int SleepTime
|
||||
public TimeSpan SleepTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return SingleIntElement(dom, "sleeptime", 15000);
|
||||
return SingleTimeSpanElement(dom, "sleeptime", TimeSpan.FromSeconds(1));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,5 +466,44 @@ namespace winsw
|
|||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
public List<SC_ACTION> FailureActions
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SC_ACTION> r = new List<SC_ACTION>();
|
||||
foreach (XmlNode n in dom.SelectNodes("//onfailure"))
|
||||
{
|
||||
SC_ACTION_TYPE type;
|
||||
string action = n.Attributes["action"].Value;
|
||||
switch (action)
|
||||
{
|
||||
case "restart":
|
||||
type = SC_ACTION_TYPE.SC_ACTION_RESTART;
|
||||
break;
|
||||
case "none":
|
||||
type = SC_ACTION_TYPE.SC_ACTION_NONE;
|
||||
break;
|
||||
case "reboot":
|
||||
type = SC_ACTION_TYPE.SC_ACTION_REBOOT;
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Invalid failure action: " + action);
|
||||
}
|
||||
XmlAttribute delay = n.Attributes["delay"];
|
||||
r.Add(new SC_ACTION(type, delay!=null ? uint.Parse(delay.Value) : 0));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
public TimeSpan ResetFailureAfter
|
||||
{
|
||||
get
|
||||
{
|
||||
return SingleTimeSpanElement(dom, "resetfailure", TimeSpan.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue