Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Going the Microservices Way – Part 3

DZone's Guide to

Going the Microservices Way – Part 3

Here's the third part of our microservices exploration, with a focus on deploying required changes on Heroku.

· Integration Zone
Free Resource

Share, secure, distribute, control, and monetize your APIs with the platform built with performance, time-to-value, and growth in mind. Free 90 day trial 3Scale by Red Hat

In the first post of this serie, I created a simple microservice based on a Spring Boot + Data JPA stack to display a list of available products in JSON format. In the second part, I demoed how this app could be uploaded on Pivotal Cloud Foundry. In this post, I’ll demo the required changes to deploy on Heroku.

Heroku

As for PCF, Heroku requires a local dedicated app. For Heroku, it’s called the Toolbelt. Once installed, one needs to login on one’s account through the toolbelt:

heroku login

The next step is to create the application on Heroku. The main difference between Cloud Foundry and Heroku is that the former deploys ready binaries while Heroku builds them from source. Creating the Heroku app will also create a remote Git repository to push to, as Heroku uses Git to manage code.

heroku create
Creating salty-harbor-2168... done, stack is cedar-14
https://salty-harbor-2168.herokuapp.com/ | https://git.heroku.com/salty-harbor-2168.git
Git remote heroku added

The heroku create command also updates the .git config by adding a new heroku remote. Let’s push to the remote repository:

Counting objects: 21, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (21/21), 2.52 KiB | 0 bytes/s, done.
Total 21 (delta 1), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> Java app detected
remote: -----> Installing OpenJDK 1.8... done
remote: -----> Installing Maven 3.3.3... done
remote: -----> Executing: mvn -B -DskipTests=true clean install
remote:        [INFO] Scanning for projects...
// Here the app is built remotely with Maven
remote:        [INFO] ------------------------------------------------------------------------
remote:        [INFO] BUILD SUCCESS
remote:        [INFO] ------------------------------------------------------------------------
remote:        [INFO] Total time: 51.955 s
remote:        [INFO] Finished at: 2015-10-03T09:13:31+00:00
remote:        [INFO] Final Memory: 32M/473M
remote:        [INFO] ------------------------------------------------------------------------
remote: -----> Discovering process types
remote:        Procfile declares types -> (none)
remote: 
remote: -----> Compressing... done, 74.8MB
remote: -----> Launching... done, v5
remote:        https://salty-harbor-2168.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy.... done.
To https://git.heroku.com/salty-harbor-2168.git
 * [new branch]      master -> master

At this point, one need to tell Heroku how to launch the newly built app. This is done through a Procfile located at the root of the project. It should contain an hint to Heroku that we are using a web application – reachable through http(s), and the standard Java command-line. Also, the web port should be bound an Heroku documented environment variable:

web: java -Dserver.port=$PORT -jar target/microservice-sample.jar

The application doesn’t work yet as the log will tell you. To display the remote log, type:

heroku logs --tail

There should be something like that:

Web process failed to bind to $PORT within 60 seconds of launch

That hints that a web node is required, or in Heroku’s parlance, a dyno. Let’s start one:

heroku ps:scale web=1

The application should now be working at https://salty-harbor-2168.herokuapp.com/products (you should be patient, since it’s a free plan, the app is probably sleeping). Yet, something is still missing: it’s still running on the embedded H2 database. We should switch to a more resilient database. By default, Heroku provides a PostgreSQL development database for free. Creating such a database can be done either through the user interface or the command-line.

Spring Boot documentation describes the Spring Cloud Connectors library. It’s able to automatically detect the app is running on Heroku and to create a datasource bound to the Postgres database provided by Heroku. However, despite my best effort, I haven’t been able to make this work, running each time into the following:

org.springframework.cloud.CloudException: No unique service matching interface javax.sql.DataSource found. Expected 1, found 0

Time to get a little creative. Instead of sniffing the database and its configuration, let’s configure it explicitly. This requires creating a dedicated profile configuration properties file for Heroku, src/main/resources/application-heroku.yml:

spring:
    datasource:
        url: jdbc:postgresql://<url>
        username: <username>
        password: <password>
        driver-class-name: org.postgresql.Driver
    jpa:
        database-platform: org.hibernate.dialect.PostgreSQLDialect

The exact database connection settings you can find in the Heroku user interface. Note the dialect seems to be required. Also, the POM should be updated to add the Postgres driver to the dependencies.

Finally, to activate the profile on Heroku, change the Procfile as such:

web: java -Dserver.port=$PORT -Dspring.profiles.active=heroku -jar target/microservice-sample.jar

Commit and push to Heroku again, the application should be updated to use the provided Postgres.

Next week, I’ll create a new shopping bag microservice that depend on this one and design for failure.

Discover how you can achielve enterpriese agility with microservices and API management

Topics:
ei ,enterprise integration ,integration ,microservices ,heroku

Published at DZone with permission of Nicolas Frankel, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}