-
Notifications
You must be signed in to change notification settings - Fork 24.4k
Function Flags support (no-writes, no-cluster, allow-state, allow-oom) #10066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Function Flags support (no-writes, no-cluster, allow-state, allow-oom) #10066
Conversation
Following the discussion on redis#10025 Added the option to specify the parameters to `redis.register_function` as named arguments, example: ``` redis.register_function{ function_name='f1', callback=function() return 'hello' end, description='some desc' } ``` The possisional arguments is also kept, which means that it still possible to write the same example like this: ``` redis.register_function('f1', function() return 'hello' end, 'some desc') ``` As with positional arguments, the `function_name` and `callback` is mandatory and an error will be raise if those are missing. Also, an error will be raise if an unknown argument name is given or the arguments type is wrong. Tests was added to verify the new syntax.
Use a struct to hold register_function arguments instead of adding each argument as out parameter by itself. This will allow us to add more named arguments easily in the future.
Following the discussion on redis#10025 added functions flags support. Flags are give to Redis when the engine calls `functionLibCreateFunction`, supported flags are: * write - the function is performing write operation on the key space do not allow executing the function on the following conditions: * On readonly replica * Using fcall_ro * If disc error detected and In addition, if this flag is not set, any attempt to execute a write command from within the function will result in an error. * deny-oom - any attempt to execute the function will result in an error if OOM is reached. * allow-stale - indicate that it is ok to run this function on stale replica * no-cluster - any attempt to execute the function will result in an error on cluster enabled server. ## Lua API On Lua engine, it is possible to give functions flags in 2 ways: * Third argument to positional arguments (notice that the description arugment moved to fourth position compared to unstable): ``` redis.register_function('f1', function() return 1 end, {'write', 'deny-oom'}) ``` * using `flags` named argument: ``` redis.register_function{function_name='f1', callback=function() return 1 end, flags={'write', 'deny-oom'}} ``` The following will result in an error: * Unknown flag * Wrong flag type Default behaviure is the same as if no flags are used. Tests were added to verify all flags functionality
Verify that we are not executing commands on stale replica inside a scripts unless the command is marked with CMD_STALE flag. This verification allows us to set CMD_STALE on EVAL, EVALSHA, EVAL_RO and EVALSHA_RO and in the wrost case, if the script will try to perform a command which is not allow while stale, an error will be raise. On functions, we also enforce this stale verification. The difference from eval is that function can leverage functions flags to allow earily exit on stale state.
1. Better error messages 2. Indentation fixes
|
@redis/core-team please approve or comment |
|
This was discussed in a core-team meeting and got an approval to be merge. |
|
If we agree on the last open conversations I do not see a reason why not to merge it. |
|
@MeirShpilraien @oranagra I have one concern about usability here. This means that as a function developer, I need to learn about flags and always explicitly specify them. Ideally I think functions should be Since flags become optional, this also implies they need to be an optional last argument (swap with description) or possibly even available only in the named form to allow additional mandatory args in the future. |
|
@yossigo i'm afraid that negating the flags can cause some confusion (and maybe bugs), since they'll be different than modules commands and redis native commands. regarding optional, both flags and description are optional, and it's not very hard to skip one of them (just use |
|
For the record I'm also for negating the flags, ie:
|
|
@oranagra But they're not really optional, because most functions need |
|
Summery discussion with @yossigo @oranagra @guybe7 FunctionsUser experience should be smooth even at the cost of not matching functions flags to modules and commands flags. To achieve this we believe that the default behaviour for functions should be:
Flags purpose is to allow users to change this default behaviour, We will change the flags as follow:
We will also change Eval ScriptsIn addition, an idea was raise to allow setting such flags for Another example, setting empty flags on eval script will change the behaviour to be the default behaviour as describe above. So setting empty flags will allow the user to indicate that the script should not be invoke if OOM reached (unlike today where it is possible to run scripts if OOM reached): This idea will allow having the same flags capabilities on eval scripts as we define it on function while still keep backward comparability. Notice that this idea allows solving this issue #8478 on eval scripts and that we need to consider how combine it with #10093 (in addition or as a replacement?). |
|
@MeirShpilraien Last comment LGTM. |
1. Change `write` flag to `no-writes` 2. Change `deny-oom` to `allow-oom` 3. flags and discription can only be given as named arguments.
Co-authored-by: Oran Agra <oran@redislabs.com>
Set server.script_oom to 0 anyway, if we will find out the we are out of memory, it will be set to 1.
When `allow-oom` is set, allow running any command even those which set with CMD_DENYOOM flag.
|
@oranagra @yoav-steinberg @yossigo and I had a discussion about the
We believe that option 3 is the best for the following reason:
Code and top comment was updated accordingly. |
Extra verification on `allow-omm` test.
Only set server.script_oom = 0 if no script timedout. Set it also on fcall_ro to not allow running scripts on OOM even with fcall_ro. Test was added to verify it.
1. rename FUNCTION_FLAG_* to SCRIPT_FLAG_* and moved it to script unit so later on it could also be consumed by eval scripts. 2. Avoid using `setDeferredSetLen` 3. Checked `server.maxmemory` when checking if its OK to run a function on OOM conditions.
The redis version is provided from within a script using: 1. redis.REDIS_VERSION - string representation of the redis version in the format of MAJOR.MINOR.PATH 2. redis.REDIS_VERSION_NUM - number representation of the redis version in the format of 0x00MMmmpp MM - major version mm - minor version PP - patch version The number version can be used to check if version is greater or less another version. The string version can be used to return to the user or print as logs.
Fixes cluster test introduced in redis#10066. ``` Function no-cluster flag: ERR Error registering functions: @user_function: 1: wrong number of arguments to redis.register_function ```
Fixes cluster test introduced in #10066. ``` Function no-cluster flag: ERR Error registering functions: @user_function: 1: wrong number of arguments to redis.register_function ```
Redis Functions Flags
Following the discussion on #10025 Added Functions Flags support. The PR is divided to 2 sections:
redis.register_functionAPI.redis.register_functionnamed argument supportThe first part of the PR adds support for named argument on
redis.register_function, example:The positional arguments is also kept, which means that it still possible to write:
But notice that it is no longer possible to pass the optional description argument on the positional argument version. Positional argument was change to allow passing only the mandatory arguments (function name and callback). To pass more arguments the user must use the named argument version.
As with positional arguments, the
function_nameandcallbackis mandatory and an error will be raise if those are missing. Also, an error will be raise if an unknown argument name is given or the arguments type is wrong.Tests was added to verify the new syntax.
Functions Flags
The second part of the PR is adding functions flags support. Flags are given to Redis when the engine calls
functionLibCreateFunction, supported flags are:no-writes- indicating the function perform no writes which means that it is OK to run it on:It will not be possible to run a function in those situations unless the function turns on the
no-writesflagallow-oom- indicate that its OK to run the function even if Redis is in OOM state, if the function will not turn on this flag it will not be possible to run it if OOM reached. If this flag is set, any command will be allow on OOM (even those that is marked with CMD_DENYOOM). The assumption is that this flag is for advance users that knows its meaning and understand what they are doing, and Redis trust them to not increase the memory usage. (e.g. it could be an INCR or a modification on an existing key, or a DEL command)Note: starting with redis 7.0.1, the
no-writesflag also impliesallow-oom, so read-only scripts (including ones used by FCALL_RO and EVAL_RO) can run in OOM state without explicitly specifying this flag. see Scripts that declare theno-writesflag are implicitlyallow-oomtoo. #10699allow-state- indicate that its OK to run the function on stale replica, in this case we will also make sure the function is only performstalecommands and raise an error if not.no-cluster- indicate to disallow running the function if cluster is enabled.Default behaviure of functions (if no flags is given):
Lua API for functions flags
On Lua engine, it is possible to give functions flags as
flagsnamed argument:The function flags argument must be a Lua table that contains all the requested flags, The following will result in an error:
Default behaviour is the same as if no flags are used.
Tests were added to verify all flags functionality
Additional changes
allow-staleflag.CMD_STALEonscriptCall(redis.call), so it will not be possible to call commands from script while stale unless the command is marked with theCMD_STALEflags. so that even if the function is allowed while stale we do not allow it to bypass theCMD_STALEflag of commands.FUNCTION LISTcommand to provide the set of flags for each function:Added API to get Redis version from within a script, The redis version can be provided using:
redis.REDIS_VERSION- string representation of the redis version in the format of MAJOR.MINOR.PATHredis.REDIS_VERSION_NUM- number representation of the redis version in the format of0x00MMmmpp(MM- major,mm- minor,pp- patch). The number version can be used to check if version is greater or less another version. The string version can be used to return to the user or print as logs.This new API is provided to eval scripts and functions, it also possible to use this API during functions loading phase.
Considerations
todo:
EVAL\_RO,EVALSHA\_ROto be allowed while stale and in worst case, if the script performs a command which is not allowed while stale, an error will be raised.writecommands.function list