package Ubic::Service::Skeleton;
$Ubic::Service::Skeleton::VERSION = '1.60';
use strict;
use warnings;
# ABSTRACT: skeleton of any service with common start/stop logic
use Ubic::Result qw(result);
use Scalar::Util qw(blessed);
use Time::HiRes qw(sleep);
use Ubic::Service::Utils qw(wait_for_status);
use parent qw(Ubic::Service);
sub status {
my ($self) = @_;
my $result = $self->status_impl;
$result ||= 'unknown';
$result = result($result);
return $result;
}
sub start {
my ($self) = @_;
my $status = $self->status;
if ($status->status eq 'running') {
return 'already running'; # TODO - update $status field instead?
}
elsif ($status->status eq 'not running') {
return $self->_do_start;
}
elsif ($status->status eq 'broken') {
# checks inside _do_start and _do_stop guarantee correct status
$self->_do_stop;
return $self->_do_start;
}
else {
die result('unknown', "wrong status '$status'");
}
}
sub stop {
my ($self) = @_;
my $status = $self->status;
if ($status->status eq 'not running') {
return 'not running';
}
return $self->_do_stop;
}
sub status_impl {
die 'not implemented';
}
sub start_impl {
die 'not implemented';
}
sub stop_impl {
die 'not implemented';
}
sub timeout_options {
return {};
}
##### internal methods ######
sub _do_start {
my ($self) = @_;
my $status;
my $start_result = $self->start_impl;
if (blessed($start_result) and $start_result->isa('Ubic::Result::Class')) {
$status = $start_result;
}
if (not $status or $status->type eq 'starting') {
$status = wait_for_status({
service => $self,
expect_status => ['running', 'not running'],
%{ $self->timeout_options->{start} || {} },
});
if ($status->status eq 'running') {
$status->type('started'); # fake status to report correct action (hopefully)
}
}
if (not $status) {
die result('unknown', 'no result');
}
if ($status->status eq 'running') {
return $status;
}
else {
die result($status, 'start failed');
}
}
sub _do_stop {
my ($self) = @_;
my $status;
my $stop_result = $self->stop_impl;
if (blessed($stop_result) and $stop_result->isa('Ubic::Result::Class')) {
$status = $stop_result;
}
if (not $status or $status->type eq 'stopping') {
$status = wait_for_status({
service => $self,
expect_status => ['not running'],
%{ $self->timeout_options->{stop} || {} },
});
if ($status->status eq 'not running') {
$status->type('stopped'); # fake status to report correct action (hopefully)
}
}
if (not $status) {
die result('unknown', 'no result');
}
if ($status->status eq 'not running') {
return $status;
}
else {
die result($status, 'stop failed');
}
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
Ubic::Service::Skeleton - skeleton of any service with common start/stop logic
=head1 VERSION
version 1.60
=head1 ACTIONS
=over
=item B<< status() >>
Get status of service.
Possible values: C<running>, C<not running>, C<unknown>, C<broken>.
=item B<< start() >>
Start service.
Throws exception on failure.
=item B<< stop() >>
Stop service.
Return values: C<stopped>, C<not running>.
Throws exception on failure.
=back
=head1 OVERLOADABLE METHODS
Subclass must overload following methods with simple status, start and stop implementations.
=over
=item B<status_impl>
Status implementation. Should return result object or plain string which coerces to result object.
=item B<start_impl>
Start implementation.
It can check for status itself and return proper C<Ubic::Result> value, or it can allow skeleton class to recheck status after that, in several attempts.
To choose second option, it should return non-result value or C<result("starting")>. See C<timeout_options()> method for details about recheck policy.
=item B<stop_impl>
Stop implementation.
It can check for status itself and return proper C<Ubic::Result> value, or it can allow skeleton class to recheck status after that, in several attempts.
To choose second option, it should return non-result value or C<result("stopping")>. See C<timeout_options()> method for details about recheck policy.
=item B<timeout_options>
Return hashref with timeout options.
Possible options:
=over
=item I<start>
Params to be used when checking for status of started service.
Should contain hashref with I<step> and I<trials> options for C<wait_for_status> function from C<Ubic::Service::Utils>.
=back
=back
=head1 AUTHOR
Vyacheslav Matyukhin <mmcleric@yandex-team.ru>
=head1 COPYRIGHT AND LICENSE
This software is copyright (c) 2016 by Yandex LLC.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut