Where does it come from?
As you can read here, I have implemented for JVM Bloggers a mechanism posting on its Facebook page. At first, I started with a microservice idea, running externally from the application. During the work, this concept changed and the posting is a part of the core now.
However, it would be a shame to remove a code of microservice and not to publish it at all. So here it is – a short entry about a microservice publishing on a Facebook page.
The service receives messages containing data to be published. A source of them is Kafka – a distributed streaming platform. A connection to it is provided by Reactive Kafka allowing to consume messages in a form of a stream. The service listens on a topic that can be set up in the service’s configuration.
I have created a consumer working in “at-least once” delivery mode. This means when a message is consumed, its offset should be committed to Kafka topic. An interesting exercise would be implementing “Exactly-once” semantic, so a message is read by the service once and only once.
Posting a message
I have employed restfb library to connect to the Facebook. It contains
com.restfb.DefaultFacebookClient class that provides an API for publishing posts on Facebook pages.
A message is published with the following call:
You can find more details about required configuration and mechanics of posting on a Facebook page in my earlier post.
final FacebookType publishResponse = facebook.publish("me/feed", Post.class, postData.getParams());
A message content
The expected format of a message is JSON. It is a map of parameters of a Facebook post. When a message arrives it is parsed into a list of
An important note here – I assumed that all fields contained in a Kafka message are well-known to the Facebook protocol. A full list of available parameters can be found here.
What about post delivery failures? In a case of any of them, the attempt to post a message will be retried. I have used a Failsafe library to ensure failure handling. The tool provides an easy way to set up a retry policy. For the service the policy and its usage looks like the following:
private final RetryPolicy retryPolicy = new RetryPolicy().withMaxRetries(3).retryOn(Exception.class);
.onFailedAttempt(ex -> log.error("Sending new post failed.", ex))
.get(() -> facebookPublisher.publishPost(data));
Unit testing of the consumer
I wondered how can I test the consumption of messages provided by Reactive Kafka source. The main concern here was setting up Kafka and feeding it with some messages. As you can guess, there is a library for that already, i.e. kafka-junit.
It offers JUnit’s rule that starts a Kafka broker at the beginning of a test and shut it down at its end. With
com.github.charithe.kafka.KafkaHelper we can easily produce a message and send it to a specified topic. The library does exactly what I was looking for.
How to run
The service connects to Kafka on a topic specified in its configuration. Thus, you have to run a Kafka broker at first. The easiest way to do so is to run it from a Docker image. Here is a nice explanation how this can be done.
Next, it is the time to start the posting service. I have added a support of Docker to the project, so you can generate a Docker image and run the service based on it:
docker run -e PAGE_ID=... -e APP_SECRET=... -e ACCESS_TOKEN=... docker_image_id
Of course, you can still do this by simply calling the following from a command line:
java -Dfacebook.app.secret=$APP_SECRET -Dfacebook.user.access.token=$ACCESS_TOKEN -Dfacebook.page.id=$PAGE_ID -Dfacebook.app.id=$APP_ID -jar facebook-posting-service-0.1-all.jar
Does it work?
Having both – the Kafka server and the service – running, we can feed the
facebook-posting-service topic with a message. To do so, I have used
kafka-console-producer.sh and created a JSON message with some text and link.
What happened next? Here is a part of logs showing that the service posted the message:
And here is a screenshot from the Facebook page of JVM Bloggers:
The code is on Github. Feel free to use it and let me know how does it work 😉