{{announcement.body}}
{{announcement.title}}

Deploy Quarkus Faster in the Cloud with Platform.sh. Part 5

DZone 's Guide to

Deploy Quarkus Faster in the Cloud with Platform.sh. Part 5

How to deploy a Quarkus application with a command mode Application in the cloud with Platform.sh

· Java Zone ·
Free Resource

Quarkus is, in its own words, a Cloud Native, (Linux) Container First framework for writing Java applications. It has become popular because of the amazingly fast boot time, incredibly low RSS memory. In this series of articles about Quarkus, we'll teach you how to deploy Quarkus application with a command mode Application in the cloud with Platform.sh.

The goal of the 'command mode application is to execute custom actions when the application starts and clean up everything when the application stops.

This application will create a name analysis application, where via rest, we can create the name, and we'll use a command mode application to create an anagram every five minutes.

The first step is to create the application itself, and Quarkus has proper documentation. You have either a Maven Archetype or the start code link where you can define the dependencies that you need to write your application.

In the maven project, we either add manually or from the start site the Hibernate Panache ORM, Hibernate Search,  JDBC driver, and the data source dependency. The maven dependency will be the same of the Quarkus part 3.

We need to configure the application to run locally to test it.

Properties files
 




xxxxxxxxxx
1
10
9


 
1
quarkus.datasource.db-kind=postgresql
2
quarkus.datasource.username=quarkus_test
3
quarkus.datasource.password=quarkus_test
4
quarkus.datasource.jdbc.url=jdbc:postgresql://localhost/quarkus_test
5
quarkus.datasource.jdbc.max-size=8
6
quarkus.datasource.jdbc.min-size=2
7
 
          
8
quarkus.hibernate-orm.database.generation=update
9
quarkus.hibernate-orm.log.sql=true



If you want to run a PostgreSQL locally, a good option might be a Docker, that you can run with the command below:

Shell
 




xxxxxxxxxx
1


 
1
docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name quarkus_test -e POSTGRES_USER=quarkus_test -e POSTGRES_PASSWORD=quarkus_test -e POSTGRES_DB=quarkus_test -p 5432:5432 postgres:10.5



The infrastructure code is ready; the next step is to create the application itself. In this sample, we'll create a small rest-application to store cars where we have a plate, make, and model. Therefore, we'll create a Name entity.

Java
 




xxxxxxxxxx
1
33


1
import io.quarkus.hibernate.orm.panache.PanacheEntity;
2
 
          
3
import javax.persistence.Column;
4
import javax.persistence.Entity;
5
 
          
6
@Entity
7
public class NameAnalysis extends PanacheEntity {
8
 
          
9
    @Column(length = 40, unique = true)
10
    public String name;
11
 
          
12
    @Column(length = 40, unique = true)
13
    public String anagram;
14
 
          
15
    public boolean executed;
16
 
          
17
 
          
18
    public void execute() {
19
        this.anagram = new StringBuilder(this.name).reverse().toString();
20
        this.executed = true;
21
        this.persist();
22
    }
23
 
          
24
    @Override
25
    public String toString() {
26
        return "NameAnalysis{" +
27
                "name='" + name + '\'' +
28
                ", anagram='" + anagram + '\'' +
29
                ", executed=" + executed +
30
                '}';
31
    }
32
}
33
 
          



The last step is to create a resource where the client can do request and then the CRUD. As we can see, with Panache, we can reduce a lot of complexity of the code.

Java
 




