Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / database / NoSQL

Running Redis as a Windows Service

4.96/5 (24 votes)
31 Jan 2014CPOL5 min read 87.2K   2.7K  
A utility to run Redis, or other executables, as a Windows Service.

Introduction

In this article I will show how to run the Window version of Redis Server, or other executables, as a Windows service.

Here at CodeProject, we use Redis as a distributed cache. We store massive amounts of information such as Articles, Forum Messages and retrieve these items from the cache rather than the database.

Redis alllows us to store and retrieve full documents, rather than querying SQL for the various pieces and composing and formatting the document on each request. This is possible on our site because most of the information is read a lot more than it is written, and some information, such as number of views, can be a little stale.

While in production we run Redis on a Linux server, in out development environment we are running the Microsoft port of Redis on a Window 7 desktop. The problem is that Redis is not designed to be run as a Windows Service. This means that someone had to logon and run the Redis executable. This was fine when Chris was the only one logging into the server, but last week, I had to connect to install a copy of our Search Server for development purposes. Needless to say, this logged Chris off, and killed the Redis Server. I restarted it under my session.

Back on my machine, I am fixing a subtle caching bug, and when I start testing, the code is acting like there is a connection failure to the Redis Server. As the code I am changing is related to the detection of problems with the connection to Redis, I spin my wheels for half an hour or so before I realize that Chris has remoted into the server, killing my session and the Redis Server.

Both Chris and I tried a number of recommended methods for running Redis as a Windows Service, without any success. Having written several Windows Services to support various CodeProject processes, I decided to write a utility which would allow us to install and run an exe as a Windows Service. This utility is called Exe2Srvc.

Using Exe2Srvc

Exe2Srv is a program that can be run as either a console application or installed as a Windows Service. This application reads the path to an executable, and the command line arguments from it .config file and then starts a the executable in a new Process.

The simplest way to use the executable is to

  1. copy the files in the binfiles download, or from bin/Release from the compiled source, into the directory containing the executable you wish to run as a Service.
  2. Edit the "Cmd" and "CmdArgs" values in the Exe2Srvc.exe.config to contain the full path to the executable, and the command line arguments required.
  3. Run the Install.bat file from a 'Run as Administrator' command shell.
  4. Use the Service Manager to:
     
    • set the start mode to Automatic
    • set the Recovery options. I usually set them to "Restart Service".
    • start the Service.

For my tests, I downloaded Redis from Nuget, and copied the files from the /packages/Redis-64.2.6.12.1/tools under the solution directory to C:/Redis. I then copied the files from Exe2Srvc\bin\Release to the same directory.

The Exe2Srvc.exe.config file contains:

XML
<?xml version="1.0" encoding="utf-8" />
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
    </startup>
    <appSettings>
        <!-- set Cmd to the executable file name. -->
        <!-- set CmdArg to any command arguments required. -->
        <add key="Cmd"      value="c:\Redis\redis-server.exe"/>
        <add key="CmdArgs"  value="c:\Redis\redis.conf --port 6379"/> 
    </appSettings>
</configuration>

If the path to the executable includes spaces, then the path needs to be in quotes. This can be accomplished by enclosing the double-quoted string in single-quotes as shown below.

XML
<?xml version="1.0" encoding="utf-8" />
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.1" />
    </startup>
    <appSettings>
        <!-- set Cmd to the executable file name. -->
        <!-- set CmdArg to any command arguments required. -->
        <add key="Cmd"      value='"c:Program Files\Redis\redis-server.exe"'/>
        <add key="CmdArgs"  value="c:\Redis\redis.conf --port 6379"/> 
    </appSettings>
</configuration>

The Install.bat file, which must be run as an Administrator, uses the SC command to install the Service.

sc create Redis binpath= "c:\Redis\Exe2Srvc.exe"

Then I use the Services Manager to configure the Service and start it.

Service Manager

Double Click on the Redis service to open the properties editor and select the Recovery tab. Set the options to restart the service on errors as shown.

 Service Manager

Select the General tab. 

  • Set the Startup Type to Automatic,
  • click the Start button
  • and click the OK button.
Service Manager

Redis is now installed and running as a Windows Service. Use the redis-cli.exe to test the connection.

How Exe2Srvc works 

Creating a console application that can be run as a Windows Service used a technique shown to me by Steve Smith and based on an article Run Windows Service as a console program by Einar Egilsson.

Basically you create a console application, and change the Program class to derive from ServiceBase. In the Main, the Environment.UserInteractive property is used to determine whether the program is being run from the command line, or run as a Service.

The required command and commandline parameters are read from the LoadConfiguration method.

C#
/// <summary>
/// Loads the configuration parameters from the application config file
/// </summary>
private void LoadConfiguration
{
    // Load the executable filename and command arguements from config file.
    _cmd     = ConfigurationManager.AppSettings["Cmd"];
    _cmdArgs = ConfigurationManager.AppSettings["CmdArgs"];
 
    if (string.IsNullOrWhiteSpace(_cmd))
        throw new Exception("The appsetting 'Cmd' was not defined in the config file.");
}

This is called from the OnStart method which is called from Main when started as a console application, or by the Service infrastructure when run as a Service. OnStart runs the executable in a new Process as shown below.

C#
/// <summary>
/// When implemented in a derived class, executes when a Start command is sent to the
/// service by the Service Control Manager (SCM) or when the operating system starts
/// (for a service that starts automatically).
/// Specifies actions to take when the service starts.
/// </summary>
/// <param name="args";>
/// Data passed by the start command.
/// </param>
protected override void OnStart(string[] args)
{
    if (Environment.UserInteractive)
    {
        string message = String.Format"Starting {0} at {1}.", _serviceName, DateTime.Now);
         Console.WriteLine(message);
    }
 
    // loading the configuration file info here allows the service to be stopped,
    // the configuration modified, and the service restarted.
    LoadConfiguration();
 
     // Start the executable.
      ProcessStartInfo procInfo = new ProcessStartInfo(_cmd);
      procInfo.UseShellExecute = false;
 
       if (!string.IsNullOrWhiteSpace(_cmdArgs))
           procInfo.Arguments = _cmdArgs;
 
       _process = Process.Start(procInfo);
 }

When the Service is stopped, the OnStop method is called. This kills the Process, waits for it to terminate, and disposes of the Process. Make sure you wait for the Process to terminate, failure to do so will result in improperly stopped Services that are difficult to remove and fix.

C#
/// <summary>
/// When implemented in a derived class, executes when a Stop command is sent to the service
/// by the Service Control Manager (SCM). Specifies actions to take when a service stops running.
/// </summary>
/// <remarks>Stops the background tasks.</remarks>
protected override void OnStop()
{
    if (Environment.UserInteractive)
    {
        string message = String.Format("Stopping {0} at {1}.", _serviceName, DateTime.Now);
         Console.WriteLine(message);
     }
           
     // Kill the process
     if (_process != null)
     {
         _process.Kill();
         _process.WaitForExit();
         _process.Dispose();
         _process = null;
      }
}

Points of Interest

I've attempted to make this as simple and flexible as possible, but it only meets my original requirement of being able to run the Windows version of Redis as a Windows Server. If you have additional requirement, feel free to modify the code to match your needs.

History

This is the original release.

31 Jan, 2014 - added example of specifying an executable path that contains spaces. 

 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)