summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Gaya <nicholasgaya+github@gmail.com>2020-03-05 01:33:55 -0800
committerAndy McCurdy <andy@andymccurdy.com>2020-03-10 17:10:04 -0700
commit07fec7e18996b6b3b4f30ec9636b88c9b287ece5 (patch)
tree8fea4af74c1aba7cd6260cb4eb62ed35948e9e64
parent81d76657385fc81548e5eaca4781c0e6b214ea16 (diff)
downloadredis-py-07fec7e18996b6b3b4f30ec9636b88c9b287ece5.tar.gz
Don't send DISCARD after ExecAbortError in pipeline
The `EXECABORT` error type was added in Redis 2.6.5 and is returned from an `EXEC` command to indicate that the transaction was aborted due to an invalid command. It is not necessary to call `DISCARD` after this error, and doing so causes a "DISCARD without MULTI" error.
-rw-r--r--CHANGES2
-rwxr-xr-xredis/client.py2
-rw-r--r--tests/test_pipeline.py15
3 files changed, 17 insertions, 2 deletions
diff --git a/CHANGES b/CHANGES
index 6d3cec6..1eff175 100644
--- a/CHANGES
+++ b/CHANGES
@@ -16,6 +16,8 @@
during command packing. Thanks @Cody-G. #1265, #1285
* HSET command now can accept multiple pairs. HMSET has been marked as
deprecated now. Thanks to @laixintao #1271
+ * Don't manually DISCARD when encountering an ExecAbortError.
+ Thanks @nickgaya, #1300/#1301
* 3.4.1
* Move the username argument in the Redis and Connection classes to the
end of the argument list. This helps those poor souls that specify all
diff --git a/redis/client.py b/redis/client.py
index 10ba979..19707b2 100755
--- a/redis/client.py
+++ b/redis/client.py
@@ -3898,8 +3898,6 @@ class Pipeline(Redis):
try:
response = self.parse_response(connection, '_')
except ExecAbortError:
- if self.explicit_transaction:
- self.immediate_execute_command('DISCARD')
if errors:
raise errors[0][1]
raise sys.exc_info()[1]
diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py
index 828b989..088071b 100644
--- a/tests/test_pipeline.py
+++ b/tests/test_pipeline.py
@@ -172,6 +172,21 @@ class TestPipeline(object):
assert pipe.set('z', 'zzz').execute() == [True]
assert r['z'] == b'zzz'
+ def test_parse_error_raised_transaction(self, r):
+ with r.pipeline() as pipe:
+ pipe.multi()
+ # the zrem is invalid because we don't pass any keys to it
+ pipe.set('a', 1).zrem('b').set('b', 2)
+ with pytest.raises(redis.ResponseError) as ex:
+ pipe.execute()
+
+ assert unicode(ex.value).startswith('Command # 2 (ZREM b) of '
+ 'pipeline caused error: ')
+
+ # make sure the pipe was restored to a working state
+ assert pipe.set('z', 'zzz').execute() == [True]
+ assert r['z'] == b'zzz'
+
def test_watch_succeed(self, r):
r['a'] = 1
r['b'] = 2