x


 
1
import io.quarkus.panache.common.Sort;
2
import org.jboss.resteasy.annotations.jaxrs.PathParam;
3
 
          
4
import javax.enterprise.context.ApplicationScoped;
5
import javax.transaction.Transactional;
6
import javax.ws.rs.Consumes;
7
import javax.ws.rs.DELETE;
8
import javax.ws.rs.GET;
9
import javax.ws.rs.POST;
10
import javax.ws.rs.PUT;
11
import javax.ws.rs.Path;
12
import javax.ws.rs.Produces;
13
import javax.ws.rs.WebApplicationException;
14
import javax.ws.rs.core.MediaType;
15
import javax.ws.rs.core.Response;
16
import java.util.List;
17
 
          
18
@Path("names")
19
@ApplicationScoped
20
@Produces(MediaType.APPLICATION_JSON)
21
@Consumes(MediaType.APPLICATION_JSON)
22
public class NameResource {
23
 
          
24
    @GET
25
    public List<NameAnalysis> get() {
26
        return NameAnalysis.listAll(Sort.ascending("name"));
27
    }
28
 
          
29
    @GET
30
    @Path("{id}")
31
    public NameAnalysis getSingle(@PathParam Long id) {
32
 
          
33
        NameAnalysis entity = NameAnalysis.findById(id);
34
        if (entity == null) {
35
            throw new WebApplicationException("Name with id of " + id + " does not exist.", Response.Status.NOT_FOUND);
36
        }
37
        return entity;
38
    }
39
 
          
40
    @POST
41
    @Transactional
42
    public Response create(NameAnalysis nameAnalysis) {
43
        nameAnalysis.persist();
44
        return Response.ok(nameAnalysis).status(Response.Status.CREATED).build();
45
    }
46
 
          
47
    @PUT
48
    @Path("{id}")
49
    @Transactional
50
    public NameAnalysis update(@PathParam Long id, NameAnalysis nameAnalysis) {
51
 
          
52
        NameAnalysis entity = NameAnalysis.findById(id);
53
        if (entity == null) {
54
            throw new WebApplicationException("Name with id of " + id + " does not exist.", Response.Status.NOT_FOUND);
55
        }
56
 
          
57
        entity.name = nameAnalysis.name;
58
        entity.executed = false;
59
        entity.persist();
60
 
          
61
        return entity;
62
    }
63
 
          
64
    @DELETE
65
    @Path("{id}")
66
    @Transactional
67
    public Response delete(@PathParam Long id) {
68
        boolean deleted = NameAnalysis.deleteById(id);
69
        if (deleted) {
70
            return Response.status(Response.Status.NO_CONTENT).build();
71
        }
72
        throw new WebApplicationException("Name with id of " + id + " does not exist.", Response.Status.NOT_FOUND);
73
    }
74
 
          
75
}
76
 
          



The rest application side is ready; the next step is to create a service to find the name that is not analyzed to create an anagram with the name.

Java
 




x


1
import io.quarkus.hibernate.orm.panache.PanacheQuery;
2
import io.quarkus.panache.common.Page;
3
 
          
4
import javax.enterprise.context.ApplicationScoped;
5
import javax.transaction.Transactional;
6
import java.util.logging.Logger;
7
 
          
8
@ApplicationScoped
9
public class AnagramService {
10
 
          
11
    private static final Logger LOGGER = Logger.getLogger(AnagramService.class.getName());
12
 
          
13
 
          
14
    @Transactional
15
    public void executeAnagram() {
16
        LOGGER.info("Starting the anagram analysis");
17
 
          
18
        PanacheQuery<NameAnalysis> living = NameAnalysis.find("executed", false);
19
        final PanacheQuery<NameAnalysis> page = living.page(Page.ofSize(20));
20
 
          
21
        LOGGER.info("The total number of entities returned by this query without paging: " + page.count());
22
        LOGGER.info("The number of pages: " + page.pageCount());
23
        boolean hasNext = true;
24
 
          
25
        while (hasNext) {
26
            page.stream().forEach(NameAnalysis::execute);
27
            if (hasNext = page.hasNextPage()) {
28
                page.nextPage();
29
            }
30
        }
31
        LOGGER.info("Finished the anagram analysis");
32
    }
33
}
34
 
          



The service has been ready, the next step is to create a Command mode application to execute this service.

Java
 




x


 
1
import io.quarkus.runtime.QuarkusApplication;
2
import io.quarkus.runtime.annotations.QuarkusMain;
3
 
          
4
import javax.inject.Inject;
5
 
          
6
@QuarkusMain(name = "anagram")
7
public class AnagramApp  implements QuarkusApplication {
8
 
          
9
    @Inject
10
    AnagramService service;
11
 
          
12
    @Override
13
    public int run(String... args){
14
        service.executeAnagram();
15
        return 0;
16
    }
17
}
18
 
          



The application is ready to go, you can run the test the application. The next step is to move to the cloud with Platform.sh.

To move your application to the cloud, briefly, you need three files:

YAML
 




xxxxxxxxxx
1


 
1
"https://{default}/":
2
  type: upstream
3
  upstream: "app:http"
4
 
          
5
"https://www.{default}/":
6
  type: redirect
7
  to: "https://{default}/"
8
 
          



Platform.sh allows you to completely define and configure the topology and services you want to use on your project.

YAML
 




xxxxxxxxxx
1


 
1
db:
2
  type: postgresql:11
3
  disk: 512



One or more application containers (.platform.app.yaml). You control your application and the way it will be built and deployed on Platform.sh via a single configuration file. This application will grand permission to access PostgreSQL.

YAML
 




xxxxxxxxxx
1
20


 
1
name: app
2
 
          
3
type: "java:11"
4
disk: 1024
5
 
          
6
hooks:
7
    build: ./mvnw package -DskipTests -Dquarkus.package.uber-jar=true
8
 
          
9
relationships:
10
    database: "db:postgresql"
11
 
          
12
crons:
13
    anagram:
14
        spec: '*/5 * * * *'
15
        cmd: java $JAVA_OPTS $CREDENTIAL -cp target/command-mode-1.0-SNAPSHOT-runner.jar org.acme.hibernate.orm.BatchApp
16
 
          
17
web:
18
    commands:
19
        start: java -jar $JAVA_OPTS $CREDENTIAL -Dquarkus.http.port=$PORT target/command-mode-1.0-SNAPSHOT-runner.jar
20
 
          



We'll start the command mode application thanks to Platform.sh Cron jobs that allow you to run scheduled tasks at specified times or intervals. The crons section of  .platform.app.yaml  describes these tasks and the schedule when they are triggered. Each item in the list is a unique name identifying a separate cron job. Crons are started right after build phase.

To simplify the application file, we'll use Shell variables int the  .environment  file.

Shell
 




xxxxxxxxxx
1


 
1
export HOST=`echo $PLATFORM_RELATIONSHIPS|base64 -d|jq -r ".database[0].host"`
2
export PASSWORD=`echo $PLATFORM_RELATIONSHIPS|base64 -d|jq -r ".database[0].password"`
3
export USER=`echo $PLATFORM_RELATIONSHIPS|base64 -d|jq -r ".database[0].username"`
4
export DATABASE=`echo $PLATFORM_RELATIONSHIPS|base64 -d|jq -r ".database[0].path"`
5
export JDBC=jdbc:postgresql://${HOST}/${DATABASE}
6
export JAVA_MEMORY=-Xmx$(jq .info.limits.memory /run/config.json)m
7
export JAVA_OPTS="$JAVA_MEMORY -XX:+ExitOnOutOfMemoryError"
8
export CREDENTIAL="-Dquarkus.datasource.username=$USER -Dquarkus.datasource.password=$PASSWORD -Dquarkus.datasource.jdbc.url=$JDBC"



The application is now ready, so it’s time to move it to the cloud with Platform.sh using the following steps:

  • Create a new free trial account.
  • Sign up with a new user and password, or login using a current GitHub, Bitbucket, or Google account. If you use a third-party login, you’ll be able to set a password for your Platform.sh account later.
  • Select the region of the world where your site should live.
  • Select the blank template.

You have the option to either integrate to GitHubGitLab, or Platform.sh will provide to you. Finally, push to the remote repository.

Done! We have a simple and nice Quarkus application ready to go to the cloud.



Topics:
cloud computing ,java ,paas ,platform.sh ,quarkus

Opinions expressed by DZone contributors are their own.

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

{{ parent.tldr }}

{{ parent.urlSource.name }}