Client / server streaming support for each component type?

Hi there,

Is there a summary about which component types support client and server streams and how this translates to the component implementation? For example if I defined a value entity method with a stream input what would the behaviour implementation look like? Similarly, if a method had a stream output?

Reading through the docs I might expect there are some limitations for different component types. Is this documented?


1 Like

I’m not sure that we have explicit documentation on this, but all entity component types (value entities, event sourced entities and replicated entities) only support unary calls. Meanwhile, actions support unary and streamed calls in both directions.

I’m not sure if you’re asking about this or not, but let me just speak to the reasoning behind this.

What would a streamed input to a value entity give you? Each instance of a value entity is an island of strong consistency, when handling a command, you are guaranteed that nothing else will be interacting with that entity, nothing can change it underneath you, you can read property X and make a decision about modifying property Y, and be sure that when you have done that modification, property X won’t have since changed. Underneath, we guarantee this by sharding entity instances across nodes, and then on a single node, executing commands serially per instance.

So, if I had an input command that was a stream, how would that be handled? Since we only execute commands one at a time, would that mean that the entity would handle that input stream until it was completed, and nothing else could use that entity in the meantime? We could implement this in Kalix, but the result would be that a single call from a client could indefinitely lock up an entity instance, preventing anything else interacting with it, which is not desirable. Alternatively, each message on the stream could be handled as an independent action, allowing other calls from other clients to be handled in between them, that would solve that problem, but now why is it a streamed call? Why not just make many unary calls in succession? The overhead of doing this is almost non-existent, just a few bytes per call due to HTTP/2 header compression, each call will have identical headers (and so compression will compress them to just references to the last requests headers) and be going across the same HTTP/2 connection - from a wire perspective, there’s almost no difference to a gRPC streamed input call and many unary calls. So, it doesn’t make sense for us to support streamed input calls.

The same logic also applies to streamed output calls.


Thanks for the detailed answer, very clear.

Fantastic explanation. Explanations such as these, do not only clear immediate doubts, but also make way for more synthesized Aha moments, that we programmers are so familiar with!