)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"ac13eb6cf85518cc10a6051d7e674a14f1816216","unresolved":true,"context_lines":[{"line_number":7,"context_line":"redis: Read groups without WATCH"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"get_members(), get_members_with_capabilities() and"},{"line_number":10,"context_line":"get_member_capabilities() read a group inside a WATCH transaction. Any"},{"line_number":11,"context_line":"join, leave or removal of an expired member before EXEC aborts the"},{"line_number":12,"context_line":"transaction, and the whole read starts again, without limit. The number"},{"line_number":13,"context_line":"of attempts grows exponentially with the write rate and the time a read"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"f51e56dd_df29973d","line":10,"range":{"start_line":10,"start_character":48,"end_line":10,"end_character":53},"updated":"2026-10-11 18:18:52.000000000","message":"Do you mind pointing the place where watch transaction is exactly started ? Looking at the code I see it starts transition when purging the expired keys but no explicit watch call is found. Or are you pointing something different here ?","commit_id":"651facc193909c8df4abc28d41a8410bd76bb89f"},{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"00b27f44b31afefc6d5951fa8d584ed61f4527ba","unresolved":false,"context_lines":[{"line_number":7,"context_line":"redis: Read groups without WATCH"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"get_members(), get_members_with_capabilities() and"},{"line_number":10,"context_line":"get_member_capabilities() read a group inside a WATCH transaction. Any"},{"line_number":11,"context_line":"join, leave or removal of an expired member before EXEC aborts the"},{"line_number":12,"context_line":"transaction, and the whole read starts again, without limit. The number"},{"line_number":13,"context_line":"of attempts grows exponentially with the write rate and the time a read"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"3959b275_332bde45","line":10,"range":{"start_line":10,"start_character":48,"end_line":10,"end_character":53},"in_reply_to":"4eb20866_16786441","updated":"2026-10-12 03:53:18.000000000","message":"OK thanks. I failed to catch that pipe call in my grep...","commit_id":"651facc193909c8df4abc28d41a8410bd76bb89f"},{"author":{"_account_id":10273,"name":"Adam Harwell","email":"flux.adam@gmail.com","username":"rm_you"},"change_message_id":"b04b4cf23b6b2ca442f6f0452addf5c44394d4f3","unresolved":true,"context_lines":[{"line_number":7,"context_line":"redis: Read groups without WATCH"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"get_members(), get_members_with_capabilities() and"},{"line_number":10,"context_line":"get_member_capabilities() read a group inside a WATCH transaction. Any"},{"line_number":11,"context_line":"join, leave or removal of an expired member before EXEC aborts the"},{"line_number":12,"context_line":"transaction, and the whole read starts again, without limit. The number"},{"line_number":13,"context_line":"of attempts grows exponentially with the write rate and the time a read"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"4eb20866_16786441","line":10,"range":{"start_line":10,"start_character":48,"end_line":10,"end_character":53},"in_reply_to":"f51e56dd_df29973d","updated":"2026-10-11 20:08:17.000000000","message":"`Redis.transaction()` calls `pipe.watch(encoded_group)` before the callback, then `pipe.execute()` afterward. That still sends `MULTI/EXEC` when no writes were queued. Clarified in PS4; real Redis traces on redis-py 6 and 8 confirm the retries.","commit_id":"651facc193909c8df4abc28d41a8410bd76bb89f"}],"tooz/drivers/redis.py":[{"author":{"_account_id":9816,"name":"Takashi Kajinami","email":"kajinamit@oss.nttdata.com","username":"kajinamit"},"change_message_id":"ac13eb6cf85518cc10a6051d7e674a14f1816216","unresolved":true,"context_lines":[{"line_number":799,"context_line":"            keys.extend(self._encode_beat_id(m) for m in batch)"},{"line_number":800,"context_line":"            try:"},{"line_number":801,"context_line":"                script(keys\u003dkeys, args\u003dbatch)"},{"line_number":802,"context_line":"            except exceptions.RedisError as e:"},{"line_number":803,"context_line":"                LOG.warning("},{"line_number":804,"context_line":"                    \"Unable to remove expired members from group \u0027%s\u0027: %s\","},{"line_number":805,"context_line":"                    encoded_group.decode(\u0027utf-8\u0027, errors\u003d\u0027replace\u0027),"}],"source_content_type":"text/x-python","patch_set":2,"id":"8d56793e_a7b2b329","line":802,"range":{"start_line":802,"start_character":12,"end_line":802,"end_character":46},"updated":"2026-10-11 18:18:52.000000000","message":"I wonder if we can use a more narrowed catch here ? This is actually a behavior change and redis driver leaves member keys when these could not be deleted for some reason.","commit_id":"651facc193909c8df4abc28d41a8410bd76bb89f"},{"author":{"_account_id":10273,"name":"Adam Harwell","email":"flux.adam@gmail.com","username":"rm_you"},"change_message_id":"b04b4cf23b6b2ca442f6f0452addf5c44394d4f3","unresolved":true,"context_lines":[{"line_number":799,"context_line":"            keys.extend(self._encode_beat_id(m) for m in batch)"},{"line_number":800,"context_line":"            try:"},{"line_number":801,"context_line":"                script(keys\u003dkeys, args\u003dbatch)"},{"line_number":802,"context_line":"            except exceptions.RedisError as e:"},{"line_number":803,"context_line":"                LOG.warning("},{"line_number":804,"context_line":"                    \"Unable to remove expired members from group \u0027%s\u0027: %s\","},{"line_number":805,"context_line":"                    encoded_group.decode(\u0027utf-8\u0027, errors\u003d\u0027replace\u0027),"}],"source_content_type":"text/x-python","patch_set":2,"id":"44e61090_bfd5c7cf","line":802,"range":{"start_line":802,"start_character":12,"end_line":802,"end_character":46},"in_reply_to":"8d56793e_a7b2b329","updated":"2026-10-11 20:08:17.000000000","message":"Agreed. Removed the catch in PS4 so pruning failures reach callers through the existing error translation. Added regression coverage for both group-read methods and verified real Redis permission errors and READONLY recovery.","commit_id":"651facc193909c8df4abc28d41a8410bd76bb89f"}]}
