November 2010 Archives

New Ubic slides

Here are the slides from my recent talk at meeting.
They are more detailed and hopefully less cryptic than my inital presentation.

Ubic - multiservices

(This is a long time overdue post in Ubic series. Previous posts can be found here.)

Last time I explained how any kind of service start/stop/status behavior can be encapsulated in an Ubic::Service subclass. But what if you have many similar services, and want to generate the service list dynamically?

For example, sometimes you already have a directory with daemon configs, and want to run them all without creating additional "service description" file per daemon.
Or you may wish to start ten instances of one processing script.
Or maybe you keep the list of your services in SQL database on another host.

In all these cases, multiservices come to the rescue.
Multiservice is a container object which provides part of the service tree.

For example, let's assume you have a dir /usr/share/psgi-apps/ with some psgi apps in it:

$ ls /usr/share/psgi-apps/
hello-14001.psgi world-14002.psgi

Future HTTP port number in this example is encoded in the file name.

Let's map these apps into ubic service tree:

# content of /etc/ubic/service/psgi-apps file

use parent qw(Ubic::Multiservice);
use Ubic::Service::Plack;

sub new {
return bless {} => shift;

sub service_names {
my @files = glob "/usr/share/psgi-apps/*.psgi";
s{^/usr/share/psgi-apps/(.*)-\d+.psgi$}{$1} for @files;
return @files;

sub simple_service {
my $name = $_[1];
my ($file) = glob "/usr/share/psgi-apps/$name-*.psgi";
my ($port) = $file =~ /(\d+)\.psgi$/;
return Ubic::Service::Plack->new({
server => 'Standalone',
app => $file,
app_name => $name,
port => $port,
stdout => "/var/log/psgi-apps/$name.log",
stderr => "/var/log/psgi-apps/$name.err.log",

return __PACKAGE__->new;

Assuming that /var/log/psgi-apps/ dir exists, this code is enough to run existing *and* all future psgi apps in /usr/share/psgi-apps/ dir.
"service_names" method returns plain list of service names, and "simple_service" builds service by name. It's really simple :)

Now, all psgi apps can be started simultaneously with one command:

$ sudo ubic start -f psgi-apps
Starting psgi-apps.hello... started
Starting started

... or one by one:

$ sudo ubic stop
Stopping stopped

When someone is performing some global action, multiservices are grouped in indented trees:

$ sudo ubic status
ubic-ping running (pid 18641)
sleeping-daemon running (pid 8056)
psgi-apps.hello running off

And of course you can create several levels of nesting too if you need them.

There are two multiservice classes in core Ubic distribution.

First, there is a Ubic::Multiservice::Simple class, which can be used for cases when you just want to group several services together:

# content of /etc/ubic/service/my
use Ubic::Multiservice::Simple;
return Ubic::Multiservice::Simple->new({
fcgi_app => $fcgi_app_service,
memcached => $memcached_service,

It's also handy for generating several identical workers:

# content of /etc/ubic/service/ten-workers
use Ubic::Multiservice::Simple;
use Ubic::Service::SimpleDaemon;
return Ubic::Multiservice::Simple->new({
map {(
"worker$_" => Ubic::Service::SimpleDaemon->new({
bin => "",
)} (1..10)

Second, there is a Ubic::Multiservice::Dir. Nobody usually uses it directly, but it is constructed for every subdir in /etc/ubic/service/, so that /etc/ubic/service/a/b file is mapped to "a.b" service.

So, summing it up, multiservices are useful for:
- grouping services together for easier management;
- dynamically generating services from external sources;
- running a large number of identical worker processes.
They really simplify some complex tasks and make ubic as unobtrusive and extensible as it is possible.

PS: PSGI example requires Ubic=1.22 and Ubic::Service::Plack=1.12. I made multiservice API slightly simpler while writing this post, and fixed one bug in Ubic::Service::Plack. Both of these modules should be available on CPAN soon.

PPS: Contacts:
our irc channel is #ubic at;
source code is at;
mailing list is at

If you are using ubic or have any questions, let me know. It motivates me SO much :)

About Vyacheslav Matyukhin

user-pic I wrote Ubic. I worked at Yandex for many years, and now i'm building my own startup (formerly PlayPerl). I'm also working on Flux, streaming data processing framework. CPAN ID: MMCLERIC.