ProcessManager: Simple Process Management


ProcessManager: Simple Process Management

1   Introduction

1.1   What is ProcessManager?

ProcessManager is a simple Python-based solution for managing--starting, stopping, and restarting--any process or collection of processes that provide services for an indefinite period of time (e.g., a server or daemon) on a Unix-based OS.

1.2   Why use ProcessManager?

Unix-based operating systems provide a variety of tools for managing server and daemon processes. In general, these tools involve a daunting variety of shell scripts, command-line utilities, configuration files, and directory heirarchies. Furthermore, the specifics of the tools vary from platform to platform. While managing a service that has already been pre-configured "out of the box" may be relatively simple, configuring a new service to be stopped, started, and restarted inevitably requires a thorough understanding of all the specific tools involved.

ProcessManager attempts to mitigate these problems by using one tool to get the job done. Python's eminent readability, ease of use, and robust support for systems programming tasks make it an ideal candidate for this role.

That said, ProcessManager is not intended to be used as a replacement for an operating system's existing init system. This will be clarified in the example below.

1.3   A ProcessManager Example

The best way to illustrate ProcessManager is through an example. Suppose we have two simple service applications called foo and bar, each of which have their own specific configuration parameters: they need to be executed under service accounts for security reasons, they have their own configuration files, and so forth.

A simple Python script serves the dual role of configuration file and command-line process management utility:

#! /usr/bin/env python

import ProcessManager
from ProcessManager import Process

# dataDir is where all intermediate data files are stored.
ProcessManager.init( dataDir = "/var/ProcessManager" )

ProcessManager.add( Process(
  name = "foo",
  desc = "my foo server",
  program = "/usr/local/bin/foo",
  args = ["--config-file=/etc/foo.conf"],
  workingDir = "/var/foo",
  uid = "nobody",
  gid = "nobody"
  ))

ProcessManager.add( Process(
  name = "bar",
  desc = "my bar server",
  program = "/usr/local/bin/bar",
  args = ["--port=8082", "--no-daemon"],
  workingDir = "/var/bar",
  uid = "www",
  gid = "www"
  ))

ProcessManager.main()

Assume this Python script is called my-servers.py. Running this script with no parameters will result in the following help text:

usage:
  my-servers.py <target> <command> [options]

targets:
  foo                  my foo server
  bar                  my bar server
  all                  (this target applies the command to all
                       of the above targets)

commands:
  status               show status of the target
  start                start the target
  stop                 stop the target
  restart              restart (stop, then start) the target

options:
  -h, --help           show this help message and exit
  -e, --enable-stderr  enable output of starting target's stderr to console
  -o, --enable-stdout  enable output of starting target's stdout to console
  -v, --version        print version information and exit

Invoking my-servers.py all status results in the following:

foo                            stopped
bar                            stopped

Invoking my-servers.py foo start results in the following:

Launching foo...               OK

Note that there would be a noticeable delay before the text OK appeared, as ProcessManager would be launching the process. If the process failed to launch for some reason, the word FAILED would have appeared instead.

Now, invoking my-servers.py all status again results in the following:

foo                            running
bar                            stopped

If at any point foo stops running via a mechanism other than my-servers.py foo stop, the following will be displayed:

foo                            crashed
bar                            stopped

1.4   Support for rc-scripts

The above example is useful for ad-hoc and development purposes, but production services ultimately need to become part of the underlying OS's init system, which ProcessManager is not intended to replace. Rather, ProcessManager can be used to augment it.

At present, such support is limited to operating systems that use rc-scripts, such as System V, NetBSD, and Linux. The rest of this section assumes that this is the case.

The above example, my-servers.py, can be seamlessly converted into a multi-purpose rc-script by changing its last line to the following:

ProcessManager.rcScriptMain()

Assuming we want to integrate the services foo and bar with the underlying init system, we simply create symbolic links /etc/init.d/foo and /etc/init.d/bar, both of which point to my-servers.py. Executing /etc/init.d/foo now results in the following:

usage:
  foo <command> [options]

This script controls my foo server.

commands:
  status               show status of the target
  start                start the target
  stop                 stop the target
  restart              restart (stop, then start) the target

options:
  -h, --help           show this help message and exit
  -e, --enable-stderr  enable output of starting target's stderr to console
  -o, --enable-stdout  enable output of starting target's stdout to console
  -v, --version        print version information and exit

Executing /etc/init.d/bar results in a similar display tailored to the bar target. Both scripts can now be integrated with the underlying operating system's init system.

3   Prerequisites

ProcessManager has been tested on Python 2.4, though it may work with earlier versions. There are no other requirements for running ProcessManager, save that the operating system it is running on be Unix-based.

4   Installation

Installing ProcessManager is done as follows:

tar -zxvf ProcessManager-0.0.4.tar.gz
cd ProcessManager-0.0.4
python setup.py install

5   Usage

Please see "A ProcessManager Example", above, for basic instructions on using this tool.

For the time being, the best source of further documentation can be found via pydoc. Just execute the following at the command line:

pydoc ProcessManager

6   Limitations

ProcessManager has fairly limited functionality. Among its limitations:

  • It can't run processes that attempt to fork or daemonize on their own.
  • ProcessManager has no way of really knowing if a spawned process successfully launched; it simply checks to see if the process still exists 5 seconds after it was launched, and if so, it deems the process launch to be successful. However, it should also be noted that a number of existing rc-scripts operate under similar conditions.
  • It has no conception of dependency order ( e.g., specifying that process A depends on process B).
  • It is incapable of launching services in parallel.

In the future, ProcessManager may be extended to address these limitations.

7   Contact Information

Please feel free to send questions, comments, bug reports, and other correspondence regarding ProcessManager to atul@humanized.com.

8   License

This software is distributed under the following license:

Copyright (c) 2006, Humanized, Inc.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above
    copyright notice, this list of conditions and the following
    disclaimer in the documentation and/or other materials provided
    with the distribution.

  * Neither the name of Humanized, Inc. nor the names of its
    contributors may be used to endorse or promote products derived
    from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

Deprecated: Assigning the return value of new by reference is deprecated in /nfs/c01/h11/mnt/34814/domains/humanized.com/html/weblog/wp-includes/cache.php on line 36

Deprecated: Assigning the return value of new by reference is deprecated in /nfs/c01/h11/mnt/34814/domains/humanized.com/html/weblog/wp-includes/query.php on line 21

Deprecated: Assigning the return value of new by reference is deprecated in /nfs/c01/h11/mnt/34814/domains/humanized.com/html/weblog/wp-includes/theme.php on line 540