Reload the code with out restarting

860 views
Skip to first unread message

Alexis Okuwa

unread,
Aug 12, 2016, 2:21:14 PM8/12/16
to openresty-en
Hello,

Wanted to know if there is anyway to reload code with out having to restart openresty. The docs are clear about lua_code_cache for when the code is inline the openresty config file but does not have any help for when i am using by file or by block. The goal is to have none restart deployments to the lua part of the code base without having to kick all the users that are connected offline. 

Yichun Zhang (agentzh)

unread,
Aug 12, 2016, 3:44:59 PM8/12/16
to openresty-en
Hello!
Sounds like you just need to write your own (simple) Lua code loader.
It is conceptually simple and also technically easy to implement.
Basically you request a remote service (like Redis, Memcached, or
KyotoKycoon) to fetch the Lua source or bytecode piece, and use
loadstring() to load the code, and finally cache the resulting Lua
object (be it a Lua module table or a Lua closure) via
lua-resty-lrucache or just inserting into package.loaded directly
(used by require too). We do this extensively at CloudFlare since we
have so many customers and they usually have different custom logic on
the edge (be it routing rules or WAF rules or anything else).

The doc for loadstring() can be found here:

https://www.lua.org/manual/5.1/manual.html#pdf-loadstring

Always specify a chunk name as the 2nd argument to loadstring()! Like
"=my_super_lua_chunk" (the leading = is special and required).
Otherwise the LuaJIT VM will just use the whole source string as the
chunk name which is hardly readable for error messages and is also a
waste of memory.

Loading LuaJIT bytecode is usually loaded much faster than Lua source
since it saves the Lua source parsing phase. But using Lua source is
much more portable (surviving major LuaJIT version updates) and more
debuggable. It's up to you to make the decision here.

Just be careful that you should call loadstring() ONLY upon Lua code
changes, otherwise you're wasting your CPU cycles on reloading the
same code over and over again, which is quite expensive. So I guess
you need to compare the new Lua code and your existing loaded Lua code
via a string comparison or, better, via a checksum comparison (like
MD5 or SHA-1).

One caveat is that your dynamically loaded Lua code should not use the
FFI API to define new C symbols or C types nor should it try load
external DSO. This is because such Lua code chunks cannot get unloaded
safely due to technical constraints. Otherwise you are good.

Enjoy the dynamic nature of Lua! And happy loading and unloading Lua code!

Best regards,
-agentzh

Aapo Talvensaari

unread,
Aug 13, 2016, 5:38:40 AM8/13/16
to openresty-en
On Friday, 12 August 2016 22:44:59 UTC+3, agentzh wrote:
Loading LuaJIT bytecode is usually loaded much faster than Lua source
since it saves the Lua source parsing phase. But using Lua source is
much more portable (surviving major LuaJIT version updates) and more
debuggable. It's up to you to make the decision here.

Also there could be security considerations on loading byte code, as it is not checked in anyway, so you could easily write byte code that cannot even be emitted by parser / byte code compiler. 

Alexis Okuwa

unread,
Aug 15, 2016, 8:22:33 PM8/15/16
to openresty-en
Agentzh,

Thank you so much this is very useful this is what i was guessing but wanted to confirm. I was thinking about making it even more simple then using a database. Having a special endpoint that that told it to reload the code from an already defined new code folder and then storing that in the ngx.shared and then lrucache would be able cache from there into each of the workers.

Aapo,
Yeah this is one thing that is not fun to think about but will have to lock it down some how.

Aapo Talvensaari

unread,
Aug 16, 2016, 11:05:22 AM8/16/16
to openresty-en
On Tuesday, 16 August 2016 03:22:33 UTC+3, Alexis Okuwa wrote:
Thank you so much this is very useful this is what i was guessing but wanted to confirm. I was thinking about making it even more simple then using a database.

Also you could unload the loaded modules by setting package.loaded['mymodule'] = nil. To do that on all the workers you can trigger that with some pub/sub + recurring timer on workers or something. 

Yichun Zhang (agentzh)

unread,
Aug 17, 2016, 3:50:00 PM8/17/16
to openresty-en
Hello!

On Sat, Aug 13, 2016 at 2:38 AM, Aapo Talvensaari wrote:
>
> Also there could be security considerations on loading byte code, as it is
> not checked in anyway, so you could easily write byte code that cannot even
> be emitted by parser / byte code compiler.
>

Apparently you should not load byte code or even Lua source code from
untrusted sources (including your customers). The bytecode should only
generated by yourself (maybe in another machine or service managed by
yourself).

Regards,
-agentzh

Alexis Okuwa

unread,
Aug 18, 2016, 2:01:55 PM8/18/16
to openresty-en
All the code that is going to be loaded is "trusted code" as in written by us and not a customer the goal is to not need to restart and disconnect things
Reply all
Reply to author
Forward
0 new messages