Hot questions for Using Cassandra in lagom

Question:

I'm trying to configure my first Entity with Cassandra and Lagom.

I'm asking about how Lagom save the entity in Cassandra?

For example, this is my UserServiceImpl class:

public class UserServiceImpl implements UserService {

    private final PersistentEntityRegistry persistentEntityRegistry;

    @Inject
    public UserServiceImpl(PersistentEntityRegistry persistentEntityRegistry) {
        this.persistentEntityRegistry = persistentEntityRegistry;
        persistentEntityRegistry.register(UserEntity.class);
    }

    @Override
    public ServiceCall<NotUsed, String> getUserInfo(String id) {
        return (request) -> {
            // Look up the user entity for the given ID.
            PersistentEntityRef<UserCommand> ref = persistentEntityRegistry.refFor(UserEntity.class, id);
            // Ask the entity the Hello command.
            return ref.ask(new UserCommand.Hello(id, Optional.empty()));
        };
    }
}

So by executing:

persistentEntityRegistry.register(UserEntity.class);

Should I have a user table into Cassandra? because I only have:

I can't understand should I create the table user before starting my Lagom project or we only save the event?

Any help, please


Answer:

Lagom does not require a table for the entity because it's not based on an object-relational mapping or anything similar. Its persistence layer is based on the principles of Event Sourcing.

The messages table will contain the events that are emitted by your entity and its state is recovered each time you bring it back into memory.

Basically, the events are being saved in json format in the messages table.

We also have the concept of snapshots. The entity state may be saved as a snapshot (also using json). This happens after every 100 events and it's a small optimization to avoid to replay the events from scratch each time.

I'll try to explain shortly the whole mechanism.

A command is sent to an entity and events are persisted (that happens in the command handler). After the events are persisted, they are applied to the entity to mutate it (that happens on the event handler).

You restart the service and send a new command to that same entity. At that point the entity is not in memory, so Lagom will bring it into memory but before handling that new command it will replay the history of events for this entity in order to bring it back to the state it had when the system went down.

After that, the command is applied and new events are persisted.

After 100 events a snapshot of the entity will be saved and next time, when it's needed to replay that same entity, we load first the snapshot and then we apply the events that took place after the snapshot. So, in that case we don't need to replay the whole event history.

Question:

In order to have a complete control on the components of my architecture, I'd like to deploy all the infrastructure components (Service Locator, Cassandra, Kafka) and services individually.

I'm able to run a service with a command as follows: mvn lagom:startServiceLocator lagom:startCassandra -pl hello-impl lagom:run

However, when I start these components individually (i.e. by mvn lagom:startServiceLocator), the started component terminates automatically. In this case, I see the following logs but the locator is not available at http://localhost:9008.

I'm on a local development environment with no proxy and using the default configurations.

How can I run those individually?


Answer:

Java/Maven: If you want to run several Lagom microservices, you just need to do what you was doing:

mvn lagom:startServiceLocator lagom:startCassandra -pl hello-impl lagom:run

It will start locator, cassandra, if you need you can add kafka, after that, you just run in new cmd following command:

mvn -pl second-lagom-microservice-impl lagom:run

Now it will connect to running in first command cassandra and locator.

Lagom does not allow you to run cassandra or locator without running service.

Scala/Sbt:

For sbt the same approach, we need to run first microservice with all needed services:

sbt lagomServiceLocatorStart lagomCassandraStart lagomKafkaStart microservice-impl/run

Then just run another like: **sbt another-microservice-impl/run**

Also, you can add an alias in build.sbt for your microservice to run it individually:

addCommandAlias(s"runMicrocervice1", ";lagomServiceLocatorStart;lagomCassandraStart;lagomKafkaStart;microservice1-impl/run")

And just run it as:

sbt runMicrocervice1