Funqy

Quarkus Funqy 是 Quarkus 的无服务器策略的一部分,旨在提供一个可移植的 Java API 来编写可部署到各种 FaaS 环境(如 AWS Lambda、Azure Functions、Google Cloud Functions、Knative 和 Knative Events(云事件))的函数。它还可以用作独立服务。 由于 Funqy 是一个跨越多个不同云/功能提供商和协议的抽象,因此它必须是一个非常简单的 API,因此可能不具有在其他远程调用抽象中使用的所有功能。然而,一个好的副作用是 Funqy 进行了尽可能的优化,并且尽可能精简。这意味着由于 Funqy 在灵活性方面做出了小小的牺牲,因此可以获得开销很小或没有开销的框架。

Funqy Basics

Funqy API 很简单。使用 `@Funq`为方法添加注解。此方法只能有一个可选输入参数,并且可以返回响应,也可以不返回响应。

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());
    }
}

Async Reactive Types

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 Names

函数名称默认为方法名,并区分大小写。如果您想通过不同的名称引用函数,请按如下方式对 @Funq 注解进行参数化:

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 jakarta.inject.Inject;
import jakarta.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;
    }
}

Context injection

Funqy API 通常不允许您注入或使用特定于协议(例如 HTTP)或函数 API(例如 AWS Lambda)的抽象。不过规则也有例外,您也许能够注入与您所部署的环境相关的上下文信息。

我们不建议注入特定于运行时的上下文信息。保持函数的可移植性。

上下文信息通过 @Context 方式注入,可在函数参数或类字段上使用。一个很好的示例是我们的 FunqyKnative 云事件集成附带的 io.quarkus.funqy.knative.events.CloudEvent 接口:

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;
    }
}

Should I Use Funqy?

在过去十年中,通过 HTTP 的 REST 已成为编写服务的一种非常常见的方法。虽然 Funqy 有一个 HTTP 绑定,但它并不能替代 REST。由于 Funqy 必须跨越各种协议和函数云平台,因此它非常极简且受限。例如,如果您使用 Funqy,您将失去将数据链接到函数输出的链接(认为是 URI)的能力。您还失去了利用类似 cache-control 和条件 GET 等酷炫 HTTP 特性的能力。许多开发者可以接受,因为许多人不会使用这些 REST/HTTP 特性或样式。您必须决定您属于哪种阵营。Quarkus 确实支持通过各种云/函数提供程序进行 REST 集成(通过 Jakarta REST、Spring MVC、Vert.x Web 和 Servlet),但使用这种方法也有一些缺点。例如,如果您想执行 HTTP with AWS Lambda,则要求您使用可能减缓部署和冷启动时间甚至增加成本的 AWS API Gateway。

Funqy 的目的是让您能够编写跨提供程序的函数,以便如果您当前的函数提供程序开始对他们的服务向您收取更多费用,则您可以将其取消。您可能不想使用 Funqy 的另一个原因是,如果您需要访问目标函数环境的特定 API。例如,开发人员通常希望访问 Lambda 上的 AWS Context。在这种情况下,我们会告诉他们可能最好改用 Quarkus AWS Lambda 集成。