File Coverage

blib/lib/DBIx/MySQL/Replication/Slave.pm
Criterion Covered Total %
statement 2 4 50.0
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 4 6 66.6


line stmt bran cond sub pod time code
1             package DBIx::MySQL::Replication::Slave;
2             BEGIN {
3 2     2   4762 $DBIx::MySQL::Replication::Slave::VERSION = '0.02';
4             }
5              
6 2     2   697 use Moose;
  0            
  0            
7              
8             =head1 NAME
9              
10             DBIx::MySQL::Replication::Slave - Stop, start and monitor your slaves.
11              
12             =head1 VERSION
13              
14             version 0.02
15              
16             =head1 SYNOPSIS
17              
18             This module gives you an OO interface for stopping, starting and monitoring
19             the status and health of your MySQL slaves. It doesn't do anything you can't
20             already do for yourself, but it makes some basic tasks just a little bit
21             easier.
22              
23             use DBIx::MySQL::Replication::Slave;
24              
25             my $slave = DBIx::MySQL::Replication::Slave->new( dbh => $dbh );
26              
27             if ( $slave->is_stopped ) {
28            
29             $slave->start;
30            
31             if ( $slave->is_running ) {
32             print "slave now running\n";
33             }
34             else {
35             print "cannot start stopped slave.\n";
36             }
37            
38             }
39              
40             If you need a quick monitor script:
41              
42             $slave->max_seconds_behind_master( 30 );
43              
44             if ( !$slave->slave_ok ) {
45             # send an alert to the administrator...
46             }
47              
48             For some quick debugging:
49              
50             use Data::Dump qw( dump );
51             print dump( $slave->status );
52              
53             print "seconds behind: " . $slave->status->{seconds_behind_master};
54              
55             =head1 CONSTRUCTOR AND STARTUP
56              
57             =head2 new( dbh => $dbh )
58              
59             Creates and returns a new DBIx::MySQL::Replication::Slave object.
60              
61             my $slave = DBIx::MySQL::Replication::Slave->new( dbh => $dbh );
62              
63             =over 4
64              
65             =item * C<< dbh => $dbh >>
66              
67             A valid database handle to your slave server is required. You'll need to pass
68             it to the constructor:
69              
70             my $slave = DBIx::MySQL::Replication::Slave->new( dbh => $dbh );
71              
72             Generally, the user will need to have the following MySQL privileges:
73              
74             SUPER,REPLICATION CLIENT
75              
76             =item * C<< lc => 0|1 >>
77              
78             By default, the status variables returned by MySQL are converted to lower case.
79             This is for readability. You may turn this off if you wish, by explicitly
80             turning it off when you create the object:
81              
82             my $slave = DBIx::MySQL::Replication::Slave->new( dbh => $dbh, lc => 0 );
83              
84             =item * C<< max_seconds_behind_master => $seconds >>
85              
86             By default this is set to a very generous number (86400 seconds). Set this
87             value if you'd like to take a shorter amount of time into account when
88             checking on your health. This is strongly recommended:
89              
90             # Anything longer than 30 seconds is not acceptable
91             my $slave = DBIx::MySQL::Replication::Slave->new(
92             dbh => $dbh,
93             seconds_behind_master => 30
94             );
95              
96             If you think it's cleaner, you can also set this value *after* object creation.
97              
98             $slave->max_seconds_behind_master(30);
99              
100             =back
101              
102             =head1 SUBROUTINES/METHODS
103              
104             =head2 status
105              
106             Returns a HASHREF of the MySQL slave status variables. These vars will, by
107             default, be converted to lower case, unless you have turned this off when you
108             construct the object. See the lc option to new() for more info.
109              
110             =head2 refresh_status
111              
112             Issues a fresh "SLOW SLAVE STATUS" query and returns the new results of
113             $slave->status to you.
114              
115             =head2 start
116              
117             Issues a "START SLAVE" query and returns DBI's raw return value directly to
118             you.
119              
120             =head2 stop
121              
122             Issues a "STOP SLAVE" query and returns DBI's raw return value directly to
123             you.
124              
125             =head2 slave_ok
126              
127             This method returns true if slave_io_running and slave_sql_running are both
128             equal to 'Yes' AND if seconds_behind_master is <= max_seconds_behind master.
129              
130             =head2 is_running
131              
132             Returns true if both slave_io_running and slave_sql_running are set to 'Yes'
133              
134             =head2 is_stopped
135              
136             Returns true if both slave_io_running and slave_sql_running are set to 'No'.
137             If only one of these values returns 'Yes', it's probably fair to say that the
138             slave is in some transitional state. Neither stopped nor running may be an
139             accurate description in this case.
140              
141             =head1 AUTHOR
142              
143             Olaf Alders, C<< <olaf at wundercounter.com> >>
144              
145             =head1 BUGS AND LIMITATIONS
146              
147             Please report any bugs or feature requests to
148             C<bug-dbix-mysql-replication-slave at rt.cpan.org>, or through the web
149             interface at
150             L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=DBIx-MySQL-Replication-Slave>.
151             I will be notified, and then you'll automatically be notified of progress on
152             your bug as I make changes.
153              
154             =head1 TESTING
155              
156             Have a look at the source of t/connect.t if you'd like to do more extensive
157             testing of your install. This will require that you already have a fully
158             functional slave set up in order for the tests to pass. These tests are
159             skipped by default, but you are encouraged to run them as part of your install
160             process.
161              
162             =head1 SUPPORT
163              
164             You can find documentation for this module with the perldoc command.
165              
166             perldoc DBIx::MySQL::Replication::Slave
167              
168              
169             You can also look for information at:
170              
171             =over 4
172              
173             =item * GitHub Source Repository
174              
175             L<http://github.com/oalders/dbix-mysql-replication-slave>
176              
177             =item * RT: CPAN's request tracker
178              
179             L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=DBIx-MySQL-Replication-Slave>
180              
181             =item * AnnoCPAN: Annotated CPAN documentation
182              
183             L<http://annocpan.org/dist/DBIx-MySQL-Replication-Slave>
184              
185             =item * CPAN Ratings
186              
187             L<http://cpanratings.perl.org/d/DBIx-MySQL-Replication-Slave>
188              
189             =item * Search CPAN
190              
191             L<http://search.cpan.org/dist/DBIx-MySQL-Replication-Slave/>
192              
193             =back
194              
195             =head1 ACKNOWLEDGEMENTS
196              
197             Thanks to Raybec Communications L<http://www.raybec.com> for funding my
198             work on this module and for releasing it to the world.
199              
200              
201             =head1 LICENSE AND COPYRIGHT
202              
203             Copyright 2010 Olaf Alders.
204              
205             This program is free software; you can redistribute it and/or modify it
206             under the terms of either: the GNU General Public License as published
207             by the Free Software Foundation; or the Artistic License.
208              
209             See http://dev.perl.org/licenses/ for more information.
210              
211             =cut
212              
213             has 'dbh' => (
214             isa => 'DBI::db',
215             is => 'rw',
216             required => 1,
217             );
218              
219             has 'lc' => (
220             default => 1,
221             is => 'rw',
222             isa => 'Str',
223             required => 0,
224             );
225              
226             has 'max_seconds_behind_master' => (
227             default => 86400,
228             is => 'rw',
229             isa => 'Str',
230             required => 0,
231             );
232              
233             has '_lc_status' => (
234             is => 'rw',
235             isa => 'HashRef',
236             );
237              
238             has '_status' => (
239             is => 'rw',
240             isa => 'HashRef',
241             lazy_build => 1,
242             );
243              
244             sub status {
245             my $self = shift;
246             return $self->_status if !$self->lc;
247             return $self->_get_lc_status;
248             }
249              
250             sub slave_ok {
251              
252             my $self = shift;
253             my $status = $self->_get_lc_status;
254              
255             if ( $status->{slave_io_running} eq 'Yes'
256             && $status->{slave_sql_running} eq 'Yes'
257             && $status->{seconds_behind_master}
258             <= $self->max_seconds_behind_master )
259             {
260             return 1;
261             }
262              
263             return 0;
264              
265             }
266              
267             sub stop {
268              
269             my $self = shift;
270             return $self->dbh->do("STOP SLAVE");
271              
272             }
273              
274             sub is_stopped {
275              
276             my $self = shift;
277             $self->refresh_status;
278              
279             my $status = $self->_get_lc_status;
280              
281             if ( $status->{slave_io_running} eq 'No'
282             && $status->{slave_sql_running} eq 'No' )
283             {
284             return 1;
285             }
286              
287             return 0;
288             }
289              
290             sub start {
291              
292             my $self = shift;
293             return $self->dbh->do("START SLAVE");
294              
295             }
296              
297             sub is_running {
298              
299             my $self = shift;
300              
301             # allow some time to connect, if need be
302             foreach (1..10) {
303             $self->refresh_status;
304             if ( $self->status->{slave_io_state} ne 'Connecting to master' ) {
305             last;
306             }
307             else {
308             sleep 1;
309             }
310             }
311              
312             my $status = $self->_get_lc_status;
313              
314             if ( $status->{slave_io_running} eq 'Yes'
315             && $status->{slave_sql_running} eq 'Yes' )
316             {
317             return 1;
318             }
319              
320             return 0;
321             }
322              
323             sub refresh_status {
324              
325             my $self = shift;
326             $self->status( $self->_build__status );
327             return $self->status;
328              
329             }
330              
331             sub _build__status {
332              
333             my $self = shift;
334             my $status = $self->dbh->selectrow_hashref( "SHOW SLAVE STATUS" );
335              
336             my $lc = {};
337             foreach my $col ( keys %{$status} ) {
338             $lc->{ lc $col } = $status->{$col};
339             }
340              
341             $self->_lc_status( $lc );
342             return $status;
343              
344             }
345              
346             sub _get_lc_status {
347              
348             my $self = shift;
349             $self->_status;
350             return $self->_lc_status;
351              
352             }
353              
354             1;