:title: Background Processes
:description: How dotCloud defines worker services and background processes.
:keywords: dotCloud documentation, quick start guide,
Background Processes
====================
.. include:: ../dotcloud2note.inc
.. include:: ../services/worker.inc
.. Ok, this is going to be difficult to merge with the new features in
dotcloud.yml. The documentation between supervisord.conf and dotcloud.yml
will overlap in same places but not everywhere. For example the section about
catching signal should be common to supervisord.conf and dotcloud.yml but
only supervisord.conf allows you to configure the signal to send.
.. _guides-define-daemons:
Defining Daemons
----------------
To run a background process you need to write a *supervisord.conf* file in the
.ini format, for example:
.. code-block:: ini
[program:daemonname]
command = php /home/dotcloud/current/my_daemon.php
This is the most simple configuration that you can write, it defines a daemon
called *daemonname* that is launched using the *"php /home/dotcloud/current/my_daemon.php"*
command.
You can use multiple *[program:x]* sections to run different daemons.
Once, you have the code of your daemon, your supervisord.conf file and your
dotcloud.yml Build File can push your application on dotCloud using "dotcloud
push".
.. note::
When you run ``"dotcloud push"``, your code will be installed in
/home/dotcloud/current by the dotCloud builder process. That's why we
specified this path.
If your script is installed into the $PATH, you don't need to include its
full path. (i.e: you can just write "command = my_daemon.php" instead).
.. note::
If you are not on Windows, do not forget to set the executable bit on your
daemon by using "chmod +x".
Configuring The Environment
---------------------------
You can easily modify the environment of execution of your daemon with the
"directory" and "environment" directives to change the directory where the
command is executed and to define additional environment variable. For example:
.. code-block:: ini
[program:daemonname]
command = php my_daemon.php
directory = /home/dotcloud/current/
environment = QUEUE="*" , VERBOSE="TRUE"
.. note::
Don't forget the quotes around the environment variable values!
Supervisor is quite picky about this. If you specify something like
``PYTHONPATH=/foo/bar`` instead of ``PYTHONPATH="/foo/bar"``,
Supervisor will truncate it to ``/``. So beware!
Exit Cleanly With Signals
-------------------------
You are advised to catch the SIGTERM signal sent by Supervisor when it tries to
gracefully stop or restart your daemon. This will happen each time you push a
new revision of your application. This is important if your daemon cannot be
interrupted in the middle of a job.
Here is some complete daemon examples that exit cleanly on SIGTERM:
.. tabswitcher::
.. tab:: PHP
To catch signals in PHP you need to add a *"declare()"* at the top of your PHP
files and then register a callback:
.. code-block:: php
#!/usr/bin/env php
You can find the full reference on Unix signal functions here:
http://www.php.net/manual/en/intro.pcntl.php
.. tab:: Ruby
.. code-block:: ruby
#!/usr/bin/env ruby
# Callback called when you run `supervisorctl stop'
def sigterm_handler
warn "Kaboom Baby!"
exit
end
def main
while true do
warn "Tick"
sleep 1
end
end
# Bind our callback to the SIGTERM signal and run the daemon:
Signal.trap("TERM") { sigterm_handler }
main
.. tab:: Perl
.. code-block:: perl
#!/usr/bin/env perl
use strict;
use warnings;
sub sigterm_handler()
{
print STDERR "Kaboom Baby!\n";
exit 0;
}
sub main()
{
while (1) {
print STDERR "Tick\n";
sleep 1;
}
}
$SIG{TERM} = \&sigterm_handler;
main;
.. tab:: Python
.. code-block:: python
#!/usr/bin/env python
import sys
import time
import signal
# Callback called when you run `supervisorctl stop'
def sigterm_handler(signum, frame):
print >> sys.stderr, "Kaboom Baby!"
sys.exit(0)
def main():
while True:
print >> sys.stderr, "Tick"
time.sleep(1)
# Bind our callback to the SIGTERM signal and run the daemon:
signal.signal(signal.SIGTERM, sigterm_handler)
main()
.. tab:: NodeJS
.. code-block:: javascript
#!/usr/bin/env node
function sigterm_handler() {
console.warn('Kaboom Baby!');
process.exit(0);
}
function main() {
setInterval(function() {
console.warn('Tick');
},
1000
);
}
process.on('SIGTERM', sigterm_handler);
main();
If your daemon doesn't follow the SIGTERM convention you can tell Supervisor to
use the signal of your choice with the "stopsignal" directive:
.. code-block:: ini
[program:daemonname]
command = php /home/dotcloud/current/my_daemon.php
stopsignal = QUIT
This example will use SIGQUIT to try to gracefully stop the daemon instead of
SIGTERM.
Configure Logging
-----------------
By default, Supervisor will create log files for you in the */var/log/supervisor/*
directory.
You can change this by using the "stderr_logfile" ---for the error output---
and the "stdout_logile" ---for the standard output--- directives:
.. code-block:: ini
[program:daemonname]
command = php /home/dotcloud/current/my_daemon.php
stderr_logfile = /var/log/supervisor/daemonname_error.log
stdout_logfile = /var/log/supervisor/daemonname.log
You can also choose to redirect the error output to the standard output, to get
everything in one log file, with ``redirect_stderr = true``.
.. _guides-multiple-workers:
Launching Multiple "Workers"
----------------------------
You can use Supervisor to launch multiple instances of one daemon. To do this you
need three things in your supervisord.conf.
First, a "numprocs" entry, for the number of identical processes to launch:
.. code-block:: ini
numprocs = 2
Second, a "process_name" entry, to give each process a different name:
.. code-block:: ini
process_name = "%(program_name)s-%(process_num)s"
Finally, you also need to give each log file a different name:
.. code-block:: ini
stderr_logfile = /var/log/supervisor/daemonname_error-%(process_num)s.log
stdout_logfile = /var/log/supervisor/daemonname-%(process_num)s.log
Here is a complete supervisord.conf example:
.. code-block:: ini
[program:daemonname]
command = php /home/dotcloud/current/my_daemon.php
numprocs = 2
process_name = "%(program_name)s-%(process_num)s"
stderr_logfile = /var/log/supervisor/daemonname_error-%(process_num)s.log
stdout_logfile = /var/log/supervisor/daemonname-%(process_num)s.log
Troubleshooting
---------------
You can check that your daemon has been started properly with the following
command::
dotcloud run workers supervisorctl status
If everything's fine, you should see an output similar to this one::
daemonname RUNNING pid 975, uptime 0:03:20
Supervisor provides some useful commands to start, stop, and restart programs::
dotcloud run tick supervisorctl stop daemonname
dotcloud run tick supervisorctl start daemonname
dotcloud run tick supervisorctl restart daemonname
You can also run the Supervisor shell interactively if you like::
dotcloud run tick supervisorctl
Caveats
-------
For performance reasons, Supervisor buffers the standard output, so the "echoes"
you do in your daemon will not show immediately in the log file. However, the
error output is written right away in the corresponding log file. Here is how to
write on the error output for different languages:
.. tabswitcher::
.. tab:: PHP
.. code-block:: php
#!/usr/bin/env php
.. tab:: Ruby
.. code-block:: ruby
#!/usr/bin/env ruby
warn "This message will be written on the error output"
.. tab:: Perl
.. code-block:: perl
#!/usr/bin/env perl
print STDERR "This message will be written on the error output\n";
.. tab:: Python
.. code-block:: python
#!/usr/bin/env python
print >> sys.stderr, "This message will be written on the error output"
.. tab:: NodeJS
.. code-block:: javascript
#!/usr/bin/env node
console.warn("This message will be written on the error output\n");
Supervisor stops to read any output as soon as it begins to stop daemons [#]_.
For example that means that the output of our *sigterm_handler* function above
will never show up in the logs, however the function is perfectly executed.
You can write daemons that listen on TCP or UDP ports but you will not be able
to reach them over the Internet or from another dotCloud instance. However this
is one of our next features.
You can find the supervisord.conf reference in the `Supervisor documentation
`_.
----
.. [#] http://www.plope.com/software/collector/271