×

在您创建了 Quarkus 函数项目之后,您可以修改提供的模板文件,以向您的函数添加业务逻辑。这包括配置函数调用以及返回的标头和状态码。

先决条件

Quarkus 函数模板结构

使用 Knative (kn) CLI 创建 Quarkus 函数时,项目目录看起来类似于典型的 Maven 项目。此外,项目包含 func.yaml 文件,用于配置函数。

httpevent 触发函数具有相同的模板结构。

模板结构
.
├── func.yaml (1)
├── mvnw
├── mvnw.cmd
├── pom.xml (2)
├── README.md
└── src
    ├── main
    │   ├── java
    │   │   └── functions
    │   │       ├── Function.java (3)
    │   │       ├── Input.java
    │   │       └── Output.java
    │   └── resources
    │       └── application.properties
    └── test
        └── java
            └── functions (4)
                ├── FunctionTest.java
                └── NativeFunctionIT.java
1 用于确定镜像名称和注册表。
2 项目对象模型 (POM) 文件包含项目配置,例如有关依赖项的信息。您可以通过修改此文件来添加其他依赖项。
附加依赖项示例
...
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.assertj</groupId>
      <artifactId>assertj-core</artifactId>
      <version>3.8.0</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
...

依赖项在第一次编译期间下载。

3 函数项目必须包含用 @Funq 注解的 Java 方法。您可以将此方法放在 Function.java 类中。
4 包含可用于在本地测试函数的简单测试用例。

关于调用 Quarkus 函数

您可以创建一个响应云事件的 Quarkus 项目,或者创建一个响应简单 HTTP 请求的项目。Knative 中的云事件通过 HTTP 以 POST 请求的形式传输,因此任何一种函数类型都可以监听和响应传入的 HTTP 请求。

收到传入请求时,将使用允许类型的实例调用 Quarkus 函数。

表 1. 函数调用选项
调用方法 实例中包含的数据类型 数据示例

HTTP POST 请求

请求正文中的 JSON 对象

{ "customerId": "0123456", "productId": "6543210" }

HTTP GET 请求

查询字符串中的数据

?customerId=0123456&productId=6543210

CloudEvent

data 属性中的 JSON 对象

{ "customerId": "0123456", "productId": "6543210" }

以下示例显示一个函数,该函数接收并处理上表中列出的 customerIdproductId 购买数据。

示例 Quarkus 函数
public class Functions {
    @Funq
    public void processPurchase(Purchase purchase) {
        // process the purchase
    }
}

包含购买数据的相应 Purchase JavaBean 类如下所示:

示例类
public class Purchase {
    private long customerId;
    private long productId;
    // getters and setters
}

调用示例

以下示例代码定义了三个名为 withBeanswithCloudEventwithBinary 的函数;

示例
import io.quarkus.funqy.Funq;
import io.quarkus.funqy.knative.events.CloudEvent;

public class Input {
    private String message;

    // getters and setters
}

public class Output {
    private String message;

    // getters and setters
}

public class Functions {
    @Funq
    public Output withBeans(Input in) {
        // function body
    }

    @Funq
    public CloudEvent<Output> withCloudEvent(CloudEvent<Input> in) {
        // function body
    }

    @Funq
    public void withBinary(byte[] in) {
        // function body
    }
}

Functions 类的 withBeans 函数可以通过以下方式调用:

  • 具有 JSON 主体的 HTTP POST 请求

    $ curl "https://127.0.0.1:8080/withBeans" -X POST \
        -H "Content-Type: application/json" \
        -d '{"message": "Hello there."}'
  • 具有查询参数的 HTTP GET 请求

    $ curl "https://127.0.0.1:8080/withBeans?message=Hello%20there." -X GET
  • 二进制编码的 CloudEvent 对象

    $ curl "https://127.0.0.1:8080/" -X POST \
      -H "Content-Type: application/json" \
      -H "Ce-SpecVersion: 1.0" \
      -H "Ce-Type: withBeans" \
      -H "Ce-Source: cURL" \
      -H "Ce-Id: 42" \
      -d '{"message": "Hello there."}'
  • 结构化编码的 CloudEvent 对象

    $ curl https://127.0.0.1:8080/ \
        -H "Content-Type: application/cloudevents+json" \
        -d '{ "data": {"message":"Hello there."},
              "datacontenttype": "application/json",
              "id": "42",
              "source": "curl",
              "type": "withBeans",
              "specversion": "1.0"}'

Functions 类的 withCloudEvent 函数可以使用 CloudEvent 对象调用,类似于 withBeans 函数。但是,与 withBeans 不同,withCloudEvent 不能使用普通的 HTTP 请求调用。

Functions 类的 withBinary 函数可以通过以下方式调用:

  • 二进制编码的 CloudEvent 对象

    $ curl "https://127.0.0.1:8080/" -X POST \
      -H "Content-Type: application/octet-stream" \
      -H "Ce-SpecVersion: 1.0"\
      -H "Ce-Type: withBinary" \
      -H "Ce-Source: cURL" \
      -H "Ce-Id: 42" \
      --data-binary '@img.jpg'
  • 结构化编码的 CloudEvent 对象

    $ curl https://127.0.0.1:8080/ \
      -H "Content-Type: application/cloudevents+json" \
      -d "{ \"data_base64\": \"$(base64 --wrap=0 img.jpg)\",
            \"datacontenttype\": \"application/octet-stream\",
            \"id\": \"42\",
            \"source\": \"curl\",
            \"type\": \"withBinary\",
            \"specversion\": \"1.0\"}"

CloudEvent 属性

如果您需要读取或写入 CloudEvent 的属性,例如typesubject,您可以使用CloudEvent<T>泛型接口和CloudEventBuilder构建器。<T>类型参数必须是允许的类型之一。

在下面的示例中,CloudEventBuilder用于返回处理购买的成功或失败结果。

public class Functions {

    private boolean _processPurchase(Purchase purchase) {
        // do stuff
    }

    public CloudEvent<Void> processPurchase(CloudEvent<Purchase> purchaseEvent) {
        System.out.println("subject is: " + purchaseEvent.subject());

        if (!_processPurchase(purchaseEvent.data())) {
            return CloudEventBuilder.create()
                    .type("purchase.error")
                    .build();
        }
        return CloudEventBuilder.create()
                .type("purchase.success")
                .build();
    }
}

Quarkus 函数返回值

函数可以返回允许类型列表中任何类型的实例。或者,它们可以返回Uni<T>类型,其中<T>类型参数可以是允许类型中的任何类型。

如果函数调用异步 API,则Uni<T>类型非常有用,因为返回的对象将以与接收对象相同的格式序列化。例如:

  • 如果函数接收 HTTP 请求,则返回的对象将发送到 HTTP 响应的正文中。

  • 如果函数接收二进制编码的CloudEvent对象,则返回的对象将发送到二进制编码的CloudEvent对象的data属性中。

以下示例显示一个获取购买列表的函数。

示例命令
public class Functions {
    @Funq
    public List<Purchase> getPurchasesByName(String name) {
      // logic to retrieve purchases
    }
}
  • 通过 HTTP 请求调用此函数会生成一个 HTTP 响应,该响应的正文中包含购买列表。

  • 通过传入的CloudEvent对象调用此函数会生成一个CloudEvent响应,其中data属性包含购买列表。

允许的类型

函数的输入和输出可以是voidStringbyte[]类型中的任何一种。此外,它们可以是基本类型及其包装器,例如intInteger。它们也可以是以下复杂对象:JavaBean、映射、列表、数组和特殊的CloudEvents<T>类型。

映射、列表、数组、CloudEvents<T>类型的<T>类型参数以及 JavaBean 的属性只能是此处列出的类型。

示例
public class Functions {
    public List<Integer> getIds();
    public Purchase[] getPurchasesByName(String name);
    public String getNameById(int id);
    public Map<String,Integer> getNameIdMapping();
    public void processImage(byte[] img);
}

测试 Quarkus 函数

可以在本地计算机上测试 Quarkus 函数。使用kn func create创建函数时创建的默认项目中,包含src/test/目录,其中包含基本的 Maven 测试。可以根据需要扩展这些测试。

先决条件
  • 您已创建了一个 Quarkus 函数。

  • 您已安装 Knative (kn) CLI。

步骤
  1. 导航到函数的项目文件夹。

  2. 运行 Maven 测试。

    $ ./mvnw test

覆盖存活性探针和就绪性探针值

您可以覆盖 Quarkus 函数的livenessreadiness探针值。这允许您配置对函数执行的健康检查。

先决条件
  • OpenShift Serverless Operator 和 Knative Serving 已安装在集群上。

  • 您已安装 Knative (kn) CLI。

  • 您已使用kn func create创建了一个函数。

步骤
  1. 使用您自己的值覆盖/health/liveness/health/readiness路径。您可以通过更改函数源代码中的属性或在func.yaml文件中设置QUARKUS_SMALLRYE_HEALTH_LIVENESS_PATHQUARKUS_SMALLRYE_HEALTH_READINESS_PATH环境变量来实现。

    1. 要使用函数源代码覆盖路径,请更新src/main/resources/application.properties文件中的路径属性。

      quarkus.smallrye-health.root-path=/health (1)
      quarkus.smallrye-health.liveness-path=alive (2)
      quarkus.smallrye-health.readiness-path=ready (3)
      1 根路径,它会自动添加到livenessreadiness路径的前面。
      2 存活性路径,此处设置为/health/alive
      3 就绪性路径,此处设置为/health/ready
    2. 要使用环境变量覆盖路径,请在func.yaml文件的build块中定义路径变量。

      build:
        builder: s2i
        buildEnvs:
        - name: QUARKUS_SMALLRYE_HEALTH_LIVENESS_PATH
          value: alive (1)
        - name: QUARKUS_SMALLRYE_HEALTH_READINESS_PATH
          value: ready (2)
      1 存活性路径,此处设置为/health/alive
      2 就绪性路径,此处设置为/health/ready
  2. 将新的端点添加到func.yaml文件,以便它们正确绑定到 Knative 服务的容器。

    deploy:
      healthEndpoints:
        liveness: /health/alive
        readiness: /health/ready

后续步骤