Sharing state between middleware instances
This is more of a question than a bug report, but is there a way to share state between middleware instances? Keeping them independent and decoupled is usually preferable, but there are cases where being able to share state is nifty. I was hoping to achieve that via attachments, but they don't seem to be propagated between instances. Thoughts?
I think there are a few ways to do this. One, and I guess the most straightforward one would be to do it though the the user context object It is available to all middleware instances. Another idea would be to explicitly declare dependencies. For example:
val m1 = new MyMiddleware1
val m1 = new MyMiddleware2(m1)
Executor.execute(middleware = m1 :: m2 :: Nil)
or
val somethingShared = ???
val m1 = new MyMiddleware1(somethingShared)
val m1 = new MyMiddleware2(somethingShared)
Executor.execute(middleware = m1 :: m2 :: Nil)
Do you think this is something that might work in your case? If you could describe your use-case in more detail, maybe we could come up with something more suitable.
Thanks for the quick reply!
Say I have the following middleware pipeline
Authentication -> Permissioning -> Personalization
In Authentication I authenticate the user and obtain a token with a bunch of claims. I want to be able to propagate the token to Permissioning and Personalization as well as the resolvers. I've tried using attachments to achieve this, but apparently they don't propagate between instances. What I've done in the interim, as you've pointed out, is use a mutable state in UserContext, but I'd like to avoid that if possible.
Thoughts?
I see, so in essence you don't really need the state sharing, but you need to define a pipeline that chains multiple middleware instances together. Is it correct?
One thing that comes in mind is to create a new middleware class that allows to define a pipeline (something similar to the Fetchers where their logic is implemented as a single DeferredResolver which composes multiple fetcher instances). I mean something like this:
trait SomeNewMiddlewareKind {
// ...
}
class MiddlewarePipeline[Ctx](pipeline: Seq[SomeNewMiddlewareKind]) extends Middleware[Ctx] with ... {
// ....
}
Also, you are right, right now attachments are not propagated through the middleware chain. This is something to consider for a future, maybe it would make sense to adjust it and implement this behaviour.
I see, so in essence you don't really need the state sharing, but you need to define a pipeline that chains multiple middleware instances together. Is it correct?
Basically
- the instances need to be executed in a certain order
- there needs to be a way for them to share values generated at any step down the line
- the same values also need to be made available to the resolvers
I like the idea of creating a concrete middleware pipeline as it makes the dependency more explicit, while stringing together a bunch of middleware instances in a specific order to share state isn't.