tyepbus: Service Composition (microservice w/ scala+akka)

Corey Auger
4 min readJan 13, 2019

PART 3

In the last post we looked at the code for a typebus service and how to build our API’s. This included a discussion about how typebus protects you against schema evolution. In this post I would like to explore how we get multiple servicies to communicate using the API’s we defined.

review: typebus

typebus is my mildly opinionated toolkit for building reactive microservices, abstracting away a publish/subscribe bus implementation. It provides a consistent way to create and advertise service definitions. These services in turn own their API and provide guarantees about how their API may evolve. If we think of the real world as a distributed system, then typebus is a set of stories or beliefs that each person holds so that we can highly organize our society (eg: the story of money). typebus aims to provide solutions to:

  • Faster to develop: providing templates that map to Domain Driven Design (DDD)
  • Better isolation and API ownership
  • Simpler gateway service design and public API implementations
  • Guarantees around schema evolution
  • Flexible deployment and scale options
  • Open and composable communication channel.
  • Tooling for support, visualization and debugging services

Service Composition

I would like to cover is how to create multiple services that can talk to one another. For this let’s keep the code we have created for our service above. The final service definition would look like this:

Make sure the we delete the other example DTO objects so that we are just left with a final data file that looks like the following:

From here make sure that we can compile and run the service. You should see log output that verifies the connection to zookeeper and the creation of a single node cluster.

Next we can generate another service, we will again use the template command for this.

> g8 git@github.com:coreyauger/typebus-service.git

This time just hit enter to choose all of the defaults values for the service. This should create a new service in

./awesome-service

Now what we want to show is how we could have our new “awesome-service” use the API of our “loan-service”. For this to be the case we will require the loan-service types. Since typebus is about fully decoupling your services from one another I provide a code generation feature that allows you to create the needed types and client. From within our “awesome-service” start sbt. When the sbt prompt has loaded we can run the following command:

sbt: awesome-service> runMain io.surfkit.typebus.gen.Main “loan-service”

After the generation service starts you will see some output in the console that should indicate that code gen was a success. You can now exit from sbt and take a look inside your “awesome-service” for the new types that were generated.

There are 2 things to point out here:

  • The first is that we have both the needed types to call the loan service.
  • The second is that there is an RPC style client that will return a Future[T] response type.

Messaging Patterns

There are a number of ways that you can now communicate with the “loan-service”. First, you could simply fire and forget a message for AddInterestToUserLoanLedger. From within our service definition you can do this by simply calling the publish( … ) method. The publish method comes in 2 variates.

The former allows you to call it with the type that you want to publish to the bus and tells typebus to take care of creating the EventMeta and routing info. The latter lets you pass in the PublishedEvent thus allowing you to define more advanced routing structure.

Another way that you can publish to the bus is through the bus actor. This is a actorRef that you could potentially pass in to other actors allowing them to publish events straight onto the bus. Your service template gave you access to this actor with the following line.

This actor expects to receive messages of type PublishedEvent. It then forwards these messages on to the bus. Here is an example usage:

One could setup a handler for a response type in our service and those kick of a command that would result in that event. You can imagine cases where you initiate a Command and then listen for the final output produced after a large orchestration of service routines.

Another message pattern that is very useful is the RPC client. This is an asynchronous client that returns a Future[T] response type. Since you get a Future it is simple to compose these clients into large compositions of multiple service types. To use the client we first need to create an instance of one. We can then call it and simply map over the returned Future.

What’s Next?

We covered a lot of ground in this post, but there are still a number of features and tools to explore still. One thing that I want to cover in a follow up post is how we can leverage Event Sourcing and CQRS to make our design even more flexible and scalable. Another thing that was not talked about is the support tooling included with typebus. I have created a web based cluster management and debugging tool called “Telemetry”. This tool has visualizations, event trigger, and tracing built in. Thanks for reading :)

References

Lightbend Reactive Architecture: https://www.lightbend.com/learn/lightbend-reactive-architecture

--

--