hotswap
hotswap copied to clipboard
A complete solution to reload your go code without restarting your server, interrupting or blocking any ongoing procedure.

简体中文版
Hotswap provides a solution for reloading your go code without restarting your server, interrupting or blocking any ongoing procedure. Hotswap is built upon the plugin mechanism.
Major Features
- Reload your code like a breeze
- Run different versions of a plugin in complete isolation
- Invoke an in-plugin function from its host program with
Plugin.InvokeFunc() - Expose in-plugin data and functions with
PluginManager.Vault.DataBagand/orPluginManager.Vault.Extension - Handle asynchronous jobs using the latest code with
live function,live type, andlive data - Link plugins statically for easy debugging
- Expose functions to other plugins with
Export() - Depend on other plugins with
Import()
Getting Started
go install github.com/edwingeng/hotswap/cli/hotswap
Build a Plugin from Source Code
Usage:
hotswap build [flags] <pluginDir> <outputDir> -- [buildFlags]
Examples:
hotswap build plugin/foo bin
hotswap build -v plugin/foo bin -- -race
hotswap build --staticLinking plugin/foo pluginHost
Flags:
--debug enable the debug mode
--exclude string go-regexp matching files to exclude from included
--goBuild if --goBuild=false, skip the go build procedure (default true)
-h, --help help for build
--include string go-regexp matching files to include in addition to .go files
--leaveTemps do not delete temporary files
--prefixLive string the case-insensitive name prefix of live functions/types (default "live_")
--staticLinking generate code for static linking instead of building a plugin
-v, --verbose enable the verbose mode
Demos
You can find these examples under the demo directory. To have a direct experience, start a server with run.sh and reload its plugin(s) with reload.sh.
hellodemonstrates the basic usage, including how to organize host and plugin, how to build them, how to load plugin on server startup, how to useInvokeEach, and how to reload.extensionshows how to define a custom extension and how to usePluginManager.Vault.Extension. A small hint:WithExtensionNewer()livexis somewhat complex. It shows how to work withlive function,live type, andlive data.slinkis an example of plugin static-linking, with which debugging a plugin with a debugger (delve) under MacOS and Windows becomes possible.trineis the last example. It demonstrates the plugin dependency mechanism.
Required Functions
A plugin must have the following functions defined in its root package.
// OnLoad gets called after all plugins are successfully loaded and all dependencies are
// properly initialized.
func OnLoad(data interface{}) error {
return nil
}
// OnInit gets called after the execution of all OnLoad functions.
func OnInit(sharedVault *vault.Vault) error {
return nil
}
// OnFree gets called at some time after a reload.
func OnFree() {
}
// Export returns an object to be exported to other plugins.
func Export() interface{} {
return nil
}
// Import returns an object indicating the dependencies of the plugin.
func Import() interface{} {
return nil
}
// InvokeFunc invokes the specified function.
func InvokeFunc(name string, params ...interface{}) (interface{}, error) {
return nil, nil
}
// Reloadable indicates whether the plugin is reloadable.
func Reloadable() bool {
return true
}
Order of Execution during Plugin Reload
1. Reloadable
2. Export
3. Import
4. OnLoad
5. OnInit
Attentions
- Build your host program with the environmental variable
CGO_ENABLED=1and the-trimpathflag. - Do not define any global variable in a reloadable plugin unless it can be discarded at any time or it actually never changes.
- Do not create any long-running goroutine in a plugin.
- The same type in different versions of a plugin are actually not the same at runtime. Use
live function,live type, andlive datato avoid the trap. - The code of your host program should never import any package of any plugin and the code of a plugin should never import any package of other plugins.
- Old versions won't be removed from the memory due to the limitation of golang plugin. However,
Hotswapoffers you a chance, theOnFreefunction, to clear caches. - It is required to manage your code with
git. - It is highly recommended to keep the code of your host program and all its plugins in a same repository.
Live Things
live functionis a type of function whose name is prefixed withlive_(case-insensitive). Live functions are automatically collected and stored inPluginManager.Vault.LiveFuncs. For example:
func live_Foo(jobData live.Data) error {
return nil
}
live typeis a type of struct whose name is prefixed withlive_(case-insensitive). Live types are automatically collected and stored inPluginManager.Vault.LiveTypes. For example:
type Live_Bar struct {
N int
}
live datais a type guardian. Convert your data into alive dataobject when scheduling an asynchronous job and restore your data from thelive dataobject when handling the job.- See the demo
livexfor details.