In my previous post I showed most trivial example of ubic service.

Now it's time to talk about more interesting stuff :)

Every ubic service is simply a perl object which implements start/stop/status methods.

It is very similar to /etc/init.d shell scripts, but since perl is a real programming language, you don't have to copy-paste tons of boilerplate code every time (Dave Rolsky, if you're reading this - your silki init script is good, but "apache2-backend" line in comments means it was copy-pasted too; is there anyone who can actually write proper init script by hands?).

So, instead of copy-pasting, you can reuse any existing Ubic::Service::* module, or implement your own if it's necessary.

For example, there is the Ubic-Service-Plack distribution on CPAN which you can use to run any PSGI applications.

Quoting Ubic::Service::Plack synopsis:





use Ubic::Service::Plack;

return Ubic::Service::Plack->new({

server => "FCGI",

server_args => { listen => "/tmp/app.sock",

nproc => 5 },

app => "/var/www/app.psgi",

app_name => 'app',

status => sub { ... },

port => 4444,

ubic_log => '/var/log/app/ubic.log',

stdout => '/var/log/app/stdout.log',

stderr => '/var/log/app/stderr.log',

user => "ppb",

});



Notice the 'status' coderef. It is optional, but if provided, it can be used as custom status check:





...

status => sub {

use IO::Socket::UNIX;

use IO::Select;

use Ubic::Result qw(result);

my $socket = IO::Socket::UNIX->new(

Peer => $self->{socket},

Timeout => 5,

) or return 'broken';

$socket->send(pack("C*", 1,9,0,0 ,0,0,8,0 , 0,0,0,0, 0,0,0,0));

my $content = "";

my $select = IO::Select->new($socket);

unless ($select->can_read(5)) {

return result('broken', 'socket timeout');

}

$socket->recv($content, 8);

my @bytes = unpack("C8", $content);

if ($bytes[1] == 10) {

return 'running';

}

else {

return 'broken';

}

},

...



We ping FCGI socket using FCGI_GET_VALUES request (thanks to unknown stackoverflow guy for this method).In case process responds properly, 'running' string is returned, and 'broken' string is returned in other cases.We don't have to check if process is actually running and if pidfile is valid - Ubic::Service::Plack does this for us.

This check will be called several times with increasing time intervals until status will become 'running'. Time intervals and number of checks until ubic will give up are configurable too (actually, they are implemented in Ubic::Service::Common class, which can be base class for most ubic services unless you want to do something really complex).

Now, if you have tons of PSGI applications which you run as fastcgi servers, you can implement Ubic::Service::Plack::FCGI on top of Ubic::Service::Plack.

Or maybe you are running tons of HTTP servers which all implement http://.../ping http check.

Or you may wish to restart your service on some external conditions, like Steven Haryanto wants to.

All these things can be implemented using custom status checks and then encapsulated via ineritance or delegation.

Of course, 'start', 'stop' and 'reload' methods can be replaced as well.



One last bit of information (it should have been in first post but i forgot to mention it): any ubic service can be turned into SysV init script.

Simply put this line in /etc/init.d/ and you are done:





# cat >/etc/init.d/any-ubic-service

#!/usr/bin/perl

use Ubic::Run;



Yes, that's enough to get LSB-compliant init script corresponding to ubic service named 'any-ubic-service'. Isn't ubic just great? :)



Next time I'll talk about multiservices and custom commands.

Also, there are Ubic::Service::Memcached and Ubic::Service::Lighttpd I still have to upload.

Don't forget to join our mailing list if you are interested in ubic and service managing stuff!