クイックフィックス (TL;DR)
EXECABORTは、クラッシュ前にRedisがブレーキをかけている状態だと考えてください。このエラーは、MULTIブロック内で不正なコマンドをキューに入れようとしたために発生します。Redisはトランザクションを「汚い(dirty)」ものとしてマークし、最終的にEXECを実行しようとしたときにすべてを拒否します。
すぐに解決するためのチェックポイント:
MULTIとEXECの間に入力したコマンドにタイポや引数の不足がないか確認してください。- サーバーが
maxmemory制限(OOM)に達していないか確認してください。 - 実際に
exec()呼び出しが送信される前にスローされた例外がないか、アプリケーションログを確認してください。
EXECABORTエラーの解読
Redisは間違いを2つの異なる方法で処理します。デバッグにはその違いを理解することが重要です。
- キューイングエラー (EXECABORT): コマンドをリストに追加している最中に発生します。コマンド名の打ち間違いや、引数が4つ必要なところに3つしか指定しなかった場合、Redisは早い段階でそれを検知します。バージョン2.6.5以降、サーバーはこの失敗を記憶し、データを保護するためにバッチ全体を中止(アボート)します。
- 実行エラー:
EXECを呼び出した後にのみ発生します。例えば、リストを保持しているキーに対してINCRを実行しようとした場合などがこれに当たります。このシナリオでは、Redisは単一の失敗に関わらず、トランザクション内の他のすべてのコマンドを実行します。
EXECABORTが表示される場合、キューイングの失敗に対処していることになります。Redisは、部分的に破損したスクリプトの実行を拒否することで安全策をとっています。
よくある原因と解決策
シナリオ1:単純な構文ミス
10回中9回は、単純なタイポが原因です。引数の数が間違っている場合、RedisはMULTIフェーズ中に即座に不一致を特定します。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> SET user:100 "John"
QUEUED
127.0.0.1:6379(TX)> HSET user:101 field1 # エラー:実際の値が不足しています
(error) ERR wrong number of arguments for 'hset' command
127.0.0.1:6379(TX)> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
解決策: コマンドのシグネチャを再確認してください。redis-pyやioredisのようなクライアントライブラリを使用している場合は、文字列が期待される場所にnullやundefinedを渡していないか、ロジックを確認してください。
シナリオ2:メモリ上限(OOM)への到達
Redisインスタンスにmaxmemory制限(例:512MB)があり、現在511.9MB使用している場合、書き込みコマンドが失敗することがあります。サーバーがいっぱいであるためにMULTIブロック内で書き込みが失敗すると、トランザクション全体が停止します。
解決策: INFO memoryを実行して現在の使用量を確認してください。used_memory_humanがmaxmemoryに迫っている場合は、以下の3つの選択肢があります。
redis.confのmaxmemoryを増やす。allkeys-lruのような積極的なエビクション(追い出し)ポリシーに切り替える。- 古いキーや期限切れのデータを手動で削除して、スペースを解放する。
シナリオ3:存在しないコマンド
存在しないコマンドや、現在のRedisバージョンで利用できないコマンドを使用すると、即座にキューイングエラーが発生します。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> GSET mykey "value" # タイポ:SETのつもりだった
(error) ERR unknown command 'GSET'
127.0.0.1:6379(TX)> EXEC
(error) EXECABORT Transaction discarded because of previous errors.
解決策: スペルを確認してください。これは、Redis 7.xから古い環境(古いAWS ElastiCacheインスタンスなど)に移行し、ストリーム(XADD)などの新しい機能がまだ存在しない場合によく発生します。
WATCHの役割
キーが変更された場合にWATCHは通常(nil)レスポンスを返しますが、これらのブロックと連動して動作します。構文エラーとWATCHの失敗が同時に発生した場合、EXECABORTが優先されます。そもそもキューが有効ではなかったため、Redisは監視対象のキーが変更されたかどうかを確認することさえしません。
修正されたことを確認する方法
Redis CLIで簡単な手動テストを行い、ロジックを検証してください。正常なトランザクションは、以下のようにQUEUEDレスポンスがきれいに並ぶはずです。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> SET health_check "up"
QUEUED
127.0.0.1:6379(TX)> INCR total_requests
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) (integer) 1
結果のリストが表示されれば問題ありません。本番環境でエラーが続く場合は、/var/log/redis/redis-server.logのシステムログを確認してください。まれに、バックグラウンド保存(RDB)の失敗やディスクの問題により、Redisが書き込みコマンドを拒否し、トランザクションを中止することもあります。

