Giter VIP home page Giter VIP logo

hotswap's Introduction

Banner

简体中文版

Hotswap provides you a complete solution to reload 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.Extension and/or PluginManager.Vault.DataBag
  • Handle asynchronous jobs using the latest code with live function, live type, and live 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 plugin

Flags:
      --debug               enable 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
      --livePrefix string   case-insensitive name prefix of live functions and live types (default "live_")
      --staticLinking       generate code for static linking instead of building a plugin
  -v, --verbose             enable 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.

  1. hello demonstrates the basic usage, including how to organize host and plugin, how to build them, how to load plugin on server startup, how to use InvokeEach, and how to reload.
  2. extension shows how to define a custom extension and how to use PluginManager.Vault.Extension. A small hint: WithExtensionNewer()
  3. livex is somewhat complex. It shows how to work with live function, live type, and live data.
  4. slink is an example of plugin static-linking, with which debugging a plugin with a debugger (delve) under MacOS and Windows becomes possible.
  5. trine is 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 before the Vault is initialized.
func OnLoad(data interface{}) error {
    return nil
}

// OnInit gets called after the execution of all OnLoad functions. The Vault is ready now.
func OnInit(sharedVault *vault.Vault) error {
    return nil
}

// OnFree gets called at some time after a reload.
func OnFree() {
}

// Export returns an object to export 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. Vault Initialization
6. OnInit

Attentions

  • Build your host program with the environmental variable CGO_ENABLED=1 and the -trimpath flag.
  • 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, it's error-prone.
  • The same type in different versions of a plugin are actually not the same at runtime. Use live function, live type, and live data to 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, Hotswap offers you a chance, the OnFree function, to clear caches.
  • It is required to manage your code with git and go module.
  • It is highly recommended to keep the code of your host program and all its plugins in a same repository.

Live Things

  • live function is a type of function whose name is prefixed with live_ (case-insensitive). Live functions are automatically collected and stored in PluginManager.Vault.LiveFuncs. For example:
func live_Foo(jobData live.Data) error {
      return nil
}
  • live type is a type of struct whose name is prefixed with live_ (case-insensitive). Live types are automatically collected and stored in PluginManager.Vault.LiveTypes. For example:
type Live_Bar struct {
      N int
}
  • live data is a type guardian. You can convert your data into a live data object when scheduling an asynchronous job and restore your data from the live data object when handling the job.
  • See the demo livex for details.

FAQ

  • How can I debug a plugin with a debugger?

Build it with --staticLink. For more information, please refer to the demo slink.

  • Does hotswap work on Windows?

Building with --staticLink works on Windows, but plugin reloading is not an option because Go's plugin mechanism doesn't support Windows.

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

hotswap's People

Contributors

edwingeng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

hotswap's Issues

Does not work on ARM

Hey. Today I gave it a try and it's failed.

mtrofimenko@Maksyms-MBP hello % ./run.sh 
Building hello...

go: downloading github.com/edwingeng/slog v0.0.0-20221027170832-482f0dfb6247
go: downloading github.com/pierrec/xxHash v0.1.5
go: downloading golang.org/x/mod v0.8.0
go: downloading go.uber.org/zap v1.23.0
Building plugin "world"...
/Users/mtrofimenko/Work/Current/hotswap/demo/hello/bin/darwin/plugin/hello/world.so

Starting hello...

05|11:33:43     INFO    hotswap/pluginManager.go:84     <hotswap> not reloadable: [], unchanged: [], to be loaded: [world]
panic: failed to load the plugin world. err: plugin.Open("/Users/mtrofimenko/Work/Current/hotswap/demo/hello/bin/darwin/plugin/hello/tmp/230405113343-27640/world-0x98fd8920.so"): dlopen(/Users/mtrofimenko/Work/Current/hotswap/demo/hello/bin/darwin/plugin/hello/tmp/230405113343-27640/world-0x98fd8920.so, 0x000A): tried: '/Users/mtrofimenko/Work/Current/hotswap/demo/hello/bin/darwin/plugin/hello/tmp/230405113343-27640/world-0x98fd8920.so' (mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64')), '/System/Volumes/Preboot/Cryptexes/OS/Users/mtrofimenko/Work/Current/hotswap/demo/hello/bin/darwin/plugin/hello/tmp/230405113343-27640/world-0x98fd8920.so' (no such file), '/Users/mtrofimenko/Work/Current/hotswap/demo/hello/bin/darwin/plugin/hello/tmp/230405113343-27640/world-0x98fd8920.so' (mach-o file, but is an incompatible architecture (have 'arm64', need 'x86_64'))

goroutine 1 [running]:
main.main()
        github.com/edwingeng/hotswap/demo/hello/hello.go:53 +0x816

Also would be really good to have some article which explains how does it work in a comparison to the go's plugin feature. Thanks

有点疑惑这个对于已经注册后的函数替换

type UseCase struct {
	api.IActvShowRankUseCase
}

func NewUseCase(createApi func(*UseCase) api.IActvShowRankUseCase) api.IActvShowRankUseCase {
	uc := &UseCase{}
	uc.CreateHotAPI(createApi)
	return uc
}

func (uc *UseCase) DepInject() {
	uc.ActvCase().RegPackModule(gdconf.ActvShowRankModule, uc.PackModule)
	uc.ActvCase().RegPackModule(gdconf.ActvShowRankModule, getICase(uc).PackModule)
}

func getICase(iuc interface{}) api.IActvShowRankUseCase {
	return iuc.(api.IActvShowRankUseCase)
}

func (uc *UseCase) CreateHotAPI(createApi func(*UseCase) api.IActvShowRankUseCase) error {
	api := createApi(uc)
	uc.IActvShowRankUseCase = api
	return nil
}

我这个UseCase有一个IActvShowRankUseCase接口(它有个PackModule函数),另外一个可热更的包里面的struct实现了这个IActvShowRankUseCase, 热更的时候我会用CreateHotAPI,给他换掉。

但是DepInject这个我只会正常启动服务器的时候才会调用。 在DepInject里面两种注册方式,第一种热更后不能读到新代码,但是第二种写法可以。请问下这个是为什么呢,。

之前我以为我需要让RegPackModule这个函数也得放到可热更包里面,然后让它支持可以重复注册,但是我用下面的写法看起来可以不用

提问: 依赖问题

你好,我最近在看go-plugin的相关文档,发现它有需要限制。对我们来说最主要的是版本冲突的问题。
你的项目应该是解决go-plugin版本冲突的问题。
请问你是如何解决这个问题的?例如main程序和plugin程序依赖的第三方包版本不一致。

同学,您这个项目引入了100个开源组件,存在4个漏洞,辛苦升级一下

检测到 edwingeng/hotswap 一共引入了100个开源组件,存在4个漏洞

漏洞标题:jwt-go 安全漏洞
漏洞编号:CVE-2020-26160
漏洞描述:jwt-go是个人开发者的一个Go语言的JWT实现。
jwt-go 4.0.0-preview1之前版本存在安全漏洞。攻击者可利用该漏洞在使用[]string{} for m[\"aud\"](规范允许)的情况下绕过预期的访问限制。
影响范围:(∞, 4.0.0-preview1)
最小修复版本:4.0.0-preview1
缺陷组件引入路径:github.com/edwingeng/hotswap@->github.com/spf13/[email protected]>github.com/spf13/[email protected]>github.com/dgrijalva/[email protected]+incompatible

另外还有4个漏洞,详细报告:https://mofeisec.com/jr?p=ne4626

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.