-
Notifications
You must be signed in to change notification settings - Fork 35
Description
Tarantool raises an error Transaction is active at return from function when a called over iproto function leaves an open transaction, but doesn't throw an error. This is the desired behavior, as it was discussed in tarantool/tarantool#7288. On the other hand, if the function raises an error, this error is returned to the user "as is".
vshard.storage.call calls the user function under a pcall, which means that if a user function raises an error, this error is not thrown out of vshard.storage.call. So if a user function throws an error before closing a transaction, the transaction will remain open and at the same time vshard.storage.call will catch this error, which will cause tarantool to raise Transaction is active at return from function instead.
Effectively, the original error will be hidden from the user and replaced with something else, without any traces of the original error location.
Example: apply the following diff to storage.lua in example cluster:
diff --git a/example/storage.lua b/example/storage.lua
index 05e5ef3..e76680e 100755
--- a/example/storage.lua
+++ b/example/storage.lua
@@ -119,9 +119,13 @@ function sleep(time)
end
function raise_luajit_error()
+ box.begin()
assert(1 == 2)
+ box.commit()
end
function raise_client_error()
+ box.begin()
box.error(box.error.UNKNOWN)
+ box.commit()
endNow try to call any of these functions from a router. The original error message will be replaced with Transaction is active at return from function:
unix/:./data/router_1.control> vshard.router.callrw(1, 'raise_client_error')
---
- null
- code: 30
base_type: ClientError
type: ClientError
message: Transaction is active at return from function
trace:
- file: src/box/iproto.cc
line: 2371
...
This is reproduced on vshard 0.1.37 and Tarantool 2.11.8, Tarantool 3.x isn't affected, at least I couldn't find a way to trigger the same error easily. This must be because of the way functions are called on 3.x compared to 2.x:
vshard/vshard/storage/init.lua
Lines 262 to 287 in 60ae7bb
| -- | |
| -- Invoke a function on this instance. Arguments are unpacked into the function | |
| -- as arguments. | |
| -- The function returns pcall() as is, because is used from places where | |
| -- exceptions are not allowed. | |
| -- | |
| local local_call | |
| if util.version_is_at_least(3, 0, 0, 'beta', 1, 18) then | |
| local_call = function(func_name, args) | |
| return pcall(netbox_self_call, netbox_self, func_name, args) | |
| end | |
| else -- < 3.0.0-beta1-18 | |
| -- net_box.self.call() doesn't work with C stored and Lua persistent | |
| -- functions before 3.0.0-beta1-18, so we try to call it via func.call | |
| -- API prior to using net_box.self API. | |
| local_call = function(func_name, args) | |
| local func = box.func and box.func[func_name] | |
| if not func then | |
| return pcall(netbox_self_call, netbox_self, func_name, args) | |
| end | |
| return pcall(func.call, func, args) | |
| end |