Runtime enable/disable modules

I’m thinking of building an app that uses a similar module (concept, not Go module) approach to Apache. I’ll have a modules_available directory and modules_enabled and to enable a module you symlink from available to enabled. I want these changes to be picked up at run time rather than having the user recompile the app.

If it helps, I think the modules will all have the same interface which will be a couple of functions, take data, return processed data.

How easy is this to do and, if easy, is there a good write up on doing it?

As background, I’m thinking of rewriting this Ruby app to take better advantage of multi-threading.

In Ruby it is easy to dynamically pull in all the enabled checkers but as I’m new to Go I’m still trying to work out what is possible, possible but shouldn’t be done and impossible.

1 Like

Go plugins might be useful, see here.

1 Like

That looks like it would do it. From the sample code there, I’d get a directory listing of the enabled directory then loop through all the files calling open on them.

I can see a weekend of brain melting trying to get this working while I get my head round all the concepts but looking forward to it.

FWIW I wouldn’t go there unless you really need to load the code at runtime. Your life will be simpler by compiling the modules at compile time and enabling/disabling them based on a configuration file or similar.

2 Likes

Why not? Is it not a good way to do things in Go, hard to work with, or something else?

The way things currently work, people install the app then if they want any small tweaks to the modules I can send over just the one file, they can drop it in the directory with a different name and see the changes straight away. Small things like that would probably be harder with a single compiled binary.

you could send the (possibly cross) compiled binary with the updated file :slight_smile:

plugins are great but, as of Go-1.10.x:

  • only work on {linux,darwin}-amd64
  • aren’t completely bug free

so… YMMV.

2 Likes

If I did this at build time, I want the flexibility to add new modules with as little effort as possible. The way I’m doing it with Ruby is to build an array of modules and then loop through the array calling the same function on each module.

The modules don’t need to hold any state so don’t need to be instantiated objects, they can be class methods or just functions in a library. The functions are all going to have the same name just in different namespaces (excuse probably wrong terminology).

Rough pseudo code is:

mod_list = dir (module_directory)
for each mod_name in mod_list
  mod_array << mod_name.register()
end

for each item I want to parse
  for each module in mod_array
    results[module name] = module.parse(data)
  end
end

for each module in array
  print module.generate_results (results[module name])
end

A common way of doing this in Go is to have a per file init() that registers the function or type in that file in some package-level variable. I typed up an example for that a while back here on the forum but I can’t find it… Basically

main.go

var registry = make(map[string]func() string)

func main() {
  for name, fn := registry {
    fmt.Println(name, "says", fn())
  }
}

foo.go

func init() {
  registry["foo"] = foo
}

func foo() string {
  return "hello"
}

“foo says hello”

I spent this morning playing with modules and interfaces and came up with a way that worked but required me to do some work when I added a new module, merging that with this I think will do just what I need. Thanks.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.