skynet 热更新

inject热更新

 inject命令相当于注入代码到服务中,原理就是让指定服务执行某个代码文件,通过修改模块及其函数的upvalue,完成对lua模块代码或变量的替换。

实践过程中,发现一个注意点:_P 内存的 key/value 其实就是 skynet.lua 里 14 行 proto 中的 name 和 dispatch 的 upvalue。 

inject这个方法先记录一下,用来修改无状态的函数。


 inject
 用法很简单,启动skynet,连接到其控制台:

 
# nc 127.0.0.1 8000
Welcome to skynet console
list
:00000004       snlua cmaster
:00000005       snlua cslave
:00000007       snlua datacenterd
:00000008       snlua service_mgr
:0000000a       snlua protoloader
:0000000b       snlua console
:0000000c       snlua debug_console 8000
:0000000d       snlua simpledb
OK
inject :0000000d example/inject_simpledb.lua

 


 inject命令的难点是,这个要注入的lua代码该怎么写。

 下面直接改写skynet自带的example做说明:

 # cat examples/simpledb.lua

 
local skynet = require "skynet"
require "skynet.manager" 
local db = {}
local command = {}

-- 增加了这里
local function test(msg)
        print(msg)
end
-- 增加了这里
function command.do_test(msg)
        test(msg)
end

skynet.start(function()
        skynet.dispatch("lua", function(session, address, cmd, ...)
                local f = command[string.upper(cmd)]
                if f then
                        skynet.ret(skynet.pack(f(...)))
                else
                        error(string.format("Unknown command %s", tostring(cmd)))
                end
        end)
        -- 增加了这里
        skynet.fork(function()
                while true do
                        skynet.sleep(100)
                        command.do_test("itest!")
                end
        end)
        skynet.register "SIMPLEDB"
end)
假设以上的 command.do_test 就是我们要热更改掉的函数。那用于inject的lua代码如下:

 # cat inject_test.lua

 
if not _P then
        print("hotfix fail, no _P define")
        return
end

print("hotfix begin")

-- 用于获取函数变量
local function get_up(f)
        local u = {}
        if not f then
                return u
        end
        local i = 1
        while true do
                local name, value = debug.getupvalue(f, i)
                if name == nil then
                        return u
                end
                u[name] = value
                i = i + 1
        end
        return u
end

-- 获取原来的函数地址,及函数变量
local command = _P.lua.command
local upvs = get_up(command.do_test)
local test = upvs.test

command.do_test = function(msg)
    test('New ' .. msg)
end

print("hotfix end")

 
启动控制台,执行inject后,就会看到类似下面的skynet的日志:

 
# ./skynet examples/config
[:00000001] LAUNCH logger 
[:00000002] LAUNCH snlua bootstrap
[:00000003] LAUNCH snlua launcher
[:00000004] LAUNCH snlua cmaster
[:00000005] LAUNCH snlua cslave
[:00000006] LAUNCH harbor 1 16777221
[:00000007] LAUNCH snlua datacenterd
[:00000008] LAUNCH snlua service_mgr
[:00000009] LAUNCH snlua main
[:0000000a] LAUNCH snlua protoloader
[:0000000b] LAUNCH snlua console
[:0000000c] LAUNCH snlua debug_console 8000
[:0000000d] LAUNCH snlua simpledb
[:0000000e] LAUNCH snlua watchdog
[:0000000f] LAUNCH snlua gate
[:0000000f] Listen on 0.0.0.0:8888
Watchdog listen on      8888
[:00000009] KILL self
[:00000002] KILL self
itest!
itest!
itest!
New itest!
New itest!
 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值