跳到主要内容

Fory v1.3.0 发布

· 阅读需 5 分钟
杨朝坤
Apache Fory PMC Member

Apache Fory 团队很高兴宣布 1.3.0 版本正式发布。本版本包含来自 3 位贡献者的 8 个 PR,并继续改进各支持语言的跨语言运行时。请访问 Install 页面 获取各平台安装方式。

发布亮点

  • Python gRPC 代码生成现在默认使用 grpc.aio AsyncIO API;同步 grpcio 输出仍可通过 --grpc-python-mode=sync 显式启用。
  • Dart 加入生成式 gRPC service 支持:foryc --dart_out=... --grpc 现在会生成 package:grpc client、service base、method descriptor,以及基于 Fory 的 payload 序列化逻辑。
  • Compiler gRPC 文档在多个语言上进一步细化,包括更清晰的生成 service 依赖和传输行为说明。
  • 运行时继续增强安全性,加入远端 schema metadata 限制,并修复 Java aligned-varint 与 type-checker cache 相关问题。

Python Async gRPC 模式

Python gRPC 生成现在默认面向 AsyncIO。生成的 companion 使用 grpc.aio:servicer base 暴露 async def 方法,stub 搭配 grpc.aio.Channel 使用,streaming RPC 使用 async iterable。这让生成代码更适合现代 Python async service,同时仍保留既有 gRPC 支持中的 Fory-backed request/response 编码方式。

默认 async companion 生成命令如下:

foryc service.fdl --python_out=./generated/python --grpc

对于简单 unary service,生成代码对应的 async server 形态如下:

import asyncio

import grpc.aio

import demo_greeter
import demo_greeter_grpc


class Greeter(demo_greeter_grpc.GreeterServicer):
async def say_hello(self, request, context):
return demo_greeter.HelloReply(reply=f"Hello, {request.name}")


async def serve():
server = grpc.aio.server()
demo_greeter_grpc.add_servicer(Greeter(), server)
server.add_insecure_port("[::]:50051")
await server.start()
await server.wait_for_termination()


asyncio.run(serve())

Client 使用 grpc.aio channel,并 await 生成的 stub 方法:

import grpc
import grpc.aio

import demo_greeter
import demo_greeter_grpc


credentials = grpc.ssl_channel_credentials()
async with grpc.aio.secure_channel("api.example.com:443", credentials) as channel:
stub = demo_greeter_grpc.GreeterStub(channel)
reply = await stub.say_hello(demo_greeter.HelloRequest(name="Fory"))

已有同步应用仍可显式请求 sync companion:

foryc service.fdl --python_out=./generated/python --grpc --grpc-python-mode=sync

Sync 模式保持相同的生成 public name 和 <module>_grpc.py 文件名,但应用使用 grpc.server(...)、标准 grpc.Channel 实例,以及普通 def servicer 方法。

Dart gRPC 代码生成

Fory 1.3.0 为包含 service 定义的 schema 增加 Dart gRPC service 生成。Service 定义可以来自 Fory IDL、protobuf IDL 或 FlatBuffers rpc_service。生成代码使用标准 grpc-dart API 来处理 client、service base、method descriptor、call option、deadline、取消、metadata 和 status code;每个 request/response 对象则使用 Fory 序列化,而不是 protobuf message bytes。

在 Dart 应用中,除 Fory package 外,还需要加入 grpcbuild_runner

dependencies:
fory: ^1.3.0
grpc: ^4.0.0

dev_dependencies:
build_runner: ^2.4.0

生成 Dart model 和 gRPC companion:

foryc service.fdl --dart_out=./lib/generated --grpc
dart run build_runner build --delete-conflicting-outputs

对于 demo.greeter package,generator 会输出 model 文件、由 build_runner 生成的 serializer part,以及包含 GreeterServiceBaseGreeterClient<stem>_grpc.dart companion。生成的 client 和 service base 会在首次使用时自动安装该 schema 的 Fory module,因此 service 实现不需要为生成的 message type 单独手动注册。

Unary Dart server 使用 grpc-dart 的 Server 和生成的 service base:

import 'dart:io';

import 'package:grpc/grpc.dart';
import 'demo/greeter/greeter.dart';
import 'demo/greeter/greeter_grpc.dart';

class GreeterService extends GreeterServiceBase {

Future<HelloReply> sayHello(ServiceCall call, HelloRequest request) async {
return HelloReply()..reply = 'Hello, ${request.name}';
}
}

Future<void> main() async {
final server = Server.create(services: [GreeterService()]);
await server.serve(address: InternetAddress.loopbackIPv4, port: 50051);
}

生成的 Dart client 使用标准 ClientChannel,并返回 grpc-dart 调用类型:

import 'package:grpc/grpc.dart';
import 'demo/greeter/greeter.dart';
import 'demo/greeter/greeter_grpc.dart';

final channel = ClientChannel(
'localhost',
port: 50051,
options: const ChannelOptions(credentials: ChannelCredentials.insecure()),
);
final client = GreeterClient(channel);

final reply = await client.sayHello(HelloRequest()..name = 'Fory');
await channel.shutdown();

Dart 生成支持 unary、server-streaming、client-streaming 和 bidirectional streaming 四种 RPC 形态,并遵循 grpc-dart 约定。

Features

Bug Fix

Other Improvements

New Contributors

Full Changelog: https://github.com/apache/fory/compare/v1.2.0...v1.3.0