As documented, the EVAL command is guaranteed to be executed atomically, however I am not able to find a similar assertion about Redis Modules, specifically lets say I write a Redis module that is a port of some lua script, I am not calling any other third party libraries or creating my own data type.
Does redis guarantee that if for instance if one of the commands that I execute in my module fails, the previous commands will be "unrolled" or not "persisted" ? or the idea is that the module itself must be able to return to the original database state in the case one of the calls fails for any reason?
Comment From: manast
I found this other question btw. https://github.com/redis/redis/issues/3613 However it makes me kind of confused. This is assuming a command cannot fail in the middle of its operation, however most calls to the Redis api return error codes, they may succeed or fail, so in theory my first three calls to redis apis in my command while the fourth could fail, then the command call should exit with an error but the state of the database would not be the same as if the command had not been executed at all since 3 calls did indeed succeed. A clarification would be greatly appreciated.
Comment From: itamarhaber
Hello @manast
It is up to the module's author to ensure whatever guarantees (atomiticity, persistance and/or replication) for each of the module's commands. I'm afraid there is no generic answer as it is up to the module's implemementation.
Comment From: manast
@itamarhaber so you mean that lua scripts have stronger guarantees that an equivalent module that does exactly the same? if this is the case I expect to be clearly stated in the documentation in order to avoid confusion. I still find difficult to believe it, what is the point of opening keys for example if not for telling redis which data is going to be modified during the command execution?
Comment From: manast
Ok, after some digging in some other mailing lists I kind of found the answer to my question. Lua script is only atomic in the sense that the execution is only persisted if the script completes. Modules should be the same, however the possible ways a module could fail are more explicit since a memory allocation could fail in the middle of the module execution making the command fail but still could have changed the dataset, since neither rollback mechanism nor MCVV exists in Redis.
Comment From: oranagra
@manast please note that when memory allocation fails, redis panics and dies (will recover from persistence or replication).
when a script calls a redis command it uses either redis.call or redis.pcall, the later will let the script a chance to rollback or do anything it likes rather than exit with failure leaving part of the changes, modules can do the same.
In general, if a module just uses RM_Call, RM_OpenKey and such, and even has it's own type (RM_CreateDataType) it should be similar to Lua scripts with regards to these guarantees (assuming it doesn't have any bugs and remembered to call RM_Replicate and such).
However, keep in mind that modules can do funny things too, like blocking clients, creating threads and doing all sorts of things in the background, in which case i can't tell what are their guarantees.
Comment From: manast
@oranagra so lets say I call this function:
int RedisModule_HashGet(RedisModuleKey *key, int flags, ...);
Although not documented I am assuming the int can be a REDISMODULE_OK or REDISMODULE_ERR. If error what should I do? unroll all the redis commands that where executed properly? or maybe it is impossible that this method returns anything else other than OK?
Comment From: oranagra
it is documented:
* The function returns REDISMODULE_OK on success and REDISMODULE_ERR if
* the key is not an hash value.
so for instance, you can open all the input keys and perform validations on their existence and type before making any modifications. this way you can probably be sure that if the module command you implemented fails and responds with an error, no changes were made.
Comment From: manast
ok, I get it. So basically we can say that if the preconditions are met, all the commands returning REDISMODULE_OK| REDISMODULE_ERR will always succeed, and if a memory allocation fails, for example while creating a new string, redis will just crash completely.
Comment From: oranagra
yes.. this is how the built in commands of redis are implemented too.