Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
EventStore as a windows service w/ TopShelf
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="eventStore" type="EventStoreService.EventStoreServiceConfiguration, EventStoreService, Version=1.0.0.0, Culture=neutral" />
</configSections>
<eventStore>
<instance name="Production" tcpPort="4532" httpPort="5500" dbPath="F:\production" />
<instance name="Staging" tcpPort="5532" httpPort="6500" dbPath="F:\staging" />
</eventStore>
</configuration>
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net;
namespace EventStoreService
{
public class EventStoreService
{
private readonly List<Process> _processes;
private readonly IPAddress _address;
private readonly ServiceInstanceCollection _instances;
public EventStoreService(IPAddress address, ServiceInstanceCollection instances)
{
_address = address;
_instances = instances;
_processes = new List<Process>();
}
public void Start()
{
string file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "eventstore/EventStore.SingleNode.exe");
foreach (ServiceInstance instance in _instances)
{
var info = instance.GetProcessStartInfo(file, _address);
var process = Process.Start(info);
process.Exited += (sender, args) => Stop();
_processes.Add(process);
}
}
public void Stop()
{
_processes.ForEach(p =>
{
p.Refresh();
if (p.HasExited) return;
p.Kill();
p.WaitForExit();
p.Dispose();
});
}
}
}
using System;
using System.Configuration;
using System.Diagnostics;
using System.Net;
using System.Text;
namespace EventStoreService
{
public class EventStoreServiceConfiguration : ConfigurationSection
{
[ConfigurationProperty("", IsDefaultCollection = true, IsKey = false, IsRequired = true)]
public ServiceInstanceCollection Instances
{
get { return (ServiceInstanceCollection) this[""]; }
set { this[""] = value; }
}
}
public class ServiceInstanceCollection : ConfigurationElementCollection
{
protected override string ElementName
{
get { return "instance"; }
}
public override ConfigurationElementCollectionType CollectionType
{
get { return ConfigurationElementCollectionType.BasicMap; }
}
public ServiceInstance this[int index]
{
get { return BaseGet(index) as ServiceInstance; }
}
protected override ConfigurationElement CreateNewElement()
{
return new ServiceInstance();
}
protected override object GetElementKey(ConfigurationElement element)
{
return ((ServiceInstance) element).Name;
}
protected override bool IsElementName(string elementName)
{
return !String.IsNullOrEmpty(elementName) && elementName == ElementName;
}
}
public class ServiceInstance : ConfigurationElement
{
[ConfigurationProperty("name", IsRequired = true)]
public string Name
{
get { return (string) this["name"]; }
set { this["name"] = value; }
}
[ConfigurationProperty("tcpPort", IsRequired = true)]
public int TcpPort
{
get { return (int) this["tcpPort"]; }
set { this["tcpPort"] = value; }
}
[ConfigurationProperty("httpPort", IsRequired = true)]
public int HttpPort
{
get { return (int) this["httpPort"]; }
set { this["httpPort"] = value; }
}
[ConfigurationProperty("dbPath", IsRequired = true)]
public string DbPath
{
get { return (string) this["dbPath"]; }
set { this["dbPath"] = value; }
}
public ProcessStartInfo GetProcessStartInfo(string file, IPAddress address)
{
var arguments = GetProcessArguments(address);
return new ProcessStartInfo(file, arguments)
{
UseShellExecute = false
};
}
private string GetProcessArguments(IPAddress address)
{
if (address == null) throw new ArgumentNullException("address");
var sb = new StringBuilder();
sb.AppendFormat("--ip {0} ", address);
sb.AppendFormat("--tcp-port {0} ", TcpPort);
sb.AppendFormat("--http-port {0} ", HttpPort);
sb.AppendFormat("--db {0}", DbPath);
return sb.ToString();
}
}
}
@ECHO off
set exe="%~dp0EventStoreService.exe"
%exe% install
pause
using System;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using Topshelf;
namespace EventStoreService
{
public class Program
{
public static void Main()
{
var configuration = (EventStoreServiceConfiguration)ConfigurationManager.GetSection("eventStore");
var address = GetIPAddress();
HostFactory.Run(x =>
{
x.RunAsLocalSystem();
x.StartAutomatically();
x.EnableShutdown();
x.EnableServiceRecovery(c => c.RestartService(1));
x.Service<EventStoreService>(s =>
{
s.ConstructUsing(name => new EventStoreService(address, configuration.Instances));
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc => tc.Stop());
});
x.SetDescription("EventDay EventStore Service");
x.SetDisplayName("EventDay EventStore");
x.SetServiceName("EventDayEventStore");
});
Console.ReadLine();
}
private static IPAddress GetIPAddress()
{
string hostName = Dns.GetHostName();
return Dns.GetHostAddresses(hostName).First(address =>
{
if (address.AddressFamily != AddressFamily.InterNetwork)
return false;
return !Equals(address, IPAddress.Loopback);
});
}
}
}

mastoj commented Aug 14, 2014

Nice and clean solution. I hope you didn't mind I copied basically everything and put it here: https://github.com/mastoj/EventStoreWinServiceWrapper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment