3

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

4

1 回答 1

6

为了找到问题的最佳解决方案,了解您要达到的目标很重要。有两种可能的情况:

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

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

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

这是一种可以概括的低级方法:循环“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 来重新注册处理程序,HTTP 请求仍然会调用旧函数。

在盒式磁带中,您通常在 apply_config() 或 init() 中注册函数。例如,请参见此处。为了重新注册回调,您需要再次调用角色的 init() 或 apply_config()。要获取角色列表,您可以使用Cartridge.roles.get_known_roles()。您需要遍历它们并重新初始化它们。

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

实现此目的的第二种方法是使用可让您通过网络推送新代码的插件扩展。它已经有了一些细节,比如简化了与公共端点的绑定。

于 2020-09-16T09:21:13.047 回答