Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Funqy Google Cloud Function #9655

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci-actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,13 @@ jobs:
java :
- { name: Java8,
java-version: 8,
maven_args: "-pl !integration-tests/vault-app,!integration-tests/vault-agroal,!integration-tests/vault,!integration-tests/google-cloud-functions-http,!integration-tests/gradle,!integration-tests/google-cloud-functions"
maven_args: "-pl !integration-tests/vault-app,!integration-tests/vault-agroal,!integration-tests/vault,!integration-tests/google-cloud-functions-http,!integration-tests/gradle,!integration-tests/google-cloud-functions,!integration-tests/funqy-google-cloud-functions"
}
- {
name: "Java 8 - 242",
java-version: 8,
release: "jdk8u242-b08",
maven_args: "-pl !integration-tests/google-cloud-functions-http,!integration-tests/gradle,!integration-tests/google-cloud-functions"
maven_args: "-pl !integration-tests/google-cloud-functions-http,!integration-tests/gradle,!integration-tests/google-cloud-functions,!integration-tests/funqy-google-cloud-functions"
}
- {
name: Java 11,
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/native-cron-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
run: mvn -B install -DskipTests -DskipITs -Dformat.skip

- name: Run integration tests in native
run: mvn -B --settings .github/mvn-settings.xml verify -f integration-tests/pom.xml --fail-at-end -Dno-format -Ddocker -Dnative -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-native-image:20.1.0-java${{ matrix.java }} -Dtest-postgresql -Dtest-elasticsearch -Dtest-mysql -Dtest-db2 -Dtest-amazon-services -Dtest-vault -Dtest-neo4j -Dtest-keycloak -Dtest-kafka -Dtest-mssql -Dtest-mariadb -Dmariadb.url="jdbc:mariadb://localhost:3308/hibernate_orm_test" -pl '!io.quarkus:quarkus-integration-test-google-cloud-functions-http,!io.quarkus:quarkus-integration-test-google-cloud-functions'
run: mvn -B --settings .github/mvn-settings.xml verify -f integration-tests/pom.xml --fail-at-end -Dno-format -Ddocker -Dnative -Dquarkus.native.container-build=true -Dquarkus.native.builder-image=quay.io/quarkus/ubi-quarkus-native-image:20.1.0-java${{ matrix.java }} -Dtest-postgresql -Dtest-elasticsearch -Dtest-mysql -Dtest-db2 -Dtest-amazon-services -Dtest-vault -Dtest-neo4j -Dtest-keycloak -Dtest-kafka -Dtest-mssql -Dtest-mariadb -Dmariadb.url="jdbc:mariadb://localhost:3308/hibernate_orm_test" -pl '!io.quarkus:quarkus-integration-test-google-cloud-functions-http,!io.quarkus:quarkus-integration-test-google-cloud-functions,!integration-tests/funqy-google-cloud-function'

- name: Report
if: always()
Expand Down
7 changes: 6 additions & 1 deletion bom/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1344,7 +1344,12 @@
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-amazon-lambda-deployment</artifactId>
<artifactId>quarkus-funqy-google-cloud-functions</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-google-cloud-functions-deployment</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
Expand Down
268 changes: 268 additions & 0 deletions docs/src/main/asciidoc/funqy-gcp-functions.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
////
This guide is maintained in the main Quarkus repository
and pull requests should be submitted there:
https://github.com/quarkusio/quarkus/tree/master/docs/src/main/asciidoc
////
= Quarkus - Funqy Google Cloud Functions
:extension-status: experimental

include::./attributes.adoc[]

The guide walks through quickstart code to show you how you can deploy Funqy functions to Google Cloud Functions.

As the Google Cloud Function Java engine is a new Beta feature of Google Cloud, this extension is flagged as experimental.

include::./status-include.adoc[]

== Prerequisites

To complete this guide, you need:

* less than 30 minutes
* JDK 11 (Google Cloud Functions requires JDK 11)
* Apache Maven {maven-version}
* https://cloud.google.com/[A Google Cloud Account]. Free accounts work.
* https://cloud.google.com/sdk[Cloud SDK CLI Installed]

== Login to Google Cloud

Login to Google Cloud is necessary for deploying the application and it can be done as follows:

[source, subs=attributes+]
----
gcloud auth login
----

At the time of this writing, Cloud Functions are still in beta so make sure to install the `beta` command group.

[source, subs=attributes+]
----
gcloud components install beta
----

== The Code

There is nothing special about the code and more importantly nothing Google Cloud specific. Funqy functions can be deployed to many different
environments and Google Cloud Functions is one of them.

[[choose]]
== Choose Your Function

Only one Funqy function can be exported per Google Cloud Functions deployment. If you only have one method
annotated with `@Funq` in your project, then there is no worries. If you have multiple functions defined
within your project, then you will need to choose the function within your Quarkus `application.properties`:

[source, subs=attributes+]
----
quarkus.funqy.export=greet
----

Alternatively, you can set the `QUARKUS_FUNQY_EXPORT` environment variable when you create the Google Cloud Function using the `gcloud` cli.

== Build and Deploy

Build the project using maven.

[source, subs=attributes+]
----
./mvnw clean package
----

This will compile and package your code.


== Create the function

In this example, we will create two background functions. Background functions allow to
react to Google Cloud events like PubSub messages, Cloud Storage events, Firestore events, ...

[source,java]
----
import javax.inject.Inject;

import io.quarkus.funqy.Funq;
import io.quarkus.funqy.gcp.functions.event.PubsubMessage;
import io.quarkus.funqy.gcp.functions.event.StorageEvent;

public class GreetingFunctions {

@Inject
GreetingService service;

@Funq // <1>
public void helloPubSubWorld(PubsubMessage pubSubEvent) {
String message = service.hello("world");
System.out.println(pubSubEvent.messageId + " - " + message);
}

@Funq // <2>
public void helloGCSWorld(StorageEvent storageEvent) {
String message = service.hello("world");
System.out.println(storageEvent.name + " - " + message);
}

}
----

NOTE: Function return type can also be Mutiny reactive types.

1. This is a background function that takes as parameter a `io.quarkus.funqy.gcp.functions.event.PubsubMessage`,
this is a convenient class to deserialize a PubSub message.
2. This is a background function that takes as parameter a `io.quarkus.funqy.gcp.functions.event.StorageEvent`,
this is a convenient class to deserialize a Google Storage event.

NOTE: we provide convenience class to deserialize common Google Cloud event inside the `io.quarkus.funqy.gcp.functions.event` package.
They are not mandatory to use, you can use any object you want.

As our project contains multiple function, we need to specify which function needs to be deployed via the following property inside our `application.properties` :

[source,property]
----
quarkus.funqy.export=helloHttpWorld
----

== Build and Deploy to Google Cloud

To build your application, you can package your application via `mvn clean package`.
You will have a single JAR inside the `target/deployment` repository that contains your classes and all your dependencies in it.

Then you will be able to use `gcloud` to deploy your function to Google Cloud, the `gcloud` command will be different depending from which event you want to be triggered.

[WARNING]
====
The first time you launch the `gcloud beta functions deploy`, you can have the following error message:
```
ERROR: (gcloud.beta.functions.deploy) OperationError: code=7, message=Build Failed: Cloud Build has not been used in project <project_name> before or it is disabled. Enable it by visiting https://console.developers.google.com/apis/api/cloudbuild.googleapis.com/overview?project=<my-project> then retry.
```
This means that Cloud Build is not activated yet. To overcome this error, open the URL shown in the error, follow the instructions and then wait a few minutes before retrying the command.
====

=== Background Functions - PubSub

Use this command to deploy to Google Cloud Functions:

[source]
----
gcloud beta functions deploy quarkus-example-funky-pubsub \
--entry-point=io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction \
--runtime=java11 --trigger-resource hello_topic --trigger-event google.pubsub.topic.publish \
--source=target/deployment
----

The entry point always needs to be `io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction` as it will be this class
that will bootstrap Quarkus.

The `--trigger-resource` option defines the name of the PubSub topic, and the `--trigger-event google.pubsub.topic.publish` option
define that this function will be triggered by all message publication inside the topic.

To trigger an event to this function, you can use the `gcloud functions call` command:

[source]
----
gcloud functions call quarkus-example-funky-pubsub --data '{"data":"Hello, Pub/Sub"}'
----

The `--data '{"data":"Hello, Pub/Sub"}'` option allow to specify the message to be send to PubSub.

=== Background Functions - Cloud Storage

Before deploying your function, you need to create a bucket.

[source]
----
gsutil mb gs://quarkus-hello
----

Then, use this command to deploy to Google Cloud Functions:

[source]
----
gcloud beta functions deploy quarkus-example-funky-storage \
--entry-point=io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction \
--runtime=java11 --trigger-resource quarkus-hello --trigger-event google.storage.object.finalize \
--source=target/deployment
----

The entry point always needs to be `io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction` as it will be this class
that will bootstrap Quarkus.

The `--trigger-resource` option defines the name of the Cloud Storage bucket, and the `--trigger-event google.storage.object.finalize` option
define that this function will be triggered by all new file inside this bucket.

To trigger an event to this function, you can use the `gcloud functions call` command:

[source]
----
gcloud functions call quarkus-example-funky-pubsub --data '{"name":"test.txt"}'
----

The `--data '{"name":"test.txt"}'` option allow to specify a fake file name, a fake Cloud Storage event will be created for this name.

You can also simply add a file to Cloud Storage using the command line of the web console.

== Testing locally

The easiest way to locally test your function is using the Cloud Function invoker JAR.

You can download it via Maven using the following command:

[source]
----
mvn dependency:copy \
-Dartifact='com.google.cloud.functions.invoker:java-function-invoker:1.0.0-beta1' \
-DoutputDirectory=.
----

Then you can use it to launch your function locally, again, the command depends on the type of function and the type of events.

=== Background Functions - PubSub

For background functions, you launch the invoker with a target class of `io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction`.

[source]
----
java -jar java-function-invoker-1.0.0-beta1.jar \
--classpath target/funqy-google-cloud-functions-1.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
----

Then you can call your background function via an HTTP call with a payload containing the event:

[source]
----
curl localhost:8080 -d '{"data":{"data":"hello"}}'
----

This will call your PubSub background function with a PubSubMessage `{"data":"hello"}`.

=== Background Functions - Cloud Storage

For background functions, you launch the invoker with a target class of `io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction`.

[source]
----
java -jar java-function-invoker-1.0.0-beta1.jar \
--classpath target/funqy-google-cloud-functions-1.0-SNAPSHOT-runner.jar \
--target io.quarkus.funqy.gcp.functions.FunqyBackgroundFunction
----

Then you can call your background function via an HTTP call with a payload containing the event:

[source]
----
curl localhost:8080 -d '{"data":{"name":"text"}}'
----

This will call your PubSub background function with a Cloud Storage event `{"name":"file.txt"}`, so an event on the `file.txt` file.


== Deploying HTTP Functions via Funqy

You can use link:funqy-http[Funqy HTTP] on Google Cloud Functions.
This allows you to invoke on multiple Funqy functions using HTTP deployed as one Google Cloud Function.

For this you need to include both `quarkus-funqy-http` and `quarkus-google-cloud-functions` extension.

== What's next?

If you are looking for JAX-RS, Servlet or Vert.x support for Google Cloud Functions, we have it thanks to our link:gcp-functions-http[Google Cloud Functions HTTP binding].
5 changes: 5 additions & 0 deletions docs/src/main/asciidoc/gcp-functions-http.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -203,3 +203,8 @@ java -jar java-function-invoker-1.0.0-beta1.jar \
----

Your endpoints will be available on http://localhost:8080.

== What's next?

You can use our link:funqy-gcp-functions[Google Cloud Functions Funqy binding] to use Funqy,
a provider agnostic function as a service framework, that allow to deploy HTTP function or Background function to Google Cloud.
48 changes: 48 additions & 0 deletions extensions/funqy/funqy-google-cloud-functions/deployment/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>quarkus-funqy-google-cloud-functions-parent</artifactId>
<groupId>io.quarkus</groupId>
<version>999-SNAPSHOT</version>
<relativePath>../</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>quarkus-funqy-google-cloud-functions-deployment</artifactId>
<name>Quarkus - Funqy Google Cloud Functions - Deployment</name>

<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-server-common-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jackson-deployment</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-funqy-google-cloud-functions</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-extension-processor</artifactId>
<version>${project.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>

</project>
Loading