#
# (c) Jan Gehring <jan.gehring@gmail.com>
#
# vim: set ts=2 sw=2 tw=0:
# vim: set expandtab:
=head1 NAME
Rex::Transaction - Transaction support.
=head1 DESCRIPTION
With this module you can define transactions and rollback scenarios on failure.
=head1 SYNOPSIS
task "do-something", "server01", sub {
on_rollback {
rmdir "/tmp/mydata";
};
transaction {
mkdir "/tmp/mydata";
upload "files/myapp.tar.gz", "/tmp/mydata";
run "cd /tmp/mydata; tar xzf myapp.tar.gz";
if($? != 0) { die("Error extracting myapp.tar.gz"); }
};
};
=head1 EXPORTED FUNCTIONS
=over 4
=cut
package Rex::Transaction;
use strict;
use warnings;
our $VERSION = '0.57.0'; # VERSION
require Exporter;
use vars qw(@EXPORT @ROLLBACKS);
use base qw(Exporter);
use Rex::Logger;
use Rex::TaskList;
use Data::Dumper;
@EXPORT = qw(transaction on_rollback);
=item transaction($codeRef)
Start a transaction for $codeRef. If $codeRef dies it will rollback the transaction.
task "deploy", group => "frontend", sub {
on_rollback {
rmdir "...";
};
deploy "myapp.tar.gz";
};
task "restart_server", group => "frontend", sub {
run "/etc/init.d/apache2 restart";
};
task "all", group => "frontend", sub {
transaction {
do_task [qw/deploy restart_server/];
};
};
=cut
sub transaction(&) {
my ($code) = @_;
my $ret = 1;
Rex::Logger::debug("Cleaning ROLLBACKS array");
@ROLLBACKS = ();
Rex::TaskList->create()->set_in_transaction(1);
eval { &$code(); };
if ($@) {
Rex::Logger::info("Transaction failed. Rolling back.");
$ret = 0;
for my $rollback_code ( reverse @ROLLBACKS ) {
# push the connection of the task back
Rex::push_connection( $rollback_code->{"connection"} );
# run the rollback code
&{ $rollback_code->{"code"} }();
# and pop it away
Rex::pop_connection();
}
die("Transaction failed. Rollback done.");
}
Rex::TaskList->create()->set_in_transaction(0);
return $ret;
}
=item on_rollback($codeRef)
This code will be executed if one step in the transaction fails.
See I<transaction>.
=cut
sub on_rollback(&) {
my ($code) = @_;
push(
@ROLLBACKS,
{
code => $code,
connection => Rex::get_current_connection()
}
);
}
=back
=cut
1;