To build a kafka/rabbitmq consuming pipeline with saturated stages in Go you normally need to spin a goroutine per stage and connect them with channels (whose buffer can’t be change in runtime). The logic of processing one message (or batch of messages) gets split between multiple functions not allowing you to use local variables and making it complicated to sync different branches of execution (in case of fan-outs).
Interesting approach, here is some opinionated critique:
API-Ergonomics. I don’t like the “stage.moveTo()” syntax. It is not clear at all that something is locked and without an explicit “release” it is very unclear when it is released. Go provides a nice option with aquire() defer release(), which feels very Go-Native and provides stability with early returns or panics. I would prefer a readStage.aquire() and defer readStage.release()
I’m missing an easy option to parallelize the processing of individual stages - as it stands I would have to code this myself when using the library - whereas channels can easily have multiple concurrent readers, which execute multiple packets in parallel. In your implementation, if a single item is very slow in a single stage, that stage will be locked until this item is completely processed, implicitly blocking all prior stages from advancing. So a single slow network call would slow down the whole pipeline.
No automatic scaling/back pressure. A good pipeline system would provide some feedback via back pressure from later stages, so earlier stages can adjust their throughput dynamically to provide an even load.