mirror of https://github.com/winsw/winsw
commit
b93e08ee8b
|
@ -1,3 +1,6 @@
|
|||
bin
|
||||
obj
|
||||
*.suo
|
||||
/UpgradeLog.htm
|
||||
/winsw.csproj.DotSettings.user
|
||||
/winsw.csproj.user
|
||||
|
|
|
@ -163,6 +163,22 @@ namespace winsw
|
|||
private string pattern;
|
||||
private int period;
|
||||
|
||||
public string Pattern
|
||||
{
|
||||
get
|
||||
{
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
|
||||
public int Period
|
||||
{
|
||||
get
|
||||
{
|
||||
return period;
|
||||
}
|
||||
}
|
||||
|
||||
public TimeBasedRollingLogAppender(string logDirectory, string baseName, string pattern, int period)
|
||||
: base(logDirectory, baseName)
|
||||
{
|
||||
|
@ -246,6 +262,22 @@ namespace winsw
|
|||
private int sizeThreshold;
|
||||
private int filesToKeep;
|
||||
|
||||
public int SizeTheshold
|
||||
{
|
||||
get
|
||||
{
|
||||
return sizeThreshold;
|
||||
}
|
||||
}
|
||||
|
||||
public int FilesToKeep
|
||||
{
|
||||
get
|
||||
{
|
||||
return filesToKeep;
|
||||
}
|
||||
}
|
||||
|
||||
public SizeBasedRollingLogAppender(string logDirectory, string baseName, int sizeThreshold, int filesToKeep)
|
||||
: base(logDirectory, baseName)
|
||||
{
|
||||
|
|
46
Main.cs
46
Main.cs
|
@ -318,16 +318,56 @@ namespace winsw
|
|||
}
|
||||
|
||||
private void StopProcessAndChildren(int pid)
|
||||
{
|
||||
var childPids = GetChildPids(pid);
|
||||
|
||||
if (descriptor.StopParentProcessFirst)
|
||||
{
|
||||
StopProcess(pid);
|
||||
foreach (var childPid in childPids)
|
||||
{
|
||||
StopProcessAndChildren(childPid);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var childPid in childPids)
|
||||
{
|
||||
StopProcessAndChildren(childPid);
|
||||
}
|
||||
StopProcess(pid);
|
||||
}
|
||||
}
|
||||
|
||||
private List<int> GetChildPids(int pid)
|
||||
{
|
||||
var searcher = new ManagementObjectSearcher("Select * From Win32_Process Where ParentProcessID=" + pid);
|
||||
var childPids = new List<int>();
|
||||
foreach (var mo in searcher.Get())
|
||||
{
|
||||
StopProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
|
||||
var childProcessId = mo["ProcessID"];
|
||||
WriteEvent("Found child process: " + childProcessId + " Name: " + mo["Name"]);
|
||||
childPids.Add(Convert.ToInt32(childProcessId));
|
||||
}
|
||||
return childPids;
|
||||
}
|
||||
|
||||
var proc = Process.GetProcessById(pid);
|
||||
private void StopProcess(int pid)
|
||||
{
|
||||
WriteEvent("Stopping process " + pid);
|
||||
Process proc;
|
||||
try
|
||||
{
|
||||
proc = Process.GetProcessById(pid);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
WriteEvent("Process " + pid + " is already stopped");
|
||||
return;
|
||||
}
|
||||
|
||||
WriteEvent("Send SIGINT " + pid);
|
||||
bool successful = SigIntHelper.SendSIGINTToProcess(proc,descriptor.StopTimeout);
|
||||
bool successful = SigIntHelper.SendSIGINTToProcess(proc, descriptor.StopTimeout);
|
||||
if (successful)
|
||||
{
|
||||
WriteEvent("SIGINT to" + pid + " successful");
|
||||
|
|
|
@ -292,3 +292,9 @@ Possible values are `idle`, `belownormal`, `normal`, `abovenormal`, `high`, `rea
|
|||
<priority>idle</priority>
|
||||
|
||||
Specifying a priority higher than normal has unintended consequences. See <a href="http://msdn.microsoft.com/en-us/library/system.diagnostics.processpriorityclass(v=vs.110).aspx">MSDN discussion</a> for details. This feature is intended primarily to launch a process in a lower priority so as not to interfere with the computer's interactive usage.
|
||||
|
||||
###stopparentprocessfirst
|
||||
Optionally specify the order of service shutdown. If true, the parent process is shutdown first. This is useful when the main process is a console, which can respond to Ctrol+C command and will gracefully shutdown child processes
|
||||
```
|
||||
<stopparentprocessfirst>true</stopparentprocessfirst>
|
||||
```
|
||||
|
|
|
@ -28,13 +28,13 @@ namespace winsw
|
|||
///
|
||||
/// This string is "c:\abc\def\ghi" when the configuration XML is "c:\abc\def\ghi.xml"
|
||||
/// </summary>
|
||||
public readonly string BasePath;
|
||||
public string BasePath { get; set; }
|
||||
/// <summary>
|
||||
/// The file name portion of the configuration file.
|
||||
///
|
||||
/// In the above example, this would be "ghi".
|
||||
/// </summary>
|
||||
public readonly string BaseName;
|
||||
public string BaseName { get; set; }
|
||||
|
||||
public virtual string ExecutablePath
|
||||
{
|
||||
|
@ -580,7 +580,21 @@ namespace winsw
|
|||
{
|
||||
get
|
||||
{
|
||||
return SingleTimeSpanElement(dom, "stoptimeout", TimeSpan.FromSeconds(15));
|
||||
return SingleTimeSpanElement(dom.FirstChild, "stoptimeout", TimeSpan.FromSeconds(15));
|
||||
}
|
||||
}
|
||||
|
||||
public bool StopParentProcessFirst
|
||||
{
|
||||
get
|
||||
{
|
||||
var value = SingleElement("stopparentprocessfirst", true);
|
||||
bool result;
|
||||
if (bool.TryParse(value, out result))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -51,12 +51,10 @@ namespace winsw
|
|||
|
||||
process.WaitForExit((int)shutdownTimeout.TotalMilliseconds);
|
||||
|
||||
return process.HasExited;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
return process.HasExited;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,63 +1,65 @@
|
|||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using winsw;
|
||||
using System.Diagnostics;
|
||||
using System.Xml;
|
||||
|
||||
namespace winswTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ServiceDescriptorTests
|
||||
{
|
||||
|
||||
private ServiceDescriptor extendedServiceDescriptor;
|
||||
|
||||
private const string ExpectedWorkingDirectory = @"Z:\Path\SubPath";
|
||||
private const string Username = "User";
|
||||
private const string Password = "Password";
|
||||
private const string Domain = "Domain";
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
const string SeedXml = "<service>"
|
||||
+ "<id>service.exe</id>"
|
||||
+ "<name>Service</name>"
|
||||
+ "<description>The service.</description>"
|
||||
+ "<executable>node.exe</executable>"
|
||||
+ "<arguments>My Arguments</arguments>"
|
||||
+ "<logmode>rotate</logmode>"
|
||||
+ "<serviceaccount>"
|
||||
+ "<domain>" + Domain + "</domain>"
|
||||
+ "<user>" + Username + "</user>"
|
||||
+ "<password>" + Password + "</password>"
|
||||
+ "</serviceaccount>"
|
||||
+ "<workingdirectory>"
|
||||
+ ExpectedWorkingDirectory
|
||||
+ "</workingdirectory>"
|
||||
+ @"<logpath>C:\logs</logpath>"
|
||||
using System.Xml;
|
||||
|
||||
namespace winswTests
|
||||
{
|
||||
using System;
|
||||
|
||||
[TestFixture]
|
||||
public class ServiceDescriptorTests
|
||||
{
|
||||
|
||||
private ServiceDescriptor extendedServiceDescriptor;
|
||||
|
||||
private const string ExpectedWorkingDirectory = @"Z:\Path\SubPath";
|
||||
private const string Username = "User";
|
||||
private const string Password = "Password";
|
||||
private const string Domain = "Domain";
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
const string SeedXml = "<service>"
|
||||
+ "<id>service.exe</id>"
|
||||
+ "<name>Service</name>"
|
||||
+ "<description>The service.</description>"
|
||||
+ "<executable>node.exe</executable>"
|
||||
+ "<arguments>My Arguments</arguments>"
|
||||
+ "<logmode>rotate</logmode>"
|
||||
+ "<serviceaccount>"
|
||||
+ "<domain>" + Domain + "</domain>"
|
||||
+ "<user>" + Username + "</user>"
|
||||
+ "<password>" + Password + "</password>"
|
||||
+ "</serviceaccount>"
|
||||
+ "<workingdirectory>"
|
||||
+ ExpectedWorkingDirectory
|
||||
+ "</workingdirectory>"
|
||||
+ @"<logpath>C:\logs</logpath>"
|
||||
+ "</service>";
|
||||
extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyWorkingDirectory()
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("_extendedServiceDescriptor.WorkingDirectory :: " + extendedServiceDescriptor.WorkingDirectory);
|
||||
Assert.That(extendedServiceDescriptor.WorkingDirectory, Is.EqualTo(ExpectedWorkingDirectory));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyUsername()
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("_extendedServiceDescriptor.WorkingDirectory :: " + extendedServiceDescriptor.WorkingDirectory);
|
||||
Assert.That(extendedServiceDescriptor.ServiceAccountUser, Is.EqualTo(Domain + "\\" + Username));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyPassword()
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("_extendedServiceDescriptor.WorkingDirectory :: " + extendedServiceDescriptor.WorkingDirectory);
|
||||
Assert.That(extendedServiceDescriptor.ServiceAccountPassword, Is.EqualTo(Password));
|
||||
extendedServiceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyWorkingDirectory()
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("_extendedServiceDescriptor.WorkingDirectory :: " + extendedServiceDescriptor.WorkingDirectory);
|
||||
Assert.That(extendedServiceDescriptor.WorkingDirectory, Is.EqualTo(ExpectedWorkingDirectory));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyUsername()
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("_extendedServiceDescriptor.WorkingDirectory :: " + extendedServiceDescriptor.WorkingDirectory);
|
||||
Assert.That(extendedServiceDescriptor.ServiceAccountUser, Is.EqualTo(Domain + "\\" + Username));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void VerifyPassword()
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine("_extendedServiceDescriptor.WorkingDirectory :: " + extendedServiceDescriptor.WorkingDirectory);
|
||||
Assert.That(extendedServiceDescriptor.ServiceAccountPassword, Is.EqualTo(Password));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -71,6 +73,85 @@ namespace winswTests
|
|||
|
||||
sd = ServiceDescriptor.FromXML("<service><id>test</id></service>");
|
||||
Assert.That(sd.Priority, Is.EqualTo(ProcessPriorityClass.Normal));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void StopParentProcessFirstIsFalseByDefault()
|
||||
{
|
||||
Assert.False(extendedServiceDescriptor.StopParentProcessFirst);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanParseStopParentProcessFirst()
|
||||
{
|
||||
const string SeedXml = "<service>"
|
||||
+ "<stopparentprocessfirst>true</stopparentprocessfirst>"
|
||||
+ "</service>";
|
||||
var serviceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||
|
||||
Assert.True(serviceDescriptor.StopParentProcessFirst);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanParseStopTimeout()
|
||||
{
|
||||
const string SeedXml = "<service>"
|
||||
+ "<stoptimeout>60sec</stoptimeout>"
|
||||
+ "</service>";
|
||||
var serviceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||
|
||||
Assert.That(serviceDescriptor.StopTimeout, Is.EqualTo(TimeSpan.FromSeconds(60)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void CanParseStopTimeoutFromMinutes()
|
||||
{
|
||||
const string SeedXml = "<service>"
|
||||
+ "<stoptimeout>10min</stoptimeout>"
|
||||
+ "</service>";
|
||||
var serviceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||
|
||||
Assert.That(serviceDescriptor.StopTimeout, Is.EqualTo(TimeSpan.FromMinutes(10)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LogModeRollBySize()
|
||||
{
|
||||
const string SeedXml = "<service>"
|
||||
+ "<logpath>c:\\</logpath>"
|
||||
+ "<log mode=\"roll-by-size\">"
|
||||
+ "<sizeThreshold>112</sizeThreshold>"
|
||||
+ "<keepFiles>113</keepFiles>"
|
||||
+ "</log>"
|
||||
+ "</service>";
|
||||
|
||||
var serviceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||
serviceDescriptor.BaseName = "service";
|
||||
|
||||
var logHandler = serviceDescriptor.LogHandler as SizeBasedRollingLogAppender;
|
||||
Assert.NotNull(logHandler);
|
||||
Assert.That(logHandler.SizeTheshold, Is.EqualTo(112 * 1024));
|
||||
Assert.That(logHandler.FilesToKeep, Is.EqualTo(113));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LogModeRollByTime()
|
||||
{
|
||||
const string SeedXml = "<service>"
|
||||
+ "<logpath>c:\\</logpath>"
|
||||
+ "<log mode=\"roll-by-time\">"
|
||||
+ "<period>7</period>"
|
||||
+ "<pattern>log pattern</pattern>"
|
||||
+ "</log>"
|
||||
+ "</service>";
|
||||
|
||||
var serviceDescriptor = ServiceDescriptor.FromXML(SeedXml);
|
||||
serviceDescriptor.BaseName = "service";
|
||||
|
||||
var logHandler = serviceDescriptor.LogHandler as TimeBasedRollingLogAppender;
|
||||
Assert.NotNull(logHandler);
|
||||
Assert.That(logHandler.Period, Is.EqualTo(7));
|
||||
Assert.That(logHandler.Pattern, Is.EqualTo("log pattern"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue