Published Wednesday, February 20, 2008 9:54 AM by mtaulty

Simple Process Launching Service

Just sharing a piece of code. I'm sure this isn't quite perfect but someone wanted a Windows Service which would run up some processes with the option to restart them if they exited.

I think the Windows Task Scheduler will do some of this but I don't think it does all of it.

The service is driven by its configuration file which is simply;

<configuration>

  <configSections>
    <section name="processLauncherConfig"
             type="ProcLauncher.ProcessLauncherConfig, ProcLauncher"/>
  </configSections>
  
  <processLauncherConfig xmlns="urn:proclauncher-com">

    <processes>
      <process executable="consoleapplication11.exe"
               restart="true"
               killOnStop="true">
        <arguments>
          <argument value="one"/>
          <argument value="two"/>
        </arguments>
      </process>
    </processes>
  </processLauncherConfig>

</configuration>

With that in place, I've just got a bit of service code;

using System;
using System.Configuration;
using System.Diagnostics;
using System.ServiceProcess;
using System.Text;
using System.Collections.Generic;
using System.Threading;

namespace ProcLauncher
{
  public partial class ProcService : ServiceBase
  {
    public ProcService()
    {
      InitializeComponent();
      dictionaryLock = new object();
    }
    protected override void OnStart(string[] args)
    {
      EventLog.WriteEntry(Messages.MsgServiceStart, EventLogEntryType.Information);

      if (!LoadConfig())
      {
        EventLog.WriteEntry(Messages.MsgConfigNotFound, EventLogEntryType.Error);
        this.Stop();
      }
      // Move to the threadpool so we can return quickly.
      ThreadPool.QueueUserWorkItem(StartProcesses);
    }
    void StartProcesses(object state)
    {
      lock (dictionaryLock)
      {
        processesStarted = new Dictionary<int, process>();
      }

      foreach (process proc in loadedConfig.processes)
      {
        StartProcess(proc);
      }
    }
    private void StartProcess(process proc)
    {
      ProcessStartInfo psi = new ProcessStartInfo()
      {
        FileName = proc.executable,
        Arguments = BuildProcessArguments(proc)
      };

      try
      {
        Process p = Process.Start(psi);

        lock (dictionaryLock)
        {
          processesStarted.Add(p.Id, proc);
        }
        if (proc.restart)
        {
          p.EnableRaisingEvents = true;
          p.Exited += OnProcessExited;
        }
        else
        {
          p.Dispose();
        }
      }
      catch
      {
      }
    }
    private static string BuildProcessArguments(process proc)
    {
      string args = null;

      if ((proc.arguments != null) && (proc.arguments.Count > 0))
      {
        StringBuilder sb = new StringBuilder(proc.arguments[0].value);

        for (int i = 1; i < proc.arguments.Count; i++)
        {
          sb.AppendFormat(" {0}", proc.arguments[i].value);
        }
        args = sb.ToString();
      }
      return (args);
    }
    void OnProcessExited(object sender, EventArgs e)
    {
      Process p = (Process)sender;
      process proc = null;

      lock (dictionaryLock)
      {
        proc = processesStarted[p.Id];

        processesStarted.Remove(p.Id);
      }
      p.Dispose();

      StartProcess(proc);
    }
    bool LoadConfig()
    {
      loadedConfig = (ProcessLauncherConfig)ConfigurationManager.GetSection(
        configSection);

      return (loadedConfig != null);
    }
    protected override void OnStop()
    {
      Dictionary<int, process> copy = null;

      lock (dictionaryLock)
      {
        copy = processesStarted;
        processesStarted = null;
      }

      foreach (KeyValuePair<int, process> entry in copy)
      {
        if (entry.Value.killOnStop)
        {
          using (Process p = Process.GetProcessById(entry.Key))
          {
            p.Kill();
          }
        }
      }
      EventLog.WriteEntry(Messages.MsgServiceStop, EventLogEntryType.Information);
    }
    private ProcessLauncherConfig loadedConfig;
    private Dictionary<int, process> processesStarted;
    private object dictionaryLock;

    private static string configSection = "processLauncherConfig";
  }
}

I didn't spend a huge amount of time on it so there might be a few bugs in there but it's a starting point.

I've put the project file up here for download. Note that I use the Configuration Section Designer for the config file stuff here so if you haven't got that installed you'd want to just make sure that the MyConfigCode.cs file was in the project as that's all you actually need to read the config file.


Filed Under:

# Link Listing - February 20, 2008 @ Thursday, February 21, 2008 5:19 AM

Announcements  CI Factory Version 1.0 [Via: jflowers ] ASP.NET  Digg.com like Login Control [Via: mikedopp...

Christopher Steen

# Link Listing - February 20, 2008 @ Thursday, February 21, 2008 5:19 AM

Link Listing - February 20, 2008

Christopher Steen

# Interesting Finds: February 21, 2008 @ Thursday, February 21, 2008 7:02 AM

Jason Haley

# process exit code 8 @ Wednesday, April 16, 2008 2:33 PM

PingBack from http://sheldon.thefreetvnews.com/processexitcode8.html

process exit code 8

# ims processing option @ Tuesday, May 13, 2008 8:57 PM

PingBack from http://nestor.freemedianewschannel.info/imsprocessingoption.html

ims processing option

# exit code 1 @ Wednesday, June 25, 2008 1:24 PM

PingBack from http://ross.usednewsdigest.info/exitcode1.html

exit code 1