Intro
Serverless is becoming an alternative way of creating and deploying some types of services due to the fast delivery and cost-efficient project management [1]. The way that serverless applications work allows for high availability with a cost-efficient delivery by “turning ON“ our application only when it is being requested and thus saving resources on “dead“ hours.
Java, as it was until recently, wasn’t adequately fit to handle fast boot-ups (needed to wake up the application) and low resource consumption (yes, serverless doesn’t mean there is no server. There is a server and one must pay for it and the resources it uses).
This is where Quarkus and Microprofile [3;4] come to the rescue allowing for a serverless service fully built on Java.
Function as a Service (FaaS) “is an event-driven computing execution model where developers write logic that is deployed in containers fully managed by a platform, then executed on demand.” [5]
Prerequisites
- Azure subscription and The Azure CLI
- Java JDK 7, 8, 11, 13, 15
- Maven v3
- A pinch of programming skills
Sample Application
We start off by having to have a service to deploy that fits the need for it to be FaaS [1;5]. For the sake of simplicity, this example will be a basic service where there is a 1-minute timer that reads an in-memory database (DB) and increments a row with the current timestamp. It should also provide a way of getting this information so it will have a microservice with an HTTP GET operation.
Time to replicate
Assuming you already have an Azure subscription it is expected to replicate this example in less than one hour.
Download Code Base
Access https://code.quarkus.io/ and start selecting the options and dependencies needed.
Group | com.example
Artifact | quarkus-functions-sample
Build Tool | Maven
Version | 1.0.0-Snapshot
Then we choose what dependencies we will need, do not worry if you miss dependencies here because you can always add them later.
So, for now, we know that we want azure functions, and we will need to create a REST service. Let’s also check if there is something for the timer as well. Let's start typing in the dependencies:
For REST, we choose RESTeasy JAX-rs
For Azure functions, we type “functions” and select the “Azure functions HTTP“
And let's try the scheduler for the timer
Last we also select the dependencies for the in-memory database.
Finally, we download the application (notice that they provide articles for you to read based on the selected dependencies )
We can see that there are many things configured therefore our job will be to code mostly
Hands-On
We start off by configuring the database, and the entities to access the data.
in the file:
src\main\resources\application.properties
add the following code:
quarkus.http.root-path=/api
quarkus.package.type=uber-jar
quarkus.datasource.db-kind=h2
quarkus.datasource.username=sa
quarkus.datasource.password=sa
quarkus.datasource.jdbc.url=jdbc:h2:mem:public;MODE=PostgreSQL
quarkus.hibernate-orm.database.generation=drop-and-create
And create a file [src/main/resources/import.sql] with the initial data:
INSERT INTO quafun
(id, current)
VALUES(1, '1615195937');
Check that you have all of these dependencies:
pom.xml
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-azure-functions-http</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jsonb</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-scheduler</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<!-- Hibernate ORM specific dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-panache</artifactId>
</dependency>
<!-- JDBC driver dependencies -->
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jdbc-h2</artifactId>
</dependency>
</dependencies>
On the java side we need a JPA entity and a repository to manage the data and an API class:
Quafun.java
@Entity(name = "quafun")
public class Quafun {
@Id
private long id;
private String current;
public Quafun() {
}
public Quafun(long nextLong, long currentTimeMillis) {
this.id = nextLong;
this.current = "" + currentTimeMillis;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getCurrent() {
return current;
}
public void setCurrent(String current) {
this.current = current;
}
}
QuafunRepo.java
@ApplicationScoped
public class QuafunRepo implements PanacheRepository<Quafun> {
}
A controller for the REST interface
QuafunController.java
@Path("/quarkus-function")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class QuafunController {
private static final Logger LOGGER = Logger.getLogger(QuafunController.class.getName());
@Inject
QuafunRepo repo;
@GET
public List<Quafun> getAll() {
LOGGER.info("[RETRIEVE-OPERATION] Get All Data");
return repo.findAll().list();
}
}
And a Scheduler to do an operation regularly.
QuafunScheduler.java
@ApplicationScoped
public class QuafunScheduler {
private static final Logger LOGGER = Logger.getLogger(QuafunScheduler.class.getName());
@Inject
QuafunRepo repo;
@Scheduled(every = "1m")
@Transactional
void updateRepo() {
LOGGER.info("[AUTO-OPERATION] Scheduller called");
Quafun quafun = new Quafun(new Random().nextLong(), System.currentTimeMillis());
repo.persist(quafun);
}
}
Beam me Up
The next step is to deliver our application to the cloud. There are several ways of achieving this, like terraform for example here [6], but for the sake of simplicity, this example will use Maven to deploy to Azure.
Link Maven to Azure
As we selected “Azure Functions HTTP“ for dependencies much of the needed information will be already placed in our pom.xml :
...
<properties>
<azure.functions.maven.plugin.version>1.3.2</azure.functions.maven.plugin.version>
<compiler-plugin.version>3.8.1</compiler-plugin.version>
<function>greeting</function>
<functionAppName>${artifactId}-<####INSERT-UUID_HERE####></functionAppName>
<functionAppRegion>westus</functionAppRegion>
<functionResourceGroup>java-functions-group</functionResourceGroup>
...
Deploy
Deploying is the easy part! We need to be logged in! Past this into a command line:
az login
and then we just tell our application to deploy itself:
mvn clean install azure-functions:deploy
if everything went fine we have :
And we may test it by calling the URL:
And watching the metrics and check our logging messages:
2021-03-31T11:04:04.514 [Information] INFO: [RETRIEVE-OPERATION] Get All Data
...
2021-03-31T11:04:33.017 [Information] INFO: [AUTO-OPERATION] Scheduller called
Happy coding!
From here on we are able to create and deploy functions with the full potential of Java.
Another topic to consider for functions and Java is the Funqy HTTP [7] which provides less overhead for functions.
#Koerber
Refs
[1] https://www.thoughtworks.com/radar/techniques/serverless-architecture
[6] https://www.maxivanov.io/deploy-azure-functions-with-terraform/
Top comments (0)