Skip to content

Commit 59fae36

Browse files
authored
Fix and test script timeout (#840)
* fix and test timeout for script execute
1 parent 91e85a8 commit 59fae36

File tree

4 files changed

+46
-13
lines changed

4 files changed

+46
-13
lines changed

src/execution/parsing/script_commands_parser.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,15 @@ static int _ScriptExecuteCommand_ParseCommand(RedisModuleCtx *ctx, RedisModuleSt
171171
}
172172

173173
while (argpos < argc) {
174-
const char *arg_string = RedisModule_StringPtrLen(argv[argpos], NULL);
174+
const char *arg_string = RedisModule_StringPtrLen(argv[argpos++], NULL);
175175
// Parse timeout arg if given and store it in timeout.
176176
if (!strcasecmp(arg_string, "TIMEOUT")) {
177-
argpos++;
178177
if (argpos >= argc) {
179178
RAI_SetError(error, RAI_ESCRIPTRUN,
180179
"ERR No value provided for TIMEOUT in AI.SCRIPTEXECUTE");
181180
return REDISMODULE_ERR;
182181
}
183-
if (ParseTimeout(argv[argpos], error, timeout) == REDISMODULE_ERR)
182+
if (ParseTimeout(argv[argpos++], error, timeout) == REDISMODULE_ERR)
184183
return REDISMODULE_ERR;
185184
// No other arguments expected after timeout.
186185
break;
@@ -192,7 +191,6 @@ static int _ScriptExecuteCommand_ParseCommand(RedisModuleCtx *ctx, RedisModuleSt
192191
"ERR Already Encountered KEYS scope in AI.SCRIPTEXECUTE command");
193192
return REDISMODULE_ERR;
194193
}
195-
argpos++;
196194
keysDone = true;
197195
if (_ScriptExecuteCommand_ParseKeys(ctx, argv, argc, &argpos, error, sctx) ==
198196
REDISMODULE_ERR) {
@@ -207,7 +205,6 @@ static int _ScriptExecuteCommand_ParseCommand(RedisModuleCtx *ctx, RedisModuleSt
207205
"ERR Already Encountered ARGS scope in AI.SCRIPTEXECUTE command");
208206
return REDISMODULE_ERR;
209207
}
210-
argpos++;
211208
argsDone = true;
212209
if (_ScriptExecuteCommand_ParseArgs(ctx, argv, argc, &argpos, error, sctx) ==
213210
REDISMODULE_ERR) {
@@ -223,7 +220,6 @@ static int _ScriptExecuteCommand_ParseCommand(RedisModuleCtx *ctx, RedisModuleSt
223220
"ERR Already Encountered INPUTS scope in AI.SCRIPTEXECUTE command");
224221
return REDISMODULE_ERR;
225222
}
226-
argpos++;
227223
inputsDone = true;
228224
if (_ScriptExecuteCommand_ParseInputs(ctx, argv, argc, &argpos, error, inputs) ==
229225
REDISMODULE_ERR) {
@@ -238,7 +234,6 @@ static int _ScriptExecuteCommand_ParseCommand(RedisModuleCtx *ctx, RedisModuleSt
238234
"ERR Already Encountered OUTPUTS scope in AI.SCRIPTEXECUTE command");
239235
return REDISMODULE_ERR;
240236
}
241-
argpos++;
242237
outputsDone = true;
243238
if (_ScriptExecuteCommand_ParseOutputs(ctx, argv, argc, &argpos, error, outputs) ==
244239
REDISMODULE_ERR) {

tests/flow/test_data/script.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,8 @@ def bar_variadic(tensors: List[Tensor], keys: List[str], args: List[str]):
77
a = tensors[0]
88
l = tensors[1:]
99
return a + l[0]
10+
11+
def long_func(tensors: List[Tensor], keys: List[str], args: List[str]):
12+
sum=0
13+
for i in range(10000000):
14+
sum+=1

tests/flow/tests_commands.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,17 @@ def test_pytorch_scriptexecute_errors(env):
296296

297297
check_error(env, con, 'AI.SCRIPTEXECUTE', 'ket{1}', 'bar', 'KEYS', 1 , '{1}', 'INPUTS', 'OUTPUTS')
298298

299-
check_error_message(env, con, "Invalid arguments provided to AI.SCRIPTEXECUTE", 'AI.SCRIPTEXECUTE', 'ket{1}', 'bar', 'KEYS', 1, '{1}', 'ARGS')
299+
check_error_message(env, con, "Invalid arguments provided to AI.SCRIPTEXECUTE",
300+
'AI.SCRIPTEXECUTE', 'ket{1}', 'bar', 'KEYS', 1, '{1}', 'ARGS')
300301

301-
check_error_message(env, con, "Invalid argument for inputs count in AI.SCRIPTEXECUTE", 'AI.SCRIPTEXECUTE', 'ket{1}', 'bar', 'INPUTS', 'OUTPUTS')
302+
check_error_message(env, con, "Invalid argument for inputs count in AI.SCRIPTEXECUTE",
303+
'AI.SCRIPTEXECUTE', 'ket{1}', 'bar', 'INPUTS', 'OUTPUTS')
302304

303-
check_error_message(env, con, "Invalid value for TIMEOUT",'AI.SCRIPTEXECUTE', 'ket{1}', 'bar', 'KEYS', 1, '{1}', 'INPUTS', 2, 'a{1}', 'b{1}', 'OUTPUTS', 1, 'c{1}', 'TIMEOUT', 'TIMEOUT')
305+
check_error_message(env, con, "Invalid value for TIMEOUT",
306+
'AI.SCRIPTEXECUTE', 'ket{1}', 'bar', 'INPUTS', 2, 'a{1}', 'b{1}', 'OUTPUTS', 1, 'c{1}', 'TIMEOUT', 'TIMEOUT')
304307

308+
check_error_message(env, con, "No value provided for TIMEOUT in AI.SCRIPTEXECUTE",
309+
'AI.SCRIPTEXECUTE', 'ket{1}', 'bar', 'INPUTS', 2, 'a{1}', 'b{1}', 'OUTPUTS', 1, 'c{1}', 'TIMEOUT')
305310

306311
if env.isCluster():
307312
# cross shard

tests/flow/tests_pytorch.py

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import redis
2+
import time
23

34
from includes import *
45
from RLTest import Env
@@ -389,13 +390,40 @@ def test_pytorch_scriptexecute_list_input(env):
389390
env.assertEqual(values2, values)
390391

391392

392-
def test_pytorch_scriptinfo(env):
393+
def test_pytorch_scriptexecute_with_timeout(env):
393394
if not TEST_PT:
394395
env.debugPrint("skipping {} since TEST_PT=0".format(sys._getframe().f_code.co_name), force=True)
395396
return
396397

397-
# env.debugPrint("skipping this tests for now", force=True)
398-
# return
398+
con = get_connection(env, '{$}')
399+
script = load_file_content('script.txt')
400+
ret = con.execute_command('AI.SCRIPTSTORE', 'my_script{$}', DEVICE,
401+
'ENTRY_POINTS', 2, 'bar', 'long_func', 'SOURCE', script)
402+
env.assertEqual(ret, b'OK')
403+
404+
con.execute_command('AI.TENSORSET', 'a{$}', 'FLOAT', 2, 2, 'VALUES', 2, 3, 2, 3)
405+
con.execute_command('AI.TENSORSET', 'b{$}', 'FLOAT', 2, 2, 'VALUES', 2, 3, 2, 3)
406+
407+
def run():
408+
con2 = get_connection(env, '{$}')
409+
con2.execute_command('AI.SCRIPTEXECUTE', 'my_script{$}', 'long_func', 'KEYS', 1, '{$}')
410+
411+
t = threading.Thread(target=run)
412+
t.start()
413+
414+
# make sure that we have a long operation that RedisAI will run upon sending the following
415+
# command, to assure that timeout will occur.
416+
time.sleep(0.1)
417+
ret = con.execute_command('AI.SCRIPTEXECUTE', 'my_script{$}', 'bar',
418+
'INPUTS', 2, 'a{$}', 'b{$}', 'OUTPUTS', 1, 'c{$}', 'TIMEOUT', 1)
419+
env.assertEqual(ret, b'TIMEDOUT')
420+
t.join()
421+
422+
423+
def test_pytorch_scriptinfo(env):
424+
if not TEST_PT:
425+
env.debugPrint("skipping {} since TEST_PT=0".format(sys._getframe().f_code.co_name), force=True)
426+
return
399427

400428
con = get_connection(env, '{1}')
401429

0 commit comments

Comments
 (0)