简体   繁体   中英

add plugins to a go program

I need to provide pluggable functionality to a Go program. The idea is that a 3rd party can add functionality for a given path, ie

/alive maps to http://localhost:9876 , or /branding maps to http://localhost:9877 and so on.

I first tried to think of it as adding a JSON config file, where each such plugin would have an entry, eg:

{
  "Uri": "alive",
  "Address":"http://localhost:9876",
  "Handler":"github.com/user/repo/path/to/implementation"
},

This though blatantly reveals Java thinking - and feels like utterly inadequate for Go - there is no notion of Class loaders in Go , and loading this would mean to have to use the loader package from golang 's tools.

Proposals on how to do this in a more Go - idiosyncratic way? In the end I just need to be able to map a URI to a port and to an implementation.

Compile-time configuration

If you can live with compile-time configuration, then there is no need for a JSON (or any other) configuration file.

Your main package can import all the involved "plugins", and map their handler to the appropriate path. There is also no need to create multiple servers, although you may do so if that fits better your (or the modules') needs.

Run-time configuration

Run-time configuration and plugging in a new module requires code to be loaded at run-time. This is supported by the plugin package, but currently only under linux.

For this you may use a JSON config file, where you would list the compiled plugins (path to the compiled plugins) along with the paths you need to map them.

In the main package you can read the config file, and load the plugins, which should expose a variable or a function that returns you the handler that handles the traffic (requests). This is preferred to the plugins themselves firing up an http server for performance reasons, but both can work (plugins returning a handler for you to register, and the plugins launching their servers).

Note that there is also no need to make the configuration "static", the main app could receive and load new modules at runtime too (eg via a dedicated handler, which could receive the (file) path to the new module and the path to map it to, optionally maybe even the binary plugin code too; but don't forget about security!).

Note that while you can load plugins at runtime, there is no way to "unload" them. Once a plugin is loaded, it will stay in memory until the app exists.

Separate, multi-apps

There is a third solution, in which your main app would act as a proxy. Here you may start the additional "modules" as separate apps, listening on localhost at specific ports, and the main app would act as a proxy, forwarding requests coming in to the other independent apps listening on different ports @localhost (or even on other hosts).

The standard library provides you the httputil.ReverseProxy doing just this.

This does not require runtime code loading, as the "modules" are separate apps which can be launched separately. Still, this gives runtime configuration flexibility, and this solution also works on all platforms. Moreover this setup supports taking down modules at runtime, as you can just as easily un-map / close the apps of the independent modules.

The separate apps can also be launched separately, or from / by the main app, both solutions are viable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM