1package Toadfarm::Command::start;
2use Mojo::Base 'Toadfarm::Command::tail';
3
4use File::Basename 'dirname';
5use File::Spec;
6use Time::HiRes 'usleep';
7
8$ENV{TOADFARM_VERBOSE} //= $ENV{HARNESS_IS_VERBOSE} || -t STDOUT;
9
10has description => 'Toadfarm: Start the server if not already running';
11
12sub run { shift->_start(@_) }
13
14sub _hypnotoad {
15  my $self = shift;
16
17  for my $p (File::Spec->path, dirname($^X)) {
18    my $exe = File::Spec->catfile($p, 'hypnotoad');
19    return $exe if -r $exe;
20  }
21
22  die "Cannot find 'hypnotoad' in \$PATH.";
23}
24
25sub _is_running {
26  my $self = shift;
27  my $pid  = $self->_pid;
28  return $pid && kill 0, $pid;
29}
30
31sub _end {
32  my ($self, $exit, $message) = @_;
33
34  if ($message and $ENV{TOADFARM_VERBOSE}) {
35    $self->_printf("   ...%s (%s)\n", $exit ? "fail!" : "done.", $message);
36  }
37  else {
38    $self->_printf("   ...%s\n", $exit ? "fail!" : "done.");
39  }
40
41  return $exit if $ENV{TOADFARM_NO_EXIT};
42  exit $exit;
43}
44
45sub _log_daemon_msg {
46  my ($self, $message) = @_;
47  $self->_printf(" * $message\n", $self->app->moniker);
48}
49
50sub _pid {
51  my $self = shift;
52  my $file = $self->_pid_file;
53  return 0 unless $file and -e $file;
54  open my $PID, '<', $file or die "Unable to read pid_file $file: $!\n";
55  my $pid = join '', <$PID>;
56  return $pid =~ /(\d+)/ ? $1 : 0;
57}
58
59sub _pid_file {
60  my $self    = shift;
61  my $moniker = $self->app->moniker;
62  return $self->app->config->{hypnotoad}{pid_file}
63    || die "$moniker has invalid config: /hypnotoad/pid_file is not set.\n";
64}
65
66sub _printf { shift; printf shift, @_; }
67
68sub _start {
69  my ($self, @args) = @_;
70  my $pid = $self->_pid;
71  my $tail = grep {/^--tail/} @args;
72
73  $self->_log_daemon_msg('Starting the process %s');
74
75  # running
76  if ($self->_is_running) {
77    return $self->_tail(grep { !/^--tail/ } @args) if $tail;
78    return $self->_end(0, "already running with pid=$pid");
79  }
80
81  # start
82  system $self->_hypnotoad, $0;
83  my $exit = $? >> 8;
84  return $self->_end($exit, "hypnotoad $0 = $exit") if $exit;
85
86  # wait until started
87  $self->_wait_for(5 => sub { shift->_is_running });
88
89  # check if started
90  return $self->_end(3, 'daemon is not running') unless $self->_is_running;
91  return $self->_tail(grep { !/^--tail/ } @args) if $tail;
92  return $self->_end(0);
93
94}
95
96sub _wait_for {
97  my ($self, $cb) = (shift, pop);
98  my $timeout = shift || ($self->app->config->{hypnotoad}{graceful_timeout} || 20) + 5;
99
100  while ($timeout--) {
101    last if $self->$cb;
102  }
103  continue {
104    usleep(300e3);
105  }
106}
107
1081;
109
110=encoding utf8
111
112=head1 NAME
113
114Toadfarm::Command::start - Start a Toadfarm DSL script
115
116=head1 DESCRIPTION
117
118L<Toadfarm::Command::start> is a command for starting a L<Toadfarm> application.
119
120=head1 SYNOPSIS
121
122  $ /path/to/script.pl start
123  $ /path/to/script.pl start --tail <args>
124
125=head1 ATTRIBUTES
126
127=head2 description
128
129Short description of command, used for the command list.
130
131=head1 METHODS
132
133=head2 run
134
135Run command.
136
137=head1 COPYRIGHT AND LICENSE
138
139Copyright (C) 2014, Jan Henning Thorsen
140
141This program is free software, you can redistribute it and/or modify it under
142the terms of the Artistic License version 2.0.
143
144=head1 AUTHOR
145
146Jan Henning Thorsen - C<jhthorsen@cpan.org>
147
148=cut
149