Идемпотентность роли проверяют так: прогнал, прогнал ещё раз, во второй раз ноль изменений — значит роль не дёргает сервер попусту. Стандартный приём, я им пользуюсь всегда.
И он меня обманул.
Прогоняю приёмку, первый прогон за день — одно изменение. Задача, создающая каталог для выгрузки. Прогоняю ещё дважды подряд — ноль и ноль. По книжке всё чисто. Но одно изменение в первом прогоне никуда не делось, и объяснить его я не мог.
Оказалось, роль была идемпотентна двадцать три часа в сутки.
Ночью отрабатывает задача выгрузки. Она сносит каталог целиком — иначе выгрузка удалённого сценария осталась бы лежать в нём навсегда и воскресла бы при восстановлении. Потом создаёт его заново одной командой сразу с двумя вложенными каталогами. И вот здесь собака: владелец и права, указанные ключами команды, применяются к тем каталогам, что названы явно. Родительский создаётся попутно — и достаётся ему то, что даст маска по умолчанию.
То есть каждую ночь каталог менял владельца, а первый прогон роли после этого возвращал его назад. Двадцать три часа роль идеально идемпотентна, а если запустить её в нужный момент — нет.
Починка на одну строку: создавать родителя отдельной командой, явно. Интереснее способ проверки. Двумя прогонами подряд этот дефект не ловится никогда — надо прогнать ровно после той задачи, которая уводит состояние. Что я и сделал: запустил выгрузку руками, сразу следом роль — ноль изменений, все три каталога с нужными правами.
Забираю правило: «дважды подряд — ноль» проверяет только то, что роль не спорит сама с собой. Она может спорить с чем-то ещё, что живёт по своему расписанию.