Supervisor: dynamic environment variable

Created on 20 Dec 2015  路  6Comments  路  Source: Supervisor/supervisor

Hi,

I want my environment variable to be dynamic, which means - the expression which is used to get it would be recalculated each time supervisor tries to spawn the process.

What I have tried:

environment=ETCD_HOST=$(ifconfig eth1 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}')

But it doesn't work. Restart ends up with:

image

What can I do here? How to make it dynamic?

Any thoughts?

Regards,

environment question

Most helpful comment

In my case I found this as solution:

[program:etcd-browser]
command=/bin/bash -c \"ETCD_HOST=\$(ifconfig eth1 | grep 'inet addr:' | cut -d: -f2 | awk '{ print \$1}') node server.js\"

This is fine also, but you should use exec like the second example above.

Change node server.js to exec node server.js. Using exec will cause bash to replace itself with node. After the command is run, supervisord will have one child node.

Without exec, supervisord will have a child bash, and bash will have a child node. You can see this with pstree. This is undesirable because if bash alone receives SIGKILL (e.g. if killasgroup=false) then it will orphan node.

All 6 comments

supervisord is not a shell, so it doesn't know how to evaluate the shell expression that you tried to put into the environment= line. The solution is to use a shell evaluate the expression.

Before supervisord starts

You can set up the environment in the init script that starts supervisord:

export ETCD_HOST=$(ifconfig eth1 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}')
supervisord -c /path/to/supervisord.conf

The shell will set ETCD_HOST in the environment which supervisord will inherit. That environment variable will then be available to all supervisord subprocesses.

Per-program basis

If you have a program that runs the command foo:

[program:foo]
command=foo

You can create a shell script start-foo.sh:

#!/bin/bash
export ETCD_HOST=$(ifconfig eth1 | grep 'inet addr:' | cut -d: -f2 | awk '{ print $1}')
exec foo

In supervisord.conf, start the shell script instead of foo:

[program:your-program]
command = start-foo.sh

Hi @mnaberez,

Thanks for the explanation and answer.

In my case I found this as solution:

[program:etcd-browser]
command=/bin/bash -c \"ETCD_HOST=\$(ifconfig eth1 | grep 'inet addr:' | cut -d: -f2 | awk '{ print \$1}') node server.js\"

However, I think it would be cool, and have some logic behind, if supervisor would evaluate the expressions from the environment configuration option. Before running the command.
Currently it's expected that we store only strings there, but I think it's still logical to store the expressions and it could be considered as feature.

Regards, thanks for the software!

In my case I found this as solution:

[program:etcd-browser]
command=/bin/bash -c \"ETCD_HOST=\$(ifconfig eth1 | grep 'inet addr:' | cut -d: -f2 | awk '{ print \$1}') node server.js\"

This is fine also, but you should use exec like the second example above.

Change node server.js to exec node server.js. Using exec will cause bash to replace itself with node. After the command is run, supervisord will have one child node.

Without exec, supervisord will have a child bash, and bash will have a child node. You can see this with pstree. This is undesirable because if bash alone receives SIGKILL (e.g. if killasgroup=false) then it will orphan node.

@mnaberez

Thanks!

@mnaberez

Thanks a bunch.

I am trying to spawn a number of processes, and trying to use sched_setaffinity to bind each process to a single CPU core.

The result config looks like this:

[program:my_program]
command=/bin/sh -c 'exec taskset -c $((%(process_num)d %% $(nproc))) /path/bin/my_program'

The result exactly as I planned. Each process spawned by supervisor with %(process_num)d will be bind to a dedicated CPU processor core. taskset+supervisor FTW!

I literally just lost an hour or two figuring out that supervisor doesn't reload environment variables when restarting process, they are only loaded once on start up of supervisord. The workaround I had to come to was the following:

command=/bin/bash -c 'some-command --derp $(cat ~/somevalue)'

Where I simply wanted:

command=some-command --derp %(ENV_SOMEVALUE)s

Perhaps an option to allow for reloading of environment variables per [program] block or reload on supervisorctl update this behaviour feels terrible. I wish I could understand the reasoning behind it...

Was this page helpful?
0 / 5 - 0 ratings