- Cloudflare Workers가 오픈 베타로 Python 작성을 지원하며, Pyodide를 오픈소스 Workers 런타임인 workerd에 직접 통합해 JavaScript 중심 모델을 확장함
- Python Workers는 Vectorize, Workers AI, R2, Durable Objects 등 기존 바인딩을 첫날부터 지원하고, FastAPI·Langchain·Numpy 같은 일부 Python 패키지를 import할 수 있음
- 구현 기반은 CPython의 WebAssembly 포트인 Pyodide이며, JavaScript와 Python 사이의 FFI로 Request, Response, Fetch API, Cloudflare 리소스 바인딩을 Python 코드에서 다룸
- Cloudflare는 배포 시점에 import를 실행하고 WebAssembly 선형 메모리 스냅샷을 만들어 Pyodide와 패키지 초기화 비용을 줄이며, 기본 Python Worker의 콜드 스타트를 1초 미만으로 낮춤
- Python 버전과 Pyodide·패키지 업데이트는 Compatibility Dates와 Compatibility Flags로 관리되며, 5년 지원 기간이 끝난 Python 릴리스에 머무는 Worker는 다음으로 오래된 Python 릴리스로 자동 이동됨
Python Workers 오픈 베타
- Cloudflare Workers에서 Python Workers를 오픈 베타로 사용할 수 있음
- 기존의 JavaScript 외 언어 지원과 달리, Python 구현체를 workerd 런타임에 직접 통합함
- 첫날부터 지원되는 Cloudflare 바인딩은 다음을 포함함
- Python Workers는 FastAPI, Langchain, Numpy 등 일부 인기 Python 패키지를 import할 수 있음
- 별도 빌드 단계나 외부 툴체인이 필요 없음
WebAssembly 컴파일만으로는 부족했던 부분
- Workers는 2018년부터 WebAssembly를 지원했고, 각 Worker는 Chrome과 같은 JavaScript 엔진인 V8 isolate에서 실행됨
- 원칙적으로 Python을 포함한 여러 언어는 WebAssembly나 JavaScript로 먼저 컴파일하면 Workers에서 실행 가능했음
- 실제 애플리케이션에는 “hello world” 실행 이상이 필요하며, 개발자가 익숙하게 쓰는 패키지 생태계 지원이 중요함
- Python Workers는 Workers에서 JavaScript 외 언어를 일급으로 지원하려는 초기 형태임
Python Worker 실행 흐름
- Pyodide가 workerd에 내장되면서 Python Worker는
on_fetch핸들러로 요청을 처리할 수 있음 wrangler.toml에서는.py파일을main으로 지정하고,compatibility_flags = ["python_workers"]를 설정함npx wrangler@latest dev실행 시 Workers 런타임이 다음을 처리함- compatibility date를 기준으로 필요한 Pyodide 버전을 결정함
- Worker용 isolate를 만들고 Pyodide를 자동 주입함
- Pyodide로 Python 코드를 제공함
- Python 실행 환경은 내부에서 처리되며, JavaScript Workers와 비슷하게 플랫폼이 제공함
Pyodide가 Workers에 맞는 이유
- Pyodide는 CPython을 WebAssembly로 포팅한 구현체이며, Python 코드를 다른 형식으로 사전 컴파일하지 않고 해석함
- 대부분의 Python 표준 라이브러리를 제공하고, JavaScript API를 Python에서 호출할 수 있는 외부 함수 인터페이스(FFI) 를 제공함
- 핵심 인터프리터와 각 네이티브 Python 모듈을 별도 WebAssembly 모듈로 빌드하고, 런타임에 동적 링크할 수 있도록 설계됨
- 같은 머신에서 실행되는 여러 Workers가 모듈의 코드 footprint를 공유할 수 있어, 머신당 수천 개 Workers를 실행하는 Cloudflare 환경에 중요함
- 대부분의 WebAssembly 대상 언어는 아직 동적 링크를 지원하지 않아, 각 애플리케이션이 자체 언어 런타임 사본을 포함하는 경우가 많음
Pyodide와 WebAssembly 동적 링크
- WebAssembly는 호스트 런타임과 분리된 샌드박스 환경이므로, 파일 읽기 같은 순수 계산 외 작업은 런타임 환경이 제공하고 모듈이 import해야 함
- LLVM의 WebAssembly 대상은 세 가지로 나뉨
wasm32-unknown-unknown: C 표준 라이브러리나 시스템 호출 인터페이스를 제공하지 않음wasm32-wasi: WASI 런타임이 구현하는 표준 시스템 인터페이스를 사용함wasm32-unknown-emscripten: 필요한 import를 정의하고 이를 구현하는 JavaScript 라이브러리를 함께 출력함
- Pyodide는 Emscripten을 사용해 CPython 인터프리터, Python-JavaScript FFI, WebAssembly로 컴파일된 서드파티 Python 패키지를 제공함
- 이 대상 중 Emscripten만 현재 동적 링크를 지원함
- WASI는 CPython이 사용하는
dlopen/dlsym동적 링크 추상화를 아직 지원하지 않음
Python과 JavaScript를 잇는 FFI
- Python Worker 예제는
from js import Response로 JavaScript의Response를 가져옴 - Pyodide의 FFI는 Python에서 모든 JavaScript 기능에 접근할 수 있게 해, Python Workers가 JavaScript Workers보다 기능 면에서 뒤처지는 문제를 줄임
- 문자열과 숫자 같은 불변 타입은 양 언어 사이에서 투명하게 변환되고, 변경 가능한 객체는 적절한 프록시로 감싸짐
- JavaScript 객체가 Python으로 전달되면 Pyodide는 해당 객체가 지원하는 JavaScript 프로토콜을 확인하고, 대응하는 Python 프로토콜을 구현하는 클래스를 동적으로 구성함
- JavaScript 반복 프로토콜을 지원하면 Python 반복 프로토콜도 지원함
- Promise나 thenable이면 Python에서는 awaitable 객체가 됨
- 요청 처리 흐름에서도 들어온 JavaScript
Request객체는 Python 코드에서 접근 가능한JsProxy로 감싸지고, Python 핸들러의 반환값은 JavaScriptResponse객체로 변환됨
동적 링크와 Python 패키지
- 많은 Python 패키지는 C FFI를 통해 네이티브 라이브러리를 가져오며, Workers 런타임에서 동작하려면 이 라이브러리들이 WebAssembly로 컴파일되어야 함
- Pyodide는 Emscripten으로 빌드되어 Python의 C FFI를 오버라이드하고, 패키지가 네이티브 라이브러리를 로드하려 할 때 Workers 런타임이 제공하는 WebAssembly 모듈을 로드함
- 동적 링크는 네이티브 라이브러리 의존성이 있는 여러 Python 패키지를 Pyodide가 지원할 수 있게 함
- 정적 링크는 바이너리 실행 전에 필요한 코드를 모두 로드해야 하지만, 동적 링크는 필요한 시점에 비용을 지불하는 방식임
- Workers는 각 Worker마다 런타임에 Python 배포판처럼 보이는 파일시스템을 생성하되, 기반 파일은 Workers 사이에서 공유함
- 현재는 파일을 Workers 사이에서 공유하지만 새 isolate마다 복사하며, 앞으로 copy-on-write 기법으로 underlying resource를 더 많이 공유할 수 있다고 봄
HTTP 클라이언트와 서버 라이브러리 지원
- Python에는 httpx, urllib3, requests 같은 HTTP 클라이언트 라이브러리가 많지만, Pyodide에서 기본 동작하지 않음
- 이 라이브러리들은 원시 소켓을 사용하고, 브라우저 보안 모델과 CORS는 이를 허용하지 않아 Workers 런타임에서는 다른 방식이 필요함
-
비동기 클라이언트
-
동기 클라이언트와 한계
- 많은 Python API는 동기식이며, 이 경우 비동기 Fetch API를 직접 사용할 수 없음
- urllib3에는 Pyodide 브라우저 지원을 위해
Atomics.wait()와 fetch worker thread, 또는 동기 XMLHttpRequest를 사용하는 기여가 들어감 - Cloudflare Workers는 현재 worker threads와 동기
XMLHttpRequest를 지원하지 않아, 이 두 접근 방식은 Python Workers에서 동작하지 않음 - 현재 동기 요청은 지원되지 않음
-
WebAssembly Stack Switching
- WebAssembly에는 스택 전환을 추가하는 stage 3 제안이 있고, V8에는 구현이 있음
- Pyodide 기여자들은 2022년 9월부터 stack switching 지원을 추가해 왔으며 거의 준비됨
- 이 지원이 들어가면 Pyodide의
run_sync가 awaitable 완료를 기다리도록 블록할 수 있어, 동기 요청 지원 경로가 생김
FastAPI와 ASGI
- FastAPI는 Python 서버 정의에 많이 쓰이는 라이브러리이며, ASGI 프로토콜을 사용함
- FastAPI 애플리케이션은 소켓을 직접 읽거나 쓰지 않고, 보통 uvicorn 같은 ASGI 서버가 원시 소켓 처리를 담당함
- 이 구조 덕분에 FastAPI 자체를 패치하거나 바꾸지 않고 Cloudflare Workers에서 동작할 수 있음
- Workers 안에서 실행 가능한 ASGI 서버로 uvicorn을 대체하면 됨
- 초기 구현은 workerd의 asgi.py에 있으며, Cloudflare가 유지하는 Pyodide fork에 포함됨
- Cloudflare는 기능을 더 갖추고 테스트 커버리지를 추가한 뒤 Pyodide에 upstream할 계획임
Python 패키지 가져오기
- Python Workers는 Pyodide가 직접 제공하는 일부 Python 패키지를 지원함
- 지원 패키지에는 numpy, httpx, FastAPI, Langchain 등이 포함됨
- 패키지를 가져오려면
requirements.txt에 버전 번호 없이 패키지 이름을 추가함 - 특정 패키지 버전은 Pyodide가 직접 제공함
- 현재는 로컬 개발에서 패키지를 사용할 수 있고, 몇 주 안에
requirements.txt의존성을 정의한 Workers 배포가 가능해질 예정임 - Cloudflare는 자체 Pyodide fork를 유지해 Workers 런타임 전용 패치를 제공하고, 변경 사항을 Pyodide upstream에 반영하겠다고 함
콜드 스타트와 메모리 스냅샷
- Pyodide 자체 크기는 6.4MB이며, Python 패키지도 클 수 있음
- Pyodide를 그대로 Worker에 넣어 Cloudflare에 업로드하면 새 isolate 로딩 비용이 커져 콜드 스타트가 느려짐
- 빠른 컴퓨터와 좋은 네트워크에서 Pyodide는 브라우저 초기화에 약 2초가 걸리며, 네트워크 1초와 CPU 1초가 소요됨
npx wrangler@latest deploy시 배포 과정은 다음처럼 동작함- Wrangler가 Python 코드와
requirements.txt를 Workers API에 업로드함 - Workers 런타임이 Python 코드와 의존성을 검증함
- 새 isolate를 만들고 Pyodide와 지정된 패키지를 자동 주입함
- Worker 코드의 import 문을 스캔하고 실행한 뒤, Worker의 WebAssembly 선형 메모리 스냅샷을 생성함
- 이 스냅샷과 Python 코드를 Cloudflare 네트워크에 배포함
- JavaScript Worker와 마찬가지로 top-level scope를 실행함
- Wrangler가 Python 코드와
- 요청이 들어오면 이 스냅샷을 로드해 isolate에서 Worker를 부트스트랩하므로 비싼 초기화 비용을 피함
- 기본 Python Worker의 콜드 스타트는 1초 미만으로 내려감
-
스냅샷 재사용
- 현재 Python Worker 업로드 시 생성되는 메모리 스냅샷은 해당 Worker 전용이며, 다른 Python Workers와 상당 부분이 같아도 공유할 수 없음
- Cloudflare는 사전에 단일 공유 스냅샷을 만들고, Pyodide 런타임이 이미 로드된 pre-warmed isolate 풀에 미리 적재할 수 있다고 봄
- 이 방식이면 Python Worker도 JavaScript Worker처럼 런타임이 on-demand로 제공되는 모델에 가까워짐
- Cloudflare는 2024년 남은 기간 동안 콜드 스타트를 더 낮추는 가장 큰 수단으로 스냅샷 재사용을 봄
Compatibility Dates로 Python 버전 관리
- Cloudflare Workers는 한 번 배포한 Worker가 업데이트 없이도 계속 실행되기를 기대하는 모델을 갖고 있음
- 이 안정성은 Compatibility Dates와 Compatibility Flags를 통해 제공됨
- Python에서는 Pyodide와 CPython이 각각 버전이 있고, 새 버전에 breaking change가 포함될 수 있음
- 새 Python 버전은 매년 8월 릴리스되고, 새 Pyodide 버전은 그 6개월 뒤 릴리스됨
- 새 Pyodide 버전은 Workers에 추가될 때 Compatibility Flag 뒤에 배치되고, 지정된 Compatibility Date 이후에만 활성화됨
- Python 릴리스는 5년 지원 기간을 가지며, 지원 기간이 지난 Python 버전에는 보안 패치가 적용되지 않음
- 5년이 지나도 오래된 Python 릴리스에 머무르는 Python Worker는 다음으로 오래된 Python 릴리스로 자동 이동됨
- Cloudflare는 대부분의 경우 Python Worker가 문제 없이 계속 실행될 것으로 기대하지만, 지원 기간 안에 머물도록 compatibility date를 정기적으로 업데이트하라고 권장함
- Python 릴리스 사이에도 패키지는 같은 opt-in 방식으로 업데이트·추가될 예정이며, 예시 플래그는
python_3.17_packages_2025_03_01형식임
Python Workers의 바인딩
- Pyodide FFI 덕분에 Python에서 JavaScript 객체, 메서드, 함수에 직접 접근할 수 있음
- 이 구조로 Cloudflare 리소스에 대한 모든 binding API가 첫날부터 Python Workers에서 지원됨
- Python 핸들러의
env객체는 JavaScript 객체이며, Pyodide가 언어 간 타입 변환을 처리하는 프록시 API를 제공함 - KV namespace에 대해
env.FOO.put()과env.FOO.get()을 Python에서 await해 값을 쓰고 읽을 수 있음 - Web API도 같은 방식으로 사용할 수 있으며,
Response처럼 JavaScript global을js모듈에서 import할 수 있음
더 Python다운 API 계획
- Cloudflare는
from js import Response같은 형태가 Python답지 않다는 점을 인식하고, Python Workers에 더 idiomatic한 API를 제공할 계획임 - 2021년에 출시한 workers-rs는 Workers의 JavaScript API마다 Rust다운 바인딩을 제공했음
- Python Workers에서도 같은 방향을 계획하며, 우선 Workers AI와 Vectorize 바인딩부터 시작함
- Rust의 workers-rs는 외부 의존성을 사용하고 업데이트해야 하지만, Python Workers의 API는 Workers 런타임에 직접 내장될 예정임
- compatibility date를 업데이트하면 최신 Python다운 API를 사용할 수 있음
- Workers의 JavaScript
connect()API를 바탕으로 Python 표준 라이브러리의 raw socket API 일부를 제공할 가능성도 있음 - Cloudflare는 JavaScript와 같은 기능을 제공하면서 Python 개발자가 쉽게 쓸 수 있는 표준화된 serverless API를 만드는 노력을 시작하길 기대함
앞으로의 방향
- 새 프로그래밍 언어를 제대로 지원하려면 “hello world” 이상으로 큰 투자가 필요함
- Python은 Stack Overflow 2023 조사 기준 JavaScript 다음으로 많이 쓰이는 언어로 나타남
- Cloudflare는 Python Workers의 성능을 계속 개선하고 Python 패키지 지원 범위를 넓히겠다고 함
- 피드백 채널은 Cloudflare Developers Discord의 Python Workers 채널과 workerd GitHub discussion임