はじめに:「異なる言語間のRPCって、普通は大変では?」
マイクロサービスを運用した経験のある方なら共感いただけると思いますが、異なる言語で書かれたサービス同士を連携させるには、従来は次のような手間が必要でした。
- Protobuf や Thrift などの IDL を別途定義し
- スキーマ変更のたびに コード生成(Codegen) を回し直し
- 言語ごとに シリアライズ/デシリアライズ層 を個別に管理
今回Cloudflareが公開した クロスランゲージRPC は、この常識を根本から覆します。Python WorkerからTypeScript Workerのメソッドを await rpc.add(42, 144) の一行でそのまま呼び出せます。スキーマも、依存追加も、ビルドステップも不要です。
本記事では、この機能が なぜ実現できるのか、実務でどう活用できるのか、そして どこに注意すべきか を整理します。👉 根拠資料

核心:スキーマなしで言語をまたぐRPC
TypeScript Workerでメソッドを定義
import { WorkerEntrypoint } from "cloudflare:workers";
export class RpcService extends WorkerEntrypoint {
async add(a: number, b: number): Promise<number> {
// 2つの数値を足して返します。
return a + b;
}
}
Python Workerからそのまま呼び出す
from workers import Response, WorkerEntrypoint
class Default(WorkerEntrypoint):
async def fetch(self, request):
# TypeScript WorkerのRPCスタブを取得します。
rpc = self.env.RPC
# TypeScriptのRPCメソッドをそのまま呼び出します。
result = await rpc.add(42, 144)
return Response.json({"result": result})
Service bindingを追加するだけ
"services": [
{
"binding": "RPC",
"service": "ts-rpc-server",
"entrypoint": "RpcService"
}
]
はい、これだけです。Protobufも、スキーマのコード生成も、追加SDKのインストールも不要 です。
内部では何が起きているのか
鍵となるのは PyodideのFFI(Foreign Function Interface) です。Python WorkerはCPythonをWebAssemblyにコンパイルしたPyodide上で動作しており、このFFIがJavaScriptとPython間の型を自動変換します。
| Python型 | JavaScript型 |
|---|---|
int, float | Number |
bool | Boolean |
dict | Object |
list | Array |
datetime | Date |
直接変換できないカスタムクラスや関数は Proxyオブジェクト でラップされ、属性アクセスやメソッド呼び出しがそのまま転送されます。たとえばPython関数をJavaScriptのコールバックとして渡すようなパターンも自然に動作します。
キーワード引数もスマートにマッピングされます。JavaScript側で get(key, options?) として定義されたメソッドを、Pythonから JSRPC.get("myKey", type="text") のように呼び出すと、内部的に { type: "text" } オブジェクトへ変換されます。Python開発者はPythonらしく、JS開発者はJSらしく書けばよい設計です。

注意点:Web APIオブジェクトには専用SDKが必要です
Pyodide FFIは基本型を自動変換してくれますが、Request、Response、Blob、File といったWeb APIオブジェクトは自動変換の対象外 です。これらはCloudflare Workersで頻繁に使われる型ですが、Pythonにはネイティブの対応型が存在しません。
デフォルトの挙動では、これらのオブジェクトは JavaScript Proxyとしてラップされたまま 渡されます。そのため、Pythonコードの中にJS実装の詳細が漏れ出し、開発者のメンタルモデルが煩雑になります。
この問題を解決するために、Cloudflareは workers-runtime-sdk というPythonパッケージを提供しています。uv run pywrangler deploy でデプロイすると自動的に含まれ、from workers import Response のように workers 名前空間からインポートする時点で既に利用していることになります。
このSDKが言語境界を越えるオブジェクトをインターセプトし、両言語で自然に扱えるネイティブな形へ変換します。
実践例:PythonパッケージをJavaScriptから使う
JavaScriptアプリでPygments(Python製のシンタックスハイライター)を使いたい場合は次のとおりです。
// JavaScript Worker: Python Workerのメソッドを呼び出します。
export default {
async fetch(request, env) {
const rpc = env.PYTHON_RPC;
const result = await rpc.highlight_code('print(42)', 'python');
return Response.json(result);
}
}
# Python Worker: Pygmentsを使ってハイライトを実行します。
from workers import WorkerEntrypoint
from pygments.formatters import HtmlFormatter
from pygments import highlight
from pygments.lexers import get_lexer_by_name
class Default(WorkerEntrypoint):
async def highlight_code(self, code: str, language: str) -> dict:
# 指定された言語のレクサーを取得します。
lexer = get_lexer_by_name(language, stripall=True)
# フォーマッターを作成し、ハイライトを実行します。
formatter = HtmlFormatter(linenos=True, cssclass="highlight", style="monokai")
highlighted_html = highlight(code, lexer, formatter)
# スタイル用のCSSを取得します。
css = formatter.get_style_defs(".highlight")
return {"html": highlighted_html, "css": css}
JS Worker側の wrangler.jsonc にはService bindingを追加するだけです。
"services": [
{ "binding": "PYTHON_RPC", "service": "py-rpc-server" }
]
この技術の限界と注意事項
- RPCはほとんどの場合ネットワークを越えません。 同一スレッド上で動作するためパフォーマンスオーバーヘッドはほぼゼロですが、その分 Worker間の分離レベルが低い ことを意味します。障害分離(Fault Isolation)が必要な場合は別途設計が必要です。
- Python Workerのコールドスタート はPyodide(WASM)のロードがあるため、純粋なJS Workerより遅くなります。レイテンシに敏感な経路には不向きな場合があります。
- Pyodide FFIが捉えないカスタム型 は依然としてProxyとして渡されるため、予期しない箇所でJSオブジェクトのように振る舞う可能性があります。型ヒントを明確に記述する習慣が有効です。
- 両方のWorkerを別々のターミナルでdevサーバーとして起動する必要 があり、ローカル開発体験はまだ洗練されていません。
次のステップ学習の方向性
- 公式ドキュメントの Python Workers RPC ガイド を一通り確認し
- python-workers-examples リポジトリで実際のサンプルを動かしてみてください。
- Pyodide FFIの型マッピング規則を理解しておくと、デバッグ速度が大きく向上します。

まとめ:「言語の境界は、今やライブラリ呼び出しのように」
Cloudflare WorkersのクロスランゲージRPCは、スキーマ・コード生成・シリアライズ層なしで PythonとJavaScriptを一つのアプリケーションのように組み合わせる機能です。整理すると次のとおりです。
- Service binding + メソッド呼び出し だけで言語をまたぐRPCが成立
- Pyodide FFI が基本型を自動変換、カスタム型はProxyで転送
workers-runtime-sdkがWeb APIオブジェクトまで自然に扱えるようにする- 一方で コールドスタート、分離レベル、ローカルDX にはまだトレードオフが存在
併せて読みたい記事
- Ray on TPU, GKEで10分で始める実践ガイド(スライスバッチ付き) — 分散ワークロードをGKE上で動かす実践感覚を掴みたい方へ。
- 従来のソフトウェアテストは終わった — エージェンティック開発時代のJiTTest革命 — 言語の境界が消えるほど、テスト戦略も変わるべき理由。