Permalink
Browse files

Better support for transactions

"Better" in that we can collect unthrown errors for commands which yield
error responses when executed.
  • Loading branch information...
1 parent 11ed728 commit 18a81d8ea2be8b76de3c9187dae76d9b21553089 @arc committed Mar 4, 2012
Showing with 54 additions and 0 deletions.
  1. +39 −0 lib/Redis.pm
  2. +15 −0 t/04-pipeline.t
View
@@ -367,6 +367,15 @@ sub pipeline {
return wantarray ? @responses : \@responses;
}
+sub txn_exec {
+ my ($self) = @_;
+
+ my ($responses) = $self->pipeline(sub { $self->exec });
+ confess $$responses # failure in EXEC, not in queued commands
+ if ref $responses ne 'ARRAY';
+ return wantarray ? @$responses : $responses;
+}
+
### PubSub
sub wait_for_messages {
@@ -745,6 +754,36 @@ If you try to use C<pipeline> from within a pipeline block, an exception is
thrown.
+=head1 Transactions
+
+Redis supports L<transactions|http://redis.io/topics/transactions> in the
+form of the C<MULTI>, C<DISCARD>, and C<EXEC> commands (as well as C<WATCH>
+and C<UNWATCH>). You can use those in the obvious way:
+
+ $r->multi;
+ $r->get('clunk');
+ $r->get('eth');
+ my ($clunk, $eth) = $r->exec;
+
+However, if any of the queued commands happen to yield an error status when
+the Redis server executes them, then an exception is thrown. If you need to
+be able to access responses to subsequent commands in that situation, use
+C<txn_exec>; it returns error status as instances of C<Redis::X::Unthrown>,
+as with C<pipeline>.
+
+ $r->multi;
+ $r->set(clunk => 'eth');
+ $r->rpush(clunk => 'oops');
+ my @responses = $r->txn_exec;
+ # $responses[0] is 'OK'
+ # $responses[1] is a Redis::X::Unthrown containing a wrong-type error
+
+Note that syntax errors in the transaction-protected commands still throw
+exceptions; only the C<txn_exec> method suppresses the exceptions.
+
+Calling C<txn_exec> without doing C<multi> first will throw an exception.
+
+
=head1 Connection Handling
=head2 quit
View
@@ -70,6 +70,21 @@ throws_ok { $r->pipeline(sub { $r->pipeline(sub {}) }) }
qr/Nested pipelines are forbidden/,
'no nested pipelines';
+subtest 'txn_exec' => sub {
+ is($r->multi, 'OK', 'start MULTI');
+ is($r->set(clunk => 'eth'), 'QUEUED', 'txn command 1 queued');
+ is($r->rpush(clunk => 'oops'), 'QUEUED', 'txn command 2 queued');
+ is($r->get('clunk'), 'QUEUED', 'txn command 3 queued');
+ is_deeply([$r->txn_exec], [
+ 'OK',
+ unthrown('ERR Operation against a key holding the wrong kind of value'),
+ 'eth',
+ ], 'correct responses, including unthrown error');
+};
+
+throws_ok { $r->txn_exec } qr/ERR EXEC without MULTI/,
+ 'txn_exec correctly detects error in its EXEC';
+
done_testing();
sub placeholder {

0 comments on commit 18a81d8

Please sign in to comment.