Created
July 10, 2012 20:22
-
-
Save ulizama/3085991 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package Project::Plugin::Dancer::Rose::Database; | |
use strict; | |
use Dancer::Plugin; | |
use Referdia::DB; | |
# This module is based on the Dancer::Plugins::Database module | |
our $VERSION = '0.01'; | |
my %handles; | |
# Hashref used as key for default handle, so we don't have a magic value that | |
# the user could use for one of their connection names and cause problems | |
# (Kudos to Igor Bujna for the idea) | |
my $def_handle = {}; | |
register database => sub { | |
my $arg = shift; | |
my $handle_key = $def_handle; | |
my $handle; | |
# To be fork safe and thread safe, use a combination of the PID and TID (if | |
# running with use threads) to make sure no two processes/threads share | |
# handles. Implementation based on DBIx::Connector by David E. Wheeler. | |
my $pid_tid = $$; | |
$pid_tid .= '_' . threads->tid if $INC{'threads.pm'}; | |
# OK, see if we have a matching handle | |
$handle = $handles{$pid_tid}{$handle_key} || {}; | |
if( $handle->{rose} ){ | |
if( $handle->{rose}->dbh->{Active} && time - $handle->{last_connection_check} < 30 ){ | |
return $handle->{rose}; | |
} | |
else{ | |
if( _check_connection($handle->{rose}) ){ | |
$handle->{last_connection_check} = time; | |
return $handle->{rose}; | |
} | |
else{ | |
Dancer::Logger::debug( | |
"Database connection went away, reconnecting" | |
); | |
Dancer::Factory::Hook->instance->execute_hooks( | |
'database_connection_lost', $handle->{rose}->dbh | |
); | |
if( $handle->{rose} ) { eval { $handle->{rose}->dbh->disconnect } } | |
return $handle->{rose} = _get_connection(); | |
} | |
} | |
} | |
else{ | |
# Get a new connection | |
if ($handle->{rose} = _get_connection()) { | |
$handle->{last_connection_check} = time; | |
$handles{$pid_tid}{$handle_key} = $handle; | |
if (ref $handle_key && ref $handle_key ne ref $def_handle) { | |
# We were given a hashref of connection settings. Shove a | |
# reference to that hashref into the handle, so that the hashref | |
# doesn't go out of scope for the life of the handle. | |
# Otherwise, that area of memory could be re-used, and, given | |
# different DB settings in a hashref that just happens to have | |
# the same address, we'll happily hand back the original handle. | |
# See http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=665221 | |
# Thanks to Sam Kington for suggesting this fix :) | |
$handle->{_orig_settings_hashref} = $handle_key; | |
} | |
return $handle->{rose}; | |
} else { | |
return; | |
} | |
} | |
}; | |
Dancer::Factory::Hook->instance->install_hooks( | |
qw( | |
database_connected | |
database_connection_lost | |
database_connection_failed | |
database_error | |
) | |
); | |
register_plugin; | |
# Given the settings to use, try to get a database connection | |
sub _get_connection { | |
my $rose = Referdia::DB->new; | |
if( !$rose->dbh ){ | |
Dancer::Logger::error( | |
"Database connection failed - " . $rose->error | |
); | |
Dancer::Factory::Hook->instance->execute_hooks( | |
'database_connection_failed' | |
); | |
return; | |
} | |
Dancer::Logger::info('Database Connected'); | |
Dancer::Factory::Hook->instance->execute_hooks('database_connected', $rose); | |
return $rose; | |
} | |
# Check the connection is alive | |
sub _check_connection { | |
my $rose = shift; | |
return unless $rose; | |
if ($rose->dbh->{Active} && (my $result = $rose->dbh->ping)) { | |
if (int($result)) { | |
# DB driver itself claims all is OK, trust it: | |
return 1; | |
} else { | |
# It was "0 but true", meaning the default DBI ping implementation | |
# Implement our own basic check, by performing a real simple query. | |
my $ok; | |
eval { | |
$ok = $rose->dbh->do('select 1'); | |
}; | |
return $ok; | |
} | |
} else { | |
return; | |
} | |
} | |
1; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment