A stateful service is a deployable unit. It is represented in Kubernetes as a
StatefulService resource. It contains a User function, and may reference a Stateful store. The Cloudstate operator transforms a stateful service into a Kubernetes Deployment resource. The Cloudstate operator then defines a Kubernetes Service to expose the stateful service to the outside world. The deployment will be augmented by the injection of a Cloudstate Proxy.
A stateful store is an abstraction over a datastore, typically a database. It is represented in Kubernetes as a
StatefulStore resource. A single store may be used by multiple Stateful services to store their data, but a stateful service may not necessarily have any store configured - if the stateful service does not have any durable state then it doesn’t need a stateful store.
A user function is the code that the user writes, packaged as a Docker image, and deployed as a Stateful service. The user function exposes a gRPC interface that speaks the Cloudstate Protocol. The injected Cloudstate Proxy speaks to the user function using this protocol. The end-user developer, generally, doesn’t need to provide the code implementation of this protocol along with the user function. This burden is delegated to a Cloudstate Support library, specific to the programming language used to write the user function.
The Cloudstate protocol is an open specification for Cloudstate state management proxies to speak to Cloudstate user functions. The Cloudstate project itself provides a Reference implementation of this protocol. The protocol is built upon gRPC, and provides support for multiple different Entity types. Cloudstate provides a Technology Compatibility Kit (TCK) that can be used to verify any permutation of Proxy and Support library available. More technical details in Creating language support libraries.
The Cloudstate proxy is injected as a sidecar into the deployment of each Stateful service. It is responsible for state management, and exposing the Entity service implemented by the User function as both gRPC and REST services to the rest of the system, translating the incoming calls to Commands that are sent to the user function using the Cloudstate Protocol. The proxy will typically form a cluster with other nodes in the same stateful service, allowing advanced distributed state management features such as sharding, replication and addressed communication between nodes of a single stateful service.
While a User function can be implemented simply by implementing the gRPC interfaces in the Cloudstate Protocol, this protocol is somewhat low level, and not particularly well suited for expressing the business logic that typically will reside in a user function. Instead, developers are encouraged to use a Cloudstate support library for their language of choice, if available.
A command is used to express the intention to alter the state of an Entity. A command is materialized by a message received by a user function. Commands may come from outside of the Stateful service, perhaps from other stateful services, other non Cloudstate services, or the outside world, or they may come from within the service, invoked as a side effect or to forward command handling from another command.
A User function implements one or more entities. An entity is conceptually equivalent to a class, or a type of state. An entity will have multiple Entity instances of it which can handle commands. For example, a user function may implement a chat room entity, encompassing the logic associated with chat rooms, and a particular chat room may be an instance of that entity, containing a list of the users currently in the room and a history of the messages sent to it. Each entity has a particular Entity type, which defines how the entity’s state is persisted, shared, and what its capabilities are.
An instance of an Entity. Entity instances are identified by an Entity key, which is unique to a given entity. An entity holds state in the User function, and depending on the Entity type this state is held within the context of a gRPC stream. When a command for a particular entity instance is received, the Proxy will make a new streamed gRPC call for that entity instance to the User function. All subsequent commands received for that entity instance will be sent through that streamed call.
An entity service is a gRPC service that allows interacting with an Entity. The Proxy makes this service available for other Kubernetes services and ingresses to consume, while the User function provides the implementation of the entity business logic. Note that the service is not implemented directly, by the user function like a normal gRPC service. Rather, it is implemented through the Cloudstate Protocol, which enriches the incoming and outgoing gRPC messages with state management capabilities, such as the ability to receive and update state.
A key used to identify instances of an Entity. All Commands must contain the entity key so that the command can be routed to the right instance of the entity that the command is for. The gRPC descriptor for the Entity service annotates the incoming message types for the entity to indicate which field(s) contain the entity key.