Plug.Router - best practices for managing dependencies/state?

A co-worker brought up a question in our Slack that stirred up some conversation around Plug.Router. It seems that Plug.Router doesn’t have any hooks for injecting dependencies and also doesn’t have any state allowing you to cache values. Here are two issues that came up:

  1. We have an existing processing pipeline. We want to add a web interface to that processing pipeline. Our thought is to treat Plug.Router like any old OTP process and inject our dependencies into the Router (PIDs, names, via tuples, whatever). As far as we can tell we can’t do that though, and our only option seems to be to register a process with a name (globally or in a Registry) and reference this constant from our web handler. This works, but it doesn’t jive with how the rest of our injection works and creates issues in tests (e.g. need to run tests synchronously)

  2. Suppose we have secrets that are injected at runtime (in this case basic auth creds). It seems like the only way to avoid recomputing these on each web request are 1) compiling these in (big no-no) or 2) creating a separate Agent or to cache the value and which can be referenced. Recomputing our basic auth headers is not expensive, but it does bring up questions on how we would handle something expensive. I feel like ideally we would pre-compute these at boot, cache them, and pass them in as arguments to the handler processes that are spawned by Plug

Are there other approaches we’re not considering? Is this design intentional? Are we falling into some anti-pattern without even realizing it? Is there some limitation in Plug, or some feature that I’m just not aware of? I’ve noticed the init callbacks, but those don’t quite seem to address our problems

Why can’t you just assign those to the assign in the plug?

Same thing, why can’t you just assign those to the assign in the plug?

A router is not a process (well, it is internally, but it is a pipeline conceptually, and the process dies on each request). To put something through it you add it to the assigns on the plug so it get’s carried through. Or instead of a plug just make a function call.

ETS, this is the very purpose of it is to cache things like this. ^.^

What you described sounds very OOP’ish, definitely not functional or Actor based. ^.^

Other than that, need (pseudo-)code to help walk you through more. :slight_smile:

4 Likes

During app Init you can read any dynamic secrets and store them with Application.put_env

The plugs in your router pipeline can then read them out of the application env and put them in the Conn assigns map.

ETS / Agents etc shouldn’t be necessary just for injected configurations.

2 Likes

Well, Application.put_env ‘is’ using ETS. ^.^