Allow to enrich a command as well as an event
It would be nice if I could attach some metadata such as the correlation id to a command so that it can be merged into the metadata of the corresponding events.
There are already pure equivalents of Java's ThreadLocal such as monix.eval.TaskLocal and zio.FiberRef that can propagate its local state through the effect context.
A possible use case:
- A http4s middleware generates a correlation id, and embeds it in the fiber (effect context) using
TaskLocal/FiberRef - The Aecor runtime serializes and sends the command using an enriched wire protocol that extracts the correlation id and makes command metadata
- The corresponding command handler deserializes the command and embeds the metadata in the fiber
- The enriched event handler extracts the metadata from the fiber and put the correlation id into the event metadata
Reference: https://blog.softwaremill.com/correlation-ids-in-scala-using-monix-3aa11783db81
Good idea.
I think it is doable using a trick similar to EitherK[M, R, F]. It turns M[F] into M[EitherT[F, R, ?]].
You can create EnrichedK[M, C, F] that turns your M[F] into M[ReaderT[F, C, ?]].
That's another possible interpretation.
Basically I prefer MTL style typeclass with effect-native interpretation over traditional monad transformer, for example, MonadState[IO, S] with Ref[IO, S] over StateT[IO, S, ?].
Speaking of the Akka cluster runtime, the tricky part seems to me is steps 2 and 3 in the above use case. Regardless of the effect stack, the wire protocol should encode the command and metadata something like Enriched[Metadata, Command] into binary, and then it's GenericAkkaRuntimeActor's responsibility to unwrap the command for the behavior function and to construct the effect stack again, possibly setting TaskLocal/FiberRef by itself with metadata.
InvariantK pops up in my head...
@typeclass trait InvariantK[A[_[_]]] {
def imapK[F[_], G[_]](af: A[F])(fk: F ~> G)(gK: G ~> F): A[G]
}
I see what you want however I prefer to use composition rather than modify existing runtime. So I need some time to think about it :)
I understand that you want to avoid changes in the runtime because you're already running Aecor based services in production. Please feel free to take your time and let me know your thoughts :) I'll add my findings as well.