В документации для транзакций говорится:
"мы можем отказаться и окончательно удалить транзакции" и "все, что вы может сделать с транзакцией Redis, вы также можете сделать с script"
http://redis.io/topics/transactions
Но не так ли? Я вижу проблему с этим.
В рамках транзакции вы можете WATCH несколько переменных, прочитать эти переменные и на основе уникального состояния этих переменных вы можете сделать совершенно другой набор записей до вызова EXEC. Если что-то мешает состоянию этих переменных за прошедшее время, EXEC не будет выполнять транзакцию. (Это позволяет вам повторить попытку. Это совершенная система транзакций.)
EVAL script не позволит вам это сделать. Согласно документации на этой странице:
"Скрипты как чистые функции... script всегда оценивает то же самое Redis записывает команды с теми же аргументами, что и те же входные данные задавать. Операции, выполняемые script, не могут зависеть от каких-либо скрытых (неявная) информация или состояние, которое может меняться как scriptисполнения или между различными исполнениями script, а также может ли он зависеть от любого внешнего входа от устройств ввода/вывода".
Проблема, которую я вижу с EVAL, заключается в том, что вы не можете получить состояние этих переменных внутри script и создать уникальный набор записей, основанных на состоянии этих переменных. Опять же: "script всегда оценивает те же команды записи Redis с теми же аргументами, что и тот же набор входных данных". Таким образом, полученные записи уже определены (кэшируются с первого запуска), а EVAL script не волнует, какие значения GET находятся внутри script. Единственное, что вы можете сделать, это выполнить GET для этих переменных перед вызовом EVAL, а затем передать эти переменные в EVAL script, но вот проблема: теперь у вас есть проблема атомарности между вызовом GET и вызовом EVAL.
Другими словами, все переменные, которые вы бы сделали WATCH для транзакции, в случае EVAL вам вместо этого нужно ПОЛУЧИТЬ эти переменные, а затем передать их в EVAL script. Поскольку атомный характер script не гарантируется до тех пор, пока фактически не запустится script, и вам нужно ПОЛУЧИТЬ эти переменные перед вызовом EVAL для запуска script, который оставляет открытие, где состояние этих переменных может измениться между GET и передачей их EVAL. Поэтому гарантия атомарности, которую у вас есть с WATCH, у вас нет с EVAL для очень важного набора вариантов использования.
Так почему же говорят об отказе от транзакций, когда это может привести к потере важной функциональности Redis? Или есть ли способ сделать это с помощью сценариев EVAL, которые я пока не понимаю? Или запланированы ли функции, которые могут решить это для EVAL? (Гипотетический пример: если они сделали WATCH работать с EVAL так же, как WATCH работает с EXEC, это может сработать.)
Есть ли решение? Или я должен понять, что Redis не может быть полностью безопасным в долгосрочной перспективе?