如何在 tarantool 墨盒中执行热重载代码?

How can I perform hot reload code in tarantool cartridge?

如何在不重新启动应用程序的情况下在 tarantool cartridge 中执行热重载代码?

为了找到问题的最佳解决方案,了解您要实现的目标非常重要。有 2 种可能的情况:

  • 您使用包管理器重新部署您的应用程序,需要从文件系统重新加载代码
  • 您想通过数据库 API、网络
  • 推送新代码

第一个可以通过卸载模块并再次加载来完成。所有模块在加载时都会将自己放置到 'package.loaded' table 中。所以你只需要更新它:

package.loaded['mymodule'] = nil
require('mymodule')

这是一种您可以推广的 low-level 方法:遍历 'package.loaded' 的内容,卸载所有内容并重新加载。您需要注意不要卸载文件系统中不存在的模块。有一个模块可以帮助您解决这个问题:https://github.com/moonlibs/package-reload

虽然该模块将帮助您了解基础知识,但您还需要考虑其他事项。在 Lua 中很容易在全局对象中存储函数指针。如果您重新加载函数本身,您将不会神奇地更新所有具有指向旧函数的指针的地方。例如,让我们考虑 http 服务器:

-- in mymodule.lua
local function handler(req)
    local resp = req:render({text = req.method..' '..req.path })
    resp.headers['x-test-header'] = 'test';
    resp.status = 201
    return resp
end

-- somewhere else
router:route({ path = '/test', method = 'GET' }, mymodule.handler)

如果您重新加载 mymodule.lua,并且不再调用 router:route 到 re-register 处理程序,HTTP 请求仍将调用旧函数。

在 cartridge 中,通常在 apply_config() 或 init() 中注册函数。参见 here for example. In order to re-register the callbacks you need to call init() or apply_config() of your roles again. To get a list of roles, you can use cartridge.roles.get_known_roles()。您需要遍历它们并 re-init 它们。

为了调用重新加载代码的函数,您需要通过二进制协议进行连接,或者使用管理套接字。管理套接字允许您为此编写一个简单的 shell 脚本。您可以通过查看 tarantool_is_up script 来了解这个想法。它演示了您可以针对 use-case.

进行调整的方法

实现此目的的第二种方法是使用 cartridge-extensions,它允许您通过网络推送新代码。它已经有了一些细节,比如简化了对 public 端点的绑定。