Skip to content

Week 16 - Plugins: plugin, go-plugin, gRPC-Based Extensions

16.1 Conceptual Core

  • Go has two plugin stories:
  • plugin package (stdlib)-load .so files at runtime via dlopen. Linux/macOS only; brittle in practice (every dependency must match the host's exact build, including the Go version).
  • HashiCorp go-plugin-out-of-process plugins communicating via gRPC or net/rpc over a local pipe. Used by Terraform, Vault, Packer, Nomad. Robust, polyglot, version-tolerant.
  • For any production extensibility story today, use go-plugin (or its design pattern)-not the stdlib plugin package.

16.2 Mechanical Detail

  • plugin package mechanics:
  • plugin.Open("./plug.so") loads the shared object.
  • p.Lookup("Symbol") returns an interface{} that you type-assert.
  • Constraints: same Go version, same module versions of every shared dependency, same build flags. In practice, used only for narrow, controlled use cases.
  • go-plugin design:
  • Host process spawns plugin as a subprocess.
  • Plugin advertises a "magic cookie" to confirm both sides agree.
  • They negotiate a protocol version and one of (gRPC, net/rpc) as the transport.
  • The host calls the plugin's interface methods, which round-trip over the pipe.
  • On host shutdown, the plugin process is killed.
  • Versioning: declare a HandshakeConfig and one or more Plugin interfaces per protocol version. Drop old versions on major bumps.
  • Performance: per-call latency is microseconds (in-process) or tens of microseconds (cross-process). Not for hot paths; use for control-plane operations (provisioning, configuration, lifecycle).

16.3 Lab-"A Pluggable Storage Backend"

Build a service whose storage backend is a plugin. The host defines an interface Storage { Get(key) (val, err); Put(key, val) error; Delete(key) error }. Ship two plugins: an in-memory backend, and a file-system backend. Both communicate via gRPC over go-plugin. Demonstrate hot-swap by killing one plugin process and starting the other.

16.4 Idiomatic & golangci-lint Drill

  • staticcheck SA1019 (deprecated net/rpc patterns), gocritic: ifElseChain. Plugin code paths are often where dependency-injection mistakes accumulate; review with discipline.

16.5 Production Hardening Slice

  • Add structured logging across the host/plugin boundary using slog with consistent attribute keys. Add a health-check method to every plugin interface; the host periodically probes it and ejects unhealthy plugins.

Month 4 Capstone Deliverable

A reflect-codegen-plugins/ workspace: 1. validator-rs (week 13)-cached reflective validator with the 10× win. 2. noctx-analyzer (week 14)-unitchecker binary, runs in CI. 3. three-gens (week 15)-stringer + mock + JSON marshaler generators. 4. pluggable-storage (week 16)-go-plugin host + two backends.

CI gates additions: custom analyzer in golangci-lint, generated-code freshness check, go-plugin integration test under - race. By end of month, open one PR upstream againstgolangci-lint(a small custom-analyzer doc fix is sufficient) orgo-playground/validator` (a benchmark, a doc, anything).

Comments