The English version of quarkus.io is the official project site. Translated sites are community supported on a best-effort basis.

Funqy

Quarkus Funqy is part of Quarkus’s serverless strategy and aims to provide a portable Java API to write functions deployable to various FaaS environments like AWS Lambda, Azure Functions, Google Cloud Functions, Knative, and Knative Events (Cloud Events). It is also usable as a standalone service.

Because Funqy is an abstraction that spans multiple different cloud/function providers and protocols it has to be a very simple API and thus, might not have all the features you are used to in other remoting abstractions. A nice side effect though is that Funqy is as optimized and as small as possible. This means that because Funqy sacrifices a little on flexibility, you’ll get a framework that has little to no overhead.

Funqy の基礎

Funqy API はシンプルです。メソッドに @Funq をアノテーションします。このメソッドはオプションの入力パラメータを1つだけ持つことができ、レスポンスを返すこともあれば返さないこともあります。

import io.quarkus.funqy.Funq;

public class GreetingFunction {
    @Funq
    public String greet(String name) {
       return "Hello " + name;
    }
}

Javaクラスは入力と出力としても使用でき、Java Bean の規約に従う必要があり、デフォルトのコンストラクタを持たなければなりません。パラメータや戻り値の型として宣言されたJavaの型は、Funqyのランタイムが期待する型です。Funqyは起動時間を短縮するためにビルド時に型のイントロスペクションを行いますので、派生型は実行時にFunqyのマーシャリング層に意識されません。

POJO を入出力タイプとして使用した例をご紹介します。

public class GreetingFunction {
    public static class Friend {
        String name;

        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
    }

    public static class Greeting {
        String msg;

        public Greeting() {}
        public Greeting(String msg) { this.msg = msg }

        public String getMessage() { return msg; }
        public void setMessage(String msg) { this.msg = msg; }
    }

    @Funq
    public Greeting greet(Friend friend) {
       return new Greeting("Hello " + friend.getName());
    }
}

非同期リアクティブ型

Funqyは戻り値の型として Smallrye Mutiny Uni リアクティブ型をサポートしています。唯一の要件は、 Uni がジェネリック型を保持しなければならないことです。

import io.quarkus.funqy.Funq;
import io.smallrye.mutiny.Uni;

public class GreetingFunction {

    @Funq
    public Uni<Greeting> reactiveGreeting(String name) {
       ...
    }
}

Function 名

The function name defaults to the method name and is case-sensitive. If you want your function referenced by a different name, parameterize the @Funq annotation as follows:

import io.quarkus.funqy.Funq;

public class GreetingFunction {

    @Funq("HelloWorld")
    public String greet(String name) {
       return "Hello " + name;
    }
}

Funqy DI

各Funqy JavaクラスはQuarkus Arcコンポーネントであり、CDIまたはSpring DIによる依存性注入をサポートしています。Spring DIでは、ビルドに quarkus-spring-di 依存関係を含める必要があります。

Funqy クラスのデフォルトのオブジェクトライフサイクルは @Dependent です。

import io.quarkus.funqy.Funq;

import javax.inject.Inject;
import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class GreetingFunction {

    @Inject
    GreetingService service;

    @Funq
    public Greeting greet(Friend friend) {
        Greeting greeting = new Greeting();
        greeting.setMessage(service.greet(friend.getName()));
        return greeting;
    }
}

コンテキスト注入

The Funqy API will usually not allow you to inject or use abstractions that are specific to a protocol (i.e. HTTP) or function API (i.e. AWS Lambda). There are exceptions to the rule though, and you may be able to inject contextual information that is specific to the environment you are deploying in.

ランタイムに固有のコンテキスト情報を注入することはお勧めしません。 Function を移植性の高いものにしてください。

Contextual information is injected via the @Context annotation which can be used on a function parameter or a class field. A good example is the io.quarkus.funqy.knative.events.CloudEvent interface that comes with our Funqy Knative Cloud Events integration:

import io.quarkus.funqy.Funq;
import io.quarkus.funqy.Context;
import io.quarkus.funqy.knative.events.CloudEvent;

public class GreetingFunction {

    @Funq
    public Greeting greet(Friend friend, @Context CloudEvent eventInfo) {
        System.out.println("Received greeting request from: " eventInfo.getSource());

        Greeting greeting = new Greeting();
        greeting.setMessage("Hello " + friend.getName()));
        return greeting;
    }
}

Funqy を使うべきか?

REST over HTTP has become a very common way to write services over the past decade. While Funqy has an HTTP binding it is not a replacement for REST. Because Funqy has to work across a variety of protocols and function cloud platforms, it is very minimalistic and constrained. For example, if you use Funqy you lose the ability to link (think URIs) to the data your functions spit out. You also lose the ability to leverage cool HTTP features like cache-control and conditional GETs. Many developers will be ok with that as many won’t be using these REST/HTTP features or styles. You’ll have to make the decision on what camp you are in. Quarkus does support REST integration (through JAX-RS, Spring MVC, Vert.x Web, and Servlet) with various cloud/function providers, but there are some disadvantages of using that approach as well. For example, if you want to do HTTP with AWS Lambda, this requires you to use the AWS API Gateway which may slow down deployment and cold start time or even cost you more.

The purpose of Funqy is to allow you to write cross-provider functions so that you can move off of your current function provider if, for instance, they start charging you a lot more for their service. Another reason you might not want to use Funqy is if you need access specific APIs of the target function environment. For example, developers often want access to the AWS Context on Lambda. In this case, we tell them they may be better off using the Quarkus Amazon Lambda integration instead.