函数服务#

openYuanrong 提供了函数服务能力,支持 openYuanrong 函数以 Serverless 服务方式运行,使用 HTTP 请求访问。服务实例随请求并发量全自动弹性伸缩,无请求时缩容到 0。函数服务定义了 Handler 方法作为请求处理入口,其签名如下。

  • handler:方法名称,可自定义。

  • event:函数服务的请求参数,包含请求头,请求体等数据,格式为 JSON 对象。

  • context:由 openYuanrong 运行时提供的上下文信息,接口介绍详见函数服务 Python SDK

def handler(event, context)
  • handler:方法名称,可自定义。

  • event:函数服务的请求参数,包含请求头,请求体等数据,格式为 string。

  • context:由 openYuanrong 运行时提供的上下文信息,接口介绍详见函数服务 C++ SDK

std::string HandleRequest(const std::string &event, Function::Context &context) 
  • handler:方法名称,可自定义。

  • event:函数服务的请求参数,包含请求头,请求体等数据,格式为 JSON 对象。

  • context:由 openYuanrong 运行时提供的上下文信息,接口介绍详见函数服务 Java SDK

public String handler(JsonObject event, Context context)

Handler 方法返回值为字符串,以下是一个完整的方法示例:

import datetime

# 服务执行入口,每次请求都会执行
def handler(event, context):
   print("received request,event content:", event)

   response = ""
   try:
      name = event.get("name")
      # 获取配置的环境变量,环境变量在注册和更新函数时设置
      show_date = context.getUserData("show_date")
      if show_date is not None:
            response = "hello " + name + ",today is " + datetime.date.today().strftime('%Y-%m-%d')
      else:
            response = "hello " + name
   except Exception as e:
      print(e)
      response = "please enter your name,for example:{'name':'yuanrong'}"

   return response
#include <string>
#include <ctime>
#include <nlohmann/json.hpp>

#include "Runtime.h"
#include "Function.h"
#include "yr/yr.h"

std::string HandleRequest(const std::string &event, Function::Context &context) {
    std::cout << "received request,event content:" << event << std::endl;
    std::string response = "";
    try {
        nlohmann::json jsonData = nlohmann::json::parse(event);
        // 读取 JSON 数据并输出
        std::string name = jsonData["name"];
        response += "hello ";
        response += name;
            
        std::string showDate = context.GetUserData("show_date");
        if (showDate != "") {
            time_t now = time(0);
            tm *ltm = localtime(&now);
                
            std::stringstream timeStr;
            timeStr << ltm->tm_year + 1900 << "-";
                timeStr << ltm->tm_mon + 1 << "-";
                timeStr << ltm->tm_mday;
            response += ",today is ";
            response += timeStr.str();
        }
    } catch (const std::exception& e) {
        std::cout << "JSON parsing error:" << e.what() << std::endl;
        response = "please enter your name,for example:{'name':'yuanrong'}";
    }
    return response;
}

int main(int argc, char *argv[])
{
    Function::Runtime rt;
    // 同时需要在 main() 函数中注册该方法
    rt.RegisterHandler(HandleRequest);
    rt.Start(argc, argv);
    return 0;
}
import com.services.runtime.Context;
import com.google.gson.JsonObject;
import java.time.LocalDate;

public String handler(JsonObject event, Context context) {
    System.out.println("received request,event content:" + event);
    String response = "";
    try {
    String name = event.get("name").getAsString();
    // 获取配置的环境变量,环境变量在注册和更新函数时设置
    String showDate = context.getUserData("show_date");
        if (showDate != null) {
            response = "hello " + name + ",today is " + LocalDate.now();
        } else {
            response = "hello " + name;
        }
    } catch(Exception e) {
        e.printStackTrace();
        response = "please enter your name,for example:{'name':'yuanrong'}";
    }
    return response;       
}

查看部署 openYuanrong 服务类应用了解如何部署函数服务。

函数生命周期回调#

在函数实例生命周期事件发生时,可以触发相应的回调方法,包括 Initializer 和 PreStop。回调方法可根据实际业务需要选择是否实现。

Initializer 回调#

初始化(Initializer) 回调方法在函数实例启动之后,请求处理方法(Handler)之前执行。在函数实例生命周期内,成功且只成功执行一次。如果初始化方法执行失败,发送到该函数实例的请求将直接返回失败,实例自动被系统回收。

初始化方法可用于处理后端建链等逻辑,在配置单个函数实例可处理多个并发的场景,请求间可复用链路,避免重复建链,降低处理时延。

Initializer 回调方法的签名如下:

  • initializer:方法名称,可自定义。

  • context:由 openYuanrong 运行时提供的上下文信息,接口介绍详见函数服务 Python SDK

def initializer(context)
  • Initializer:方法名称,可自定义。

  • context:由 openYuanrong 运行时提供的上下文信息,接口介绍详见函数服务 C++ SDK

void Initializer(Function::Context &context)
  • initializer:方法名称,可自定义。

  • context:由 openYuanrong 运行时提供的上下文信息,接口介绍详见函数服务 Java SDK

public void initializer(Context context) 

Initializer 方法无返回值,一个简单的示例如下:

def initializer(context):
   print("function instance initialization completed")
std::string HandleRequest(const std::string &event, Function::Context &context) {
    return "ok";
}

void Initializer(Function::Context &context) {
    std::cout << "function instance initialization completed" << std::endl;
    return;
}

int main(int argc, char *argv[])
{
    Function::Runtime rt;
    rt.RegisterHandler(HandleRequest);
    // 同时需要在 main() 函数中注册该方法
    rt.RegisterInitializerFunction(Initializer);
    rt.Start(argc, argv);
    return 0;
}
public void initializer(Context context) {
    System.out.println("function instance initialization completed");
}

PreStop 回调#

预停止(PreStop)回调方法在函数实例退出前执行,可用于断开链路,保存持久化数据等操作。

PreStop 回调方法的签名如下:

  • pre_stop:方法名称,可自定义。

def pre_stop()
  • PreStop:方法名称,可自定义。

void PreStop(Function::Context &context) 
  • preStop:方法名称,可自定义。

public void preStop(Context context)

PreStop 方法无返回值,一个简单的示例如下:

def pre_stop():
   print("function instance is being destroyed")
std::string HandleRequest(const std::string &event, Function::Context &context) {
    return "ok";
}

void PreStop(Function::Context &context) {
    std::cout << "function instance is being destroyed" << std::endl;
}

int main(int argc, char *argv[])
{
    Function::Runtime rt;
    rt.RegisterHandler(HandleRequest);
    // 同时需要在 main() 函数中注册该方法
    rt.RegisterPreStopFunction(PreStop);
    rt.Start(argc, argv);
    return 0;
}
public void preStop(Context context) {
    System.out.println("function instance is being destroyed");
}

函数日志#

函数的各方法往标准输出 stdout 打印的日志会被 openYuanrong 收集存储,你可以使用以下方式打印日志。

使用 openYuanRong 的日志记录器#

您可通过上下文方法 getLogger() 打印日志,将获得和 openYuanrong 组件一样的输出格式。每条日志中都包含时间、请求 ID 和日志级别等信息。一个简单的示例如下。

def handler(event, context):
    context.getLogger().info("hello world")
    return 'ok'
std::string HandlerRequest(const std::string &event, Function::Context &context) {
    Function::FunctionLogger logger = context.GetLogger();
    logger.setLevel("INFO");
    logger.Info("hello world");
    return "ok";
}

int main(int argc, char *argv[])
{
    Function::Runtime rt;
    // 同时需要在 main() 函数中注册该方法
    rt.RegisterHandler(HandleRequest);
    rt.Start(argc, argv);
    return 0;
}
public String handler(JsonObject event, Context context) {
    context.getLogger().info("hello world");
    return "ok";
}

运行函数,预期输出的日志内容如下。

2025-xx-xx xx:xx:xx xxxxxxxx-xxxx-xxxx-xxxx-xxxxx****xx [INFO] hello world

使用编程语言的日志输出函数#

使用编程语言日志输出函数打印的日志,内容将原样输出到日志文件中。一个简单的示例如下。

def handler(event, context):
    print('hello world')
    return 'ok'
std::string HandlerRequest() {
    std::cout << "hello world" << std::endl;
    return "ok";
}

int main(int argc, char *argv[])
{
    Function::Runtime rt;
    // 同时需要在 main() 函数中注册该方法
    rt.RegisterHandler(HandleRequest);
    rt.Start(argc, argv);
    return 0;
}
public String handler() {
    System.out.println("hello world");
    return "ok";
}

运行服务,预期输出的日志内容如下。

hello world

实例弹性策略#

openYuanrong 支持基于并发度的弹性策略,当并发度达到配置的单实例并发度时,触发函数实例扩容。函数实例 1 分钟内无请求处理时,触发缩容,函数实例可缩容到 0。

实例调度#

openYuanrong 会根据函数指定的资源量和配置的调度策略选择合适节点运行它。详情请参阅调度章节。

请求调度#

openYuanrong 支持为函数配置不同的请求调度策略,包括 concurrency、 round-robin 和 microservice 。

  • concurrency:调度策略即为根据当前实例的并发度情况完成调度,请求会被优先调度到并发度较低的实例上。

  • round-robin:调度策略即轮询调度,请求会被轮流分配给不同的实例。

  • microservice:调度策略代表您没有为单个函数指定调度策略,具体使用什么调度策略将在 openYuanrong 集群部署时指定。

更多使用方式#