ievv devrun — All your development servers in one command

The ievv devrun command makes it easy to run (start/stop) all your development servers with a single command. It uses multithreading, background processes to run all your servers in a single blocking process that stops all the processes when CTRL-C is hit.

Getting started

First of all, make sure you have the following in your INSTALLED_APPS setting:

'ievv_opensource.ievvtasks_common',
'ievv_opensource.ievvtasks_development',

Next, you need to configure what to run when you run ievv devrun. You do this with the IEVVTASKS_DEVRUN_RUNNABLES-setting.

For the first example, we will use ievv devrun to just run the Django development server, just like python manage.py runserver. Add the following you your Django settings:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.django_runserver.RunnableThread()
    )
}

With this configured, you can run:

$ ievv devrun

to start the Django development. Hit CTRL-C to stop the server.

Using Django dbdev

For this example, we will setup Django runserver and Django dbdev database server:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.dbdev_runserver.RunnableThread(),
        ievvdevrun.runnables.django_runserver.RunnableThread()
    )
}

With this configured, you can run:

$ ievv devrun

to start both the Django development server and your django_dbdev database. Hit CTRL-C to stop both the servers.

Multiple run configurations

You may already have guessed that you can add multiple configurations since we only add a default-key to IEVVTASKS_DEVRUN_RUNNABLES. To add multiple configurations, just add another key to the dict. For this example, we will add an design key that also runs ievv buildstatic --watch:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        # ... same as above ...
    ),
    'design': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.dbdev_runserver.RunnableThread(),
        ievvdevrun.runnables.django_runserver.RunnableThread(),
        ievvdevrun.runnables.ievv_buildstatic.RunnableThread(),
    )
}

To run the design-set of runnables, use:

$ ievv devrun -n design

Adding ievv devrun as PyCharm run config

If you use PyCharm, you can do the following to add ievv devrun as a run target:

  • Select Run -> Edit configurations ....
  • Select + -> Python.
    • Give it a name (E.g.: ievv devrun default).
    • Check Single instance.
    • Check Share if you want to share it with your co-workers.
    • Select your manage.py as the script.
    • Set ievvtasks_devrun -n default as Script parameters.

If you want to create a target for the design config shown above, you just create another PyCharm run target with ievvtasks_devrun -n design.

Custom runnables

We bundle a fairly limited set of runnables, but adding one is really easy. Check out the docs for:

Bundled runnables

Overview

base.AbstractRunnableThread([name]) Abstract class for a thread that runs something for the ievvdevrun framework.
base.ShellCommandRunnableThread([name, …]) Makes it very easy to implement AbstractRunnableThread for system/shell commands.
django_runserver.RunnableThread([host, port]) Django runserver runnable thread.
dbdev_runserver.RunnableThread([name, …]) Django-DBdev run database runnable thread.
elasticsearch.RunnableThread(configpath[, …]) Elasticsearch runnable thread.
redis_server.RunnableThread([port, config_path]) redis-server runnable thread.

Details

class ievv_opensource.utils.ievvdevrun.runnables.base.AbstractRunnableThread(name=None)[source]

Bases: threading.Thread, ievv_opensource.utils.logmixin.LogMixin

Abstract class for a thread that runs something for the ievvdevrun framework.

You have to override the run()-method (refer to the docs for threading.Thread.run), and the stop() method.

Parameters:name – An optional name for the logger. See get_logger_name().
log_startup()[source]

Called automatically on startup with "Starting <name>" message.

log_successful_stop(message='')[source]

Call this in stop() to show a message after successfully stopping the runnable.

Parameters:message – Optional extra message to show.
start()[source]

Start the thread’s activity.

It must be called at most once per thread object. It arranges for the object’s run() method to be invoked in a separate thread of control.

This method will raise a RuntimeError if called more than once on the same thread object.

get_logger_name()[source]

Get the logger name. Defaults to the name-parameter and falls back on the module name of the class.

stop()[source]

Must stop the code running in the thread (the code in the run method).

class ievv_opensource.utils.ievvdevrun.runnables.base.ShellCommandRunnableThread(name=None, command_config=None, autorestart_on_crash=None)[source]

Bases: ievv_opensource.utils.ievvdevrun.runnables.base.AbstractRunnableThread, ievv_opensource.utils.shellcommandmixin.ShellCommandMixin

Makes it very easy to implement AbstractRunnableThread for system/shell commands.

Examples

Implement Django runserver:

class DjangoRunserverRunnableThread(base.ShellCommandRunnableThread):
    def get_logger_name(self):
        return 'Django development server'

    def get_command_config(self):
        return {
            # We use sys.executable instead of "python" to ensure we run the same python executable
            # as we are using to start the process.
            'executable': sys.executable,
            'args': ['manage.py', 'runserver']
        }

As you can see, we just need specify the name and the command we want to run. You can even do this without creating a class by sending the command config as a parameter to this class in your django settings:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.base.ShellCommandRunnableThread(
            name='Django development server',
            command_config={
                'executable': sys.executable,
                'args': ['manage.py', 'runserver']
            }
        ),
    )
}

Making the command automatically restart when it crashes:

class DjangoRunserverRunnableThread(base.ShellCommandRunnableThread):
    default_autorestart_on_crash = True
    # ... same code as the example above ...

You can also autorestart by sending autorestart_on_crash=True as a parameter for the class.

Parameters:
  • name – Optional name for the runnable. Defaults to the module name.
  • command_config – Same format as the return value from get_command_config().
  • autorestart_on_crash – Set this to True if you want to automatically restart the process if it crashes.
default_autorestart_on_crash = False

The default value for the autorestart_on_crash parameter. You can override this in subclasses if it is more natural to automatically restart on crash by default.

get_command_config()[source]

Get the config for the shell/system command as a dict with the following keys:

  • executable: The name of the executable (E.g.: python, sqlite, …).
  • args: Arguments for the executable as a list.
  • kwargs: Keyword arguments for the executable as a dict. my_option: "myvalue"
    is automatically translated to --my-option="myvalue".
run()[source]

Method representing the thread’s activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

stop()[source]

Must stop the code running in the thread (the code in the run method).

class ievv_opensource.utils.ievvdevrun.runnables.django_runserver.RunnableThread(host='127.0.0.1', port='8000')[source]

Bases: ievv_opensource.utils.ievvdevrun.runnables.base.ShellCommandRunnableThread

Django runserver runnable thread.

Examples

You can just add it to your Django development settings with:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.django_runserver.RunnableThread()
    )
}

And you can make it not restart on crash with:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.django_runserver.RunnableThread(
            autorestart_on_crash=False)
    )
}
Parameters:
  • host – The host to run the Django server on. Defaults to "127.0.0.1".
  • port – The port to run the Django server on. Defaults to "8000".
get_logger_name()[source]

Get the logger name. Defaults to the name-parameter and falls back on the module name of the class.

get_command_config()[source]

Get the config for the shell/system command as a dict with the following keys:

  • executable: The name of the executable (E.g.: python, sqlite, …).
  • args: Arguments for the executable as a list.
  • kwargs: Keyword arguments for the executable as a dict. my_option: "myvalue"
    is automatically translated to --my-option="myvalue".
class ievv_opensource.utils.ievvdevrun.runnables.dbdev_runserver.RunnableThread(name=None, command_config=None, autorestart_on_crash=None)[source]

Bases: ievv_opensource.utils.ievvdevrun.runnables.base.ShellCommandRunnableThread

Django-DBdev run database runnable thread.

Examples

You can just add it to your Django development settings with:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.dbdev_runserver.RunnableThread()
    )
}
Parameters:
  • name – Optional name for the runnable. Defaults to the module name.
  • command_config – Same format as the return value from get_command_config().
  • autorestart_on_crash – Set this to True if you want to automatically restart the process if it crashes.
get_logger_name()[source]

Get the logger name. Defaults to the name-parameter and falls back on the module name of the class.

get_command_config()[source]

Get the config for the shell/system command as a dict with the following keys:

  • executable: The name of the executable (E.g.: python, sqlite, …).
  • args: Arguments for the executable as a list.
  • kwargs: Keyword arguments for the executable as a dict. my_option: "myvalue"
    is automatically translated to --my-option="myvalue".
start()[source]

Start the thread’s activity.

It must be called at most once per thread object. It arranges for the object’s run() method to be invoked in a separate thread of control.

This method will raise a RuntimeError if called more than once on the same thread object.

run()[source]

Method representing the thread’s activity.

You may override this method in a subclass. The standard run() method invokes the callable object passed to the object’s constructor as the target argument, if any, with sequential and keyword arguments taken from the args and kwargs arguments, respectively.

stop()[source]

Must stop the code running in the thread (the code in the run method).

class ievv_opensource.utils.ievvdevrun.runnables.elasticsearch.RunnableThread(configpath, elasticsearch_executable='elasticsearch', **kwargs)[source]

Bases: ievv_opensource.utils.ievvdevrun.runnables.base.ShellCommandRunnableThread

Elasticsearch runnable thread.

Examples

You can just add it to your Django development settings with:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.elasticsearch.RunnableThread(
            configpath='not_for_deploy/elasticsearch.develop.yml')
    )
}
get_logger_name()[source]

Get the logger name. Defaults to the name-parameter and falls back on the module name of the class.

get_command_config()[source]

Get the config for the shell/system command as a dict with the following keys:

  • executable: The name of the executable (E.g.: python, sqlite, …).
  • args: Arguments for the executable as a list.
  • kwargs: Keyword arguments for the executable as a dict. my_option: "myvalue"
    is automatically translated to --my-option="myvalue".
class ievv_opensource.utils.ievvdevrun.runnables.redis_server.RunnableThread(port='6379', config_path=None)[source]

Bases: ievv_opensource.utils.ievvdevrun.runnables.base.ShellCommandRunnableThread

redis-server runnable thread.

Examples

You can just add it to your Django development settings with:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.redis_server.RunnableThread()
    )
}

Or if you want Redis to run with your custom redis.conf file:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.redis_server.RunnableThread(config_path=/path/to/config/redis.conf)
    )
}

And you can make it not restart on crash with:

IEVVTASKS_DEVRUN_RUNNABLES = {
    'default': ievvdevrun.config.RunnableThreadList(
        ievvdevrun.runnables.redis_server.RunnableThread(
            autorestart_on_crash=False)
    )
}
Parameters:
  • port – The port to run the Redis server on. Defaults to "6379".
  • config_path – Path to the redis.conf file. Defaults to None.
get_logger_name()[source]

Get the logger name. Defaults to the name-parameter and falls back on the module name of the class.

get_command_config()[source]

Get the config for the shell/system command as a dict with the following keys:

  • executable: The name of the executable (E.g.: python, sqlite, …).
  • args: Arguments for the executable as a list.
  • kwargs: Keyword arguments for the executable as a dict. my_option: "myvalue"
    is automatically translated to --my-option="myvalue".

Low level API

class ievv_opensource.utils.ievvdevrun.config.RunnableThreadList(*runnablethreads)[source]

Bases: object

List of AbstractRunnableThread objects.

You use this with the IEVVTASKS_DEVRUN_RUNNABLES setting to define what to run with ievv devrun.

Parameters:runnablethreadsAbstractRunnableThread objects to add to the list.
append(runnablethread)[source]

Append a AbstractRunnableThread.

Parameters:runnablethread – A AbstractRunnableThread object.
start()[source]

Start all the runnable threads and block until SIGTERM or KeyboardInterrupt.