Workers RPC 打通 Python 与 JavaScript:跨语言直接调用活对象

2026-08-03 54 预计阅读时间: 1 分钟
来源: blog.cloudflare.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

Workers RPC 的边界已经从同语言调用扩展到 Python 与 JavaScript 之间。一个编码代理可以实现 Python Worker,另一个负责 JavaScript Worker;运行时不仅能让两端调用方法,还能传递活对象引用,而不必先设计 HTTP API、维护 Schema 或编写序列化代码。

这项变化的重点不只是“少写几个接口”,而是把跨 Worker 协作从数据传输问题,改造成对象能力调用问题。

从传 JSON 变成传能力

传统跨语言服务通常围绕消息构建边界:调用方把对象压成 JSON,服务端解析字段、执行业务逻辑,再把结果序列化回来。随着系统演进,团队还要处理版本兼容、字段缺失、日期与大整数格式,以及错误码映射。

Workers RPC 提供的是另一种模型。Python Worker 可以返回一个活对象的引用,JavaScript Worker 持有这个引用后,能够继续调用对象公开的方法。引用背后的对象仍运行在原 Worker 中,并没有被复制到调用方进程。

可以把两种模型简化为:

HTTP/JSON:
JavaScript -> serialize -> network -> parse -> Python

Workers RPC:
JavaScript -> remote object reference -> Python method

因此,开发者不再需要为内部调用重复定义路由、请求体和响应体。对象公开的方法本身构成调用界面,运行时负责跨语言调用和引用传递。

这并不意味着接口设计消失了。方法名称、参数含义、返回对象的生命周期和错误语义,仍然是调用契约,只是契约不再集中写在 OpenAPI 或 JSON Schema 中。

活对象引用适合哪些场景

活对象引用特别适合带状态或需要多步交互的工作流。例如,Python Worker 创建一个分析会话,JavaScript Worker 随后向同一个会话追加数据、读取进度并取得结果。使用普通 HTTP 时,每次请求通常都要携带 session_id,服务端再查找对应状态;使用对象引用时,调用方可以直接保存会话对象并调用它的方法。

典型场景包括:

  • Python 承担模型推理、数据分析或科学计算,JavaScript 负责请求编排与 Web 响应。
  • 一个 Worker 创建任务、游标或会话对象,另一个 Worker连续执行多步操作。
  • 多个编码代理分别实现不同语言模块,通过对象接口完成集成。
  • 内部服务希望减少 DTO、路由和序列化样板代码。

边界也需要看清。远程对象调用仍然会产生网络延迟和运行时开销,不应把它当成本地对象使用。例如,对一万个元素逐个调用远程 add(),通常不如一次调用 add_batch(items)。接口应保持粗粒度,并避免在高频循环中跨 Worker 往返。

一个跨语言会话示例

下面是一个可改造的最小项目,用来展示 Python Worker 返回会话对象、JavaScript Worker继续调用其方法的结构。由于来源摘要没有给出具体 SDK 版本和部署配置,示例采用 Workers RPC 的概念性接口;请按当前运行时提供的 Python 基类、RPC 目标类型和服务绑定语法调整导入名称。

目录可以这样组织:

workers-rpc-demo/
├── python-worker/
│   └── src.py
└── javascript-worker/
    └── src.js

Python Worker 创建一个分析会话:

# python-worker/src.py
# 假设当前 Workers Python SDK 提供 WorkerEntrypoint 与 RpcTarget。
from workers import WorkerEntrypoint, RpcTarget


class AnalysisSession(RpcTarget):
    def __init__(self, name: str):
        self.name = name
        self.values = []

    async def add_batch(self, values: list[float]) -> int:
        self.values.extend(values)
        return len(self.values)

    async def summary(self) -> dict:
        count = len(self.values)
        total = sum(self.values)
        return {
            "name": self.name,
            "count": count,
            "average": total / count if count else None,
        }


class Default(WorkerEntrypoint):
    async def create_session(self, name: str) -> AnalysisSession:
        return AnalysisSession(name)

JavaScript Worker 通过服务绑定取得对象引用并继续调用:

// javascript-worker/src.js
export default {
  async fetch(request, env) {
    // PYTHON_WORKER 是绑定到 Python Worker 的服务名。
    const session = await env.PYTHON_WORKER.create_session("latency-check");

    await session.add_batch([18.2, 20.1, 17.8, 19.4]);
    const result = await session.summary();

    return Response.json(result);
  },
};

预期响应为:

{
  "name": "latency-check",
  "count": 4,
  "average": 18.875
}

部署时需要把 JavaScript Worker 的 PYTHON_WORKER 绑定指向 Python Worker。下面使用 YAML 表达与平台无关的配置意图;它是可改造的配置草案,不代表某个 CLI 的原生文件格式:

services:
  python-worker:
    language: python
    entrypoint: python-worker/src.py

  javascript-worker:
    language: javascript
    entrypoint: javascript-worker/src.js
    bindings:
      PYTHON_WORKER:
        service: python-worker

实际接入时,应将这段配置映射到当前部署工具支持的服务绑定格式,并确认平台是否要求显式导出 RPC 入口类。

不写 Schema,不等于没有契约

Workers RPC 省去了显式序列化层,但跨语言类型仍需谨慎选择。字符串、数字、布尔值、列表和普通对象通常最容易在两种语言之间形成稳定约定。语言专属类型则可能带来歧义,例如 Python 的任意精度整数、datetime、生成器,以及 JavaScript 的 BigIntSymbol 或带原型链的复杂实例。

项目中可以保留一组跨语言契约测试,而不必引入完整 Schema:

// contract-test.mjs
import assert from "node:assert/strict";

export async function verifyAnalysisService(service) {
  const session = await service.create_session("contract-test");
  const count = await session.add_batch([10, 20, 30]);
  const result = await session.summary();

  assert.equal(count, 3);
  assert.deepEqual(result, {
    name: "contract-test",
    count: 3,
    average: 20,
  });
}

还应明确远程对象何时失效、是否能跨请求保存、并发调用如何处理,以及异常会以什么形式传播。对于支付、审计或外部合作方接口,显式版本化的 HTTP API 和 Schema 往往仍然更合适,因为它们更容易独立验证、记录和长期兼容。

落地时检查这五件事

引入跨语言 Workers RPC 时,可以从一个内部、低风险的调用链开始,并逐项检查:

  1. 方法是否足够粗粒度,避免循环中的大量远程往返。
  2. 参数与返回值是否使用两种语言都能稳定表达的类型。
  3. 活对象引用的生命周期、并发行为和失效方式是否清楚。
  4. 超时、异常、重试是否会造成重复写入或状态不一致。
  5. 是否有跨语言契约测试覆盖方法签名和关键返回结构。

Workers RPC 让 Python 与 JavaScript Worker 可以按各自擅长的领域分工,同时保留接近对象调用的编程体验。它减少了内部接口的机械代码,但没有消除分布式系统的成本。把调用设计得粗粒度、明确对象生命周期,并用契约测试守住边界,才能真正获得跨语言 RPC 带来的开发效率。


相关推荐