"error_marshaling_enabled" 设置似乎始终启用

The "error_marshaling_enabled" setting seems to be always enabled

当我运行这段代码时:

$client->evaluate('
    box.session.settings.error_marshaling_enabled = false
    box.error{code = 42, reason = "Foobar", type = "MyError"}
');

无论 error_marshaling_enabled 的值如何,我总是收到新的 (extended) 错误格式的响应:

  [
    49 => 'Foobar',
    82 => [
      0 => [
        0 => [
          0 => 'CustomError',
          2 => 3,
          1 => 'eval',
          3 => 'Foobar',
          4 => 0,
          5 => 42,
          6 => [
            'custom_type' => 'MyError',
          ],
        ],
      ],
    ],
  ],

这是为什么?

简答。

error_marshaling_enabled 选项仅影响错误 object 在响应 body (48, IPROTO_DATA) 中的编码方式。它不影响在响应 header (82, IPROTO_ERROR).

中将它们 return 编辑为异常的方式

长答案。

在 Tarantool 中,错误 object 可以通过两种方式 return 编辑:作为异常和作为 object。例如,这是如何将错误作为异常抛出:

function throw_error()
    box.error({code = 1000, reason = "Error message"})
    -- Or
    error('Some error string')
end

这是如何 return 它作为 object:

function return_error()
    return box.error.new({code = 1000, reason = "Error message"})
end

如果函数是远程调用的,使用 IPROTO 协议通过连接器(如 netbox)或 PHP 连接器或任何其他连接器,错误 return 方式会影响它如何编码到 MessagePack 响应中包。当函数抛出,并且错误到达栈顶帧而没有被捕获时,它被编码为IPROTO_ERROR(82)和IPROTO_ERROR_24(49).

当错误 object 被 return 编辑为常规值而不是异常时,它也被编码为常规值,在 IPROTO_DATA (48) 中。就像字符串、数字、元组等

编码为 IPROTO_ERROR/IPROTO_ERROR_24 时,没有太多的配置 space。这些值的格式无法更改。 IPROTO_ERROR 总是被 return 编辑为 MessagePack 映射,其中有一堆错误。 IPROTO_ERROR_24 始终是一条错误消息。保留 IPROTO_ERROR_24 字段是为了与 Tarantool 版本 < 2.4.1 的连接器兼容。

将编码作为 IPROTO_DATA 的一部分,您可以使用 error_marshaling_enabled 选项选择序列化方式。当它为真时,错误被编码为 MessagePack 扩展类型 MP_EXT,并包含整个错误堆栈,编码与 IPROTO_ERROR 值完全相同。当该选项为 false(2.4.1 中的默认行为)时,错误被编码为字符串 MP_STR,这是错误的消息。如果有一堆错误,则只对最新的错误进行编码。

error_marshaling_enabled 选项用于向后兼容,以防您在 Tarantool 上的应用程序希望与不支持 MP_EXT 编码错误的旧连接器兼容。

在 Tarantool < 2.4.1 中,错误被编码到结果 MessagePack 中作为带有错误消息的字符串,错误堆栈根本不存在。因此,当引入新格式和错误堆栈功能时,将新格式设置为默认格式将是一个过于激进的更改,会破坏旧连接器。

考虑这些错误封送处理如何影响结果的示例。我在这里使用 Tarantool 2.4.1 控制台和 built-in netbox 连接器。下面的代码可以复制粘贴到控制台中。

一审:

box.cfg{listen = 3313}
box.schema.user.grant('guest', 'super')

function throw_error()
    box.error({code = 1000, reason = "Error message"})
end

function return_error()
    return box.error.new({code = 1000, reason = "Error message"})
end

二审:

netbox = require('net.box')
c = netbox.connect(3313)

现在我尝试在第二个实例上调用函数:

tarantool> c:call('throw_error')
---
- error: Error message
...

c:call('throw_error') 引发异常。如果我使用 pcall() Lua 函数捕获它,我将看到错误 object.

tarantool> ok, err = pcall(c.call, c, 'throw_error')
tarantool> err:unpack()
---
- code: 1000
  base_type: ClientError
  type: ClientError
  message: Error message
  trace:
  - file: '[string "function throw_error()..."]'
    line: 2
...

如您所见,我没有设置 error_marshaling_enabled,但得到了完整的错误。现在我将毫无例外地调用另一个函数。但是报错object不会满

tarantool> err = c:call('return_error')
tarantool> err
---
- Error message
...
tarantool> err:unpack()
---
- error: '[string "return err:unpack()"]:1: attempt to call method ''unpack'' (a nil
    value)'
...

该错误被 return 编为纯字符串错误消息。不是错误 object。现在我将打开编组:

tarantool> c:eval('box.session.settings.error_marshaling_enabled = true')
---
...
tarantool> err = c:call('return_error')
---
...
tarantool> err:unpack()
---
- code: 1000
  base_type: ClientError
  type: ClientError
  message: Error message
  trace:
  - file: '[C]'
    line: 4294967295
...

现在相同的函数 return 以新的格式修正了错误,更有特色。

总结:error_marshaling_enabled 仅影响 returned 错误。没有抛出错误。