Suscríbete para recibir notificaciones de nuevas publicaciones:

Usamos Python en Workers con Pyodide y WebAssembly

2024-04-02

14 min de lectura
Esta publicación también está disponible en English, Deutsch, Português y Français.

A partir de hoy, puedes escribir Cloudflare Workers en Python con la versión beta abierta.

Esta nueva compatibilidad para Python es diferente a la forma en la que Workers ha admitido tradicionalmente lenguajes más allá de JavaScript — en este caso, hemos integrado directamente una implementación de Python en workerd, el entorno de ejecución de código abierto de Workers. Todos los enlaces, incluidos los enlaces a Vectorize, Workers AI, R2, Durable Objects, entre otros, son compatibles desde el primer día. Python Workers puede importar un subconjunto de paquetes populares de Python como FastAPI, Langchain, Numpy y muchos más. No hay pasos de desarrollo adicionales ni cadenas de herramientas externas.

Para ello, hemos tenido que ampliar los límites de todos nuestros sistemas, desde el propio entorno de ejecución, pasando por nuestro sistema de implementación, hasta el contenido del paquete de Worker que se publica en nuestra red. Puedes leer los documentos y empezar a usarlo hoy mismo.

Queremos aprovechar esta publicación para desvelar el ciclo de vida interno de un Python Worker, compartir lo que hemos aprendido en el proceso y destacar hacia dónde nos dirigimos próximamente.

No solo compilamos a WebAssembly

Cloudflare Workers es compatible con WebAssembly desde 2018. Cada Worker es un motor V8 aislado, que funciona con el mismo motor JavaScript que el navegador web Chrome. En principio, durante años ha sido posible escribir Workers en cualquier lenguaje, incluido Python, siempre que se compile primero en WebAssembly o en JavaScript.

En la práctica, el hecho de que algo sea posible no significa que sea sencillo. Y el hecho de que "Hello World" funcione no significa que puedas crear una aplicación de forma fiable. El desarrollo de una aplicación completa requiere admitir un ecosistema de paquetes con el que los desarrolladores estén acostumbrados a crear. Para que una plataforma sea realmente compatible con un lenguaje de programación, es necesario ir mucho más allá de mostrar cómo compilar código utilizando cadenas de herramientas externas.

Python Workers es diferente de lo que hemos hecho hasta ahora. Es una versión preliminar, y aún está en fase beta, pero creemos que muestra la forma de prestar servicio de primera calidad para lenguajes de programación más allá de JavaScript en Workers.

El ciclo de vida de un Python Worker

Con Pyodide ahora integrado en workerd, puedes escribir un Worker como este:

…con un archivo Wrangler.toml que apunta a un archivo .py :

from js import Response

async def on_fetch(request, env):
    return Response.new("Hello world!")

…y cuando ejecutas npx wrangler@latest dev, el entorno de ejecución de Workers:

name = "hello-world-python-worker"
main = "src/entry.py"
compatibility_date = "2024-03-18"
compatibility_flags = ["python_workers"]
  1. Determina qué versión de Pyodide es necesaria, en función de tu fecha de compatibilidad

  2. Crea un aislamiento para tu Worker e inyecta automáticamente Pyodide

  3. Sirve tu código Python usando Pyodide

Todo esto ocurre en segundo plano, sin necesidad de cadenas de herramientas adicionales ni pasos previos a la compilación. Te proporcionamos el entorno de ejecución de Python, que refleja cómo funcionan los Workers escritos en JavaScript.

Un intérprete de Python integrado en el entorno de ejecución de Workers

Al igual que JavaScript tiene muchos motores, Python tiene muchas implementaciones que pueden ejecutar código Python. CPython es la implementación de referencia de Python. Si has utilizado Python antes es muy probable que lo hayas utilizado, y se suele denominar simplemente "Python".

Pyodide es un puerto de CPython para WebAssembly. Interpreta el código Python, sin necesidad de compilar previamente el propio código Python en ningún otro formato. Se ejecuta en un navegador web — echa un vistazo a este REPL. Es fiel al CPython que los desarrolladores de Python conocen y esperan, y proporciona la mayor parte de la biblioteca estándar de Python. Ofrece una interfaz de función externa (FFI) a JavaScript, lo que te permite llamar a la API de JavaScript directamente desde Python. Más información a continuación. Proporciona paquetes populares de código abierto y puede importar paquetes de Python puro directamente desde PyPI.

Pyodide nos pareció la solución perfecta para Workers. Está diseñado para permitir que el intérprete principal y cada módulo nativo de Python se creen como módulos WebAssembly independientes, vinculados dinámicamente en el entorno de ejecución. De esta manera, la huella de código de estos módulos se puede compartir entre todos los Workers que se ejecutan en la misma máquina, en lugar de requerir que cada Worker use su propia copia. Esta ventaja es esencial para que WebAssembly funcione bien en el entorno de Workers, donde a menudo ejecutamos miles de Workers por máquina. Necesitamos Workers que utilicen el mismo lenguaje de programación para compartir su huella de código en el entorno de ejecución. La ejecución de miles de Workers en cada máquina es lo que nos permite implementar cada aplicación en cada ubicación a un precio razonable.

Al igual que con JavaScript Workers, con Python Workers te proporcionamos el entorno de ejecución:

Actualmente, Pyodide es la excepción. La mayoría de los lenguajes que se dirigen a WebAssembly aún no admiten la vinculación dinámica, por lo que cada aplicación acaba usando su propia copia de su entorno de ejecución de lenguaje. Esperamos que en el futuro haya más lenguajes que admitan la vinculación dinámica, para que podamos incorporarlos a Workers de manera más eficaz.

Cómo funciona Pyodide

Pyodide ejecuta código Python en WebAssembly, que es un entorno de espacio restringido y controlado, separado del entorno de ejecución del host. A diferencia de la ejecución de código nativo, todas las operaciones fuera del cálculo puro (como las lecturas de archivos) deben ser proporcionadas por un entorno de ejecución, y luego importadas por el módulo WebAssembly.

LLVM proporciona tres target triples para WebAssembly:

  1. wasm32-unknown-unknown: este backend no proporciona una biblioteca estándar C ni una interfaz de llamada al sistema. Para admitir este backend, necesitaríamos reescribir manualmente cada llamada al sistema o biblioteca para hacer uso de las importaciones que definiríamos nosotros mismos en el entorno de ejecución.

  2. wasm32-wasi: WASI es una interfaz de sistema estandarizada, y define un conjunto estándar de importaciones que se implementan en entornos de ejecución de WASI como wasmtime.

  3. wasm32-unknown-emscripten: al igual que WASI, Emscripten define las importaciones que un programa WebAssembly necesita ejecutar, pero también genera una biblioteca JavaScript adjunta que implementa estas funciones importadas.

Pyodide utiliza Emscripten y proporciona:

  1. Una distribución del intérprete CPython, compilada con Emscripten

  2. Una FFI entre Python y JavaScript

  3. Un conjunto de paquetes de Python de terceros, compilados con el compilador de Emscripten para WebAssembly.

De estos objetivos, solo Emscripten admite actualmente la vinculación dinámica, que, como hemos señalado anteriormente, es esencial para proporcionar un entorno de ejecución de lenguaje compartido para Python que se comparte entre los entornos aislados. Emscripten lo hace proporcionando implementaciones de dlopen y dlsym, que utilizan la biblioteca JavaScript adjunta para modificar la tabla del programa WebAssembly y vincular módulos adicionales compilados por WebAssembly en el entorno de ejecución. WASI aún no es compatible con las abstracciones de enlace dinámico dlopen/dlsym utilizadas por CPython.

Pyodide y la magia de las FFI

Es posible que hayas notado que en nuestro Python Worker "Hello World", importamos Response desde el módulo js :

¿Por qué?

from js import Response

async def on_fetch(request, env):
    return Response.new("Hello world!")

La mayoría de Workers están escritos en JavaScript, y la mayor parte de nuestro equipo de ingeniería en el entorno de ejecución de Workers se dedica a mejorar JavaScript Workers. Cuando se añade un segundo lenguaje, existe el riesgo de que nunca alcance la paridad de funciones con el primer lenguaje y sea siempre inferior. La FFI de Pyodide es fundamental para evitar este inconveniente, ya que proporciona acceso a toda la funcionalidad de JavaScript desde Python. El autor de Worker lo puede utilizar directamente, y también se utiliza para hacer que paquetes como FastAPI y Langchain funcionen sin configuración, como mostraremos más adelante en esta publicación.

Una FFI es un sistema para llamar a funciones en un lenguaje que se implementan en otro lenguaje. En la mayoría de los casos, una FFI se define mediante un lenguaje de "nivel superior" para llamar a funciones implementadas en un lenguaje de sistemas, a menudo el lenguaje C. El módulo ctypes de Python es un sistema de este tipo. Este tipo de interfaces de funciones externas suelen ser difíciles de usar debido a la naturaleza de las API del lenguaje C.

La interfaz de función externa de Pyodide es una interfaz entre Python y JavaScript, que son dos lenguajes orientados a objetos de alto nivel con muchas similitudes de diseño. Cuando se pasan de un lenguaje a otro, los tipos inmutables, como cadenas y números, se traducen de forma transparente. Todos los objetos mutables están encapsulados en un proxy apropiado.

Cuando se pasa un objeto JavaScript a Python, Pyodide determina qué protocolo JavaScript admite el objeto y crea dinámicamente una clase Python adecuada que implementa el protocolo Python correspondiente. Por ejemplo, si el objeto JavaScript admite el protocolo de iteración de JavaScript, el proxy admitirá el protocolo de iteración de Python. Si el objeto JavaScript es un objeto Promise u otro objeto thenable, el objeto Python será un objeto awaitable.

El ciclo de vida de una solicitud a un Python Worker utiliza la FFI de Pyodide, que encapsula el objeto Request de JavaScript entrante en un objeto JsProxy al que se puede acceder en tu código Python. A continuación, convierte el valor devuelto por el controlador de Python Worker en un objeto Response de JavaScript que se puede devolver al cliente:

from js import JSON

js_array = JSON.parse("[1,2,3]")

for entry in js_array:
   print(entry)

Por qué los enlaces dinámicos son esenciales y los estáticos no son suficientes

Python viene con una C FFI, y muchos paquetes de Python utilizan esta FFI para importar bibliotecas nativas. Estas bibliotecas suelen estar escritas en C, por lo que primero se deben compilar a WebAssembly para que funcionen en el entorno de ejecución de Workers. Como hemos señalado anteriormente, Pyodide se crea con Emscripten, que anula C FFI de Python. Cada vez que un paquete intenta cargar una biblioteca nativa, se carga desde un módulo WebAssembly proporcionado por el entorno de ejecución de Workers. La vinculación dinámica es lo que lo hace posible, es lo que nos permite anular el C FFI de Python, lo que permite a Pyodide admitir muchos paquetes de Python que tienen dependencias de bibliotecas nativas.

La vinculación dinámica es "pago por uso", mientras que la vinculación estática es "pago por adelantado". Si el código está vinculado estáticamente a tu binario, se debe cargar por adelantado para que el binario se ejecute, incluso si este código nunca se utiliza.

La vinculación dinámica permite que el entorno de ejecución de Workers comparta los módulos WebAssembly subyacentes de los paquetes entre diferentes Workers que se ejecutan en la misma máquina.

No entraremos demasiado en detalles sobre cómo funciona la vinculación dinámica en Emscripten, pero la conclusión principal es que el entorno de ejecución de Emscripten obtiene los módulos WebAssembly de una abstracción del sistema de archivos proporcionada en JavaScript. Para cada Worker, generamos un sistema de archivos en el entorno de ejecución, cuya estructura imita una distribución de Python que tiene instaladas las dependencias de Worker, pero cuyos archivos subyacentes se comparten entre Workers. De esta manera se pueden compartir archivos Python y WebAssembly entre varios Workers que importan la misma dependencia. Hoy en día, podemos compartir estos archivos en Workers y copiarlos en cada nuevo entorno aislado. Creemos que podemos ir aún más allí con el uso de técnicas de copy-on-write para compartir el recurso subyacente entre muchos Workers.

Compatibilidad con bibliotecas de servidor y cliente

Python tiene una amplia variedad de bibliotecas de cliente HTTP populares, incluidas httpx, urllib3, Requests, entre otras. Desafortunadamente, ninguno de ellas funciona de forma inmediata en Pyodide. Los usuarios llevan mucho tiempo solicitando compatibilidad con estas bibliotecas para el proyecto Pyodide. Todas las bibliotecas de cliente HTTP de Python funcionan con sockets sin formato, y el modelo de seguridad del navegador y CORS no lo permiten, por lo que necesitábamos otra forma de hacer que funcionaran en el entorno de ejecución de Workers.

Bibliotecas de cliente asíncronos

Para las bibliotecas que pueden realizar solicitudes de forma asíncrona, como aiohttp y httpx, podemos utilizar la API Fetch para realizar las solicitudes. Para ello, actualizamos la biblioteca y le indicamos que utilice la API Fetch de JavaScript, aprovechando la FFI de Pyodide. La actualización de httpx acaba siendo bastante sencilla. Menos de 100 líneas de código. Si lo simplificamos aún más, se ve así:

Bibliotecas de cliente síncrono

from js import Headers, Request, fetch

def py_request_to_js_request(py_request):
    js_headers = Headers.new(py_request.headers)
    return Request.new(py_request.url, method=py_request.method, headers=js_headers)

def js_response_to_py_response(js_response):
  ... # omitted

async def do_request(py_request):
  js_request = py_request_to_js_request(py_request)
    js_response = await fetch(js_request)
    py_response = js_response_to_py_response(js_response)
    return py_response

Otro desafío en la compatibilidad con las bibliotecas de cliente HTTP de Python es que muchas API de Python son síncronas. Para estas bibliotecas, no podemos utilizar la API Fetch directamente porque es asíncrona.

Afortunadamente, Joe Marshall consiguió recientemente una contribución a urllib3 que añade compatibilidad de Pyodide con los navegadores web :

  1. Comprueba si es posible bloquear con `Atomics.wait()`

a.  Si es así, inicia un worker thread en fetchb. Delega la operación fetch al worker thread y serializa la respuesta en un SharedArrayBufferc. En el subproceso de Python, utiliza Atomics.wait para bloquear la respuesta en el SharedArrayBuffer

2.    Si `Atomics.wait()` no funciona, recurre a una XMLHttpRequest síncrona

A pesar de ello, hoy en día Cloudflare Workers no admite worker threads ni XMLHttpRequest síncrono, por lo que ninguno de estos dos enfoques funcionará en Python Workers. Actualmente no admitimos solicitudes síncronas, pero hay una forma de avanzar...

Conmutador apilable de WebAssembly

Existe un enfoque que nos permitirá admitir solicitudes síncronas. WebAssembly tiene una propuesta de fase 3 que añade compatibilidad para la conmutación apilable, de la que el motor v8 tiene una implementación. Los colaboradores de Pyodide han estado trabajando para añadir compatibilidad para el conmutador apilable a Pyodide desde septiembre de 2022, y ya está casi listo.

from pyodide.ffi import run_sync

def sync_fetch(py_request):
   js_request = py_request_to_js_request(py_request)
   js_response  = run_sync(fetch(js_request))
   return js_response_to_py_response(js_response)

Con esta compatibilidad, Pyodide expone una función llamada `run_sync` que puede bloquear la finalización de un objeto awaitable:

FastAPI y la interfaz de puerta de enlace de servidor asíncrono de Python

FastAPI es una de las bibliotecas más populares para definir servidores Python. La aplicación FastAPI utiliza un protocolo llamado Asynchronous Server Gateway Interface (ASGI). Esto significa que FastAPI nunca lee o escribe en un socket. Una aplicación ASGI espera estar conectada a un servidor ASGI, normalmente uvicorn. El servidor ASGI gestiona todos los sockets sin procesar en nombre de la aplicación.

Para nuestra comodidad, esto significa que FastAPI funciona en Cloudflare Workers sin ninguna actualización o cambio en la propia FastAPI. Simplemente necesitamos reemplazar uvicorn por un servidor ASGI apropiado que se pueda ejecutar dentro de un Worker. Nuestra implementación inicial se aloja aquí, en la bifurcación de Pyodide que mantenemos. Esperamos añadir un conjunto de funciones más completo, añadir cobertura de prueba y luego subir esta implementación a Pyodide.

Puedes intentarlo tú mismo clonando Cloudflare/python-workers-examples y ejecutando `npx wrangler@latest dev` en el directorio del ejemplo de FastAPI.

Importación de paquetes de Python

Python Workers admite un subconjunto de paquetes de Python, que Pyodide proporciona directamente, incluidos numpy, httpx, FastAPI, Langchain, entre otros. De esta manera se garantiza la compatibilidad con el entorno de ejecución de Pyodide al vincular las versiones de los paquetes a las versiones de Pyodide, y permite a Pyodide revisar las implementaciones internas, como mostramos anteriormente en el caso de httpx.

Para importar un paquete, simplemente añádelo a tu archivo requirements.txt, sin añadir un número de versión. Pyodide proporciona directamente una versión específica del paquete. Hoy en día, puedes utilizar paquetes en el desarrollo local, y en las próximas semanas podrás implementar Workers que definan dependencias en un archivo requirements.txt. Más adelante en esta publicación, mostraremos cómo pensamos gestionar las nuevas versiones de Pyodide y los paquetes.

Mantenemos nuestra propia bifurcación de Pyodide, que nos permite proporcionar una revisión específica del entorno de ejecución de Workers, y ampliar rápidamente nuestra compatibilidad para paquetes en Python Workers, al tiempo que nos comprometemos a enviar nuestros cambios a Pyodide, para que todo el ecosistema de desarrolladores puede beneficiarse.

Sin embargo, los paquetes de Python suelen ser grandes, consumen mucha memoria, y pueden hacer mucho trabajo en el momento de la importación. ¿Cómo podemos asegurarnos de que puedes usar los paquetes que necesitas, mitigando al mismo tiempo los largos tiempos de arranque en frío?

Cómo acelerar los arranques en frío con las instantáneas de memoria

En el ejemplo del principio de esta publicación, en desarrollo local, mencionamos la inyección de Pyodide en tu Worker. El propio Pyodide ocupa 6,4 MB, y los paquetes de Python también pueden ser bastante grandes.

Si simplemente insertáramos Pyodide en tu Worker y lo subiéramos a Cloudflare, sería un Worker bastante grande para cargar en un nuevo entorno aislado. Los arranques en frío serían lentos. En un ordenador rápido con una buena conexión de red, Pyodide tarda unos dos segundos en inicializarse en un navegador web, un segundo de tiempo de red y un segundo de tiempo de CPU. No sería aceptable inicializarlo cada vez que actualizas tu código para cada aislamiento que tu Worker ejecuta en la red de Cloudflare.

En su lugar, cuando ejecutas npx wrangler@latest deployment, sucede lo siguiente:

  1. Wrangler carga tu código Python y tu archivo requirements.txt a la API de Workers.

  2. Enviamos tu código Python y tu archivo requirements.txt al entorno de ejecución de Workers para su validación.

  3. Creamos un nuevo aislamiento para tu Worker, e inyectamos automáticamente Pyodide y cualquier paquete que hayas especificado en tu archivo requirements.txt.

  4. Escaneamos el código del Worker en busca de declaraciones import, las ejecutamos y luego tomamos una instantánea de la memoria lineal WebAssembly del Worker. Efectivamente, realizamos el costoso trabajo de importar paquetes en el momento de la implementación, no en el entorno de ejecución.

  5. Implementamos esta instantánea junto con tu código Python de Worker en la red de Cloudflare.

  6. Al igual que un Worker de JavaScript, ejecutamos el ámbito de nivel superior del Worker.

Cuando llega una solicitud a tu Worker, cargamos esta instantánea y la utilizamos para arrancar tu Worker en un entorno aislado, evitando así el tiempo largo de inicialización:

De esta manera, los arranques en frío de un Python Worker básico pueden ser inferiores a 1 segundo. Sin embargo, todavía no estamos satisfechos con este resultado. Estamos seguros de que podemos reducirlo mucho más. ¿Cómo? Reutilizando instantáneas de memoria.

Reutilización de instantáneas de memoria

Cuando cargas un Python Worker, generamos una única instantánea de memoria de las importaciones de nivel superior del Worker, que incluye tanto Pyodide como cualquier dependencia. Esta instantánea es específica de tu Worker. No se puede compartir, aunque la mayor parte de su contenido es el mismo que el de otros Python Workers.

En su lugar, podemos crear una única instantánea compartida con antelación, y precargarla en un grupo de aislamientos "precalentados". Estos aislamientos ya tendrían el entorno de ejecución de Pyodide cargado y listo, lo que haría que un Python Worker funcionara igual que un JavaScript Worker. En ambos casos, el intérprete subyacente y el entorno de ejecución lo proporciona el entorno de ejecución de Workers, y está disponible bajo demanda de inmediato. La única diferencia es que con Python, el intérprete se ejecuta en WebAssembly, dentro del Worker.

Las instantáneas son un patrón común en los tiempos de ejecución y los entornos de ejecución. Node.js utiliza instantáneas del motor V8 para acelerar el tiempo de inicio. Puedes tomar instantáneas de las microVM de Firecracker y reanudar la ejecución en un proceso diferente. Podemos hacer mucho más, no solo para Python Workers, sino también para Workers escritos en JavaScript, almacenar en caché instantáneas del código compilado del ámbito de nivel superior y el estado del propio aislamiento. Workers es tan rápido y eficiente que hasta la fecha no hemos tenido que tomar instantáneas de esta manera, pero creemos que aún se pueden obtener grandes mejoras de rendimiento.

Esta es nuestra mayor ventaja para reducir los tiempos de arranque en frío durante el resto de 2024.

Prueba de compatibilidad futura con las versiones de Pyodide y fechas de compatibilidad

Cuando implementas un Worker en Cloudflare, esperas que siga ejecutándose indefinidamente, incluso si nunca lo vuelves a actualizar. Hay Workers implementados en 2018 que todavía funcionan bien en producción.

Lo conseguimos utilizando fechas de compatibilidad y marcas de compatibilidad, que proporcionan mecanismos de suscripción explícitos para nuevos comportamientos y cambios potencialmente incompatibles con versiones anteriores, sin afectar a los Workers existentes.

Esto funciona en parte porque refleja cómo funcionan Internet y los navegadores web. Publicas una página web con algo de JavaScript, y con razón esperas que funcione para siempre. Los navegadores web y Cloudflare Workers tienen el mismo tipo de compromiso de estabilidad con los desarrolladores.

Sin embargo, hay un desafío con Python. Tanto Pyodide como CPython tienen distintas versiones. Las versiones actualizadas se publican periódicamente y pueden contener cambios importantes. Pyodide proporciona un conjunto de paquetes integrados, cada uno con un número de versión anclado. Esto plantea una pregunta: ¿cómo deberíamos permitirte actualizar tu Worker a una versión más reciente de Pyodide?

La respuesta es fechas de compatibilidad y marcas de compatibilidad.

Cada año se lanza una nueva versión de Python en agosto, y seis (6) meses después se lanza una nueva versión de Pyodide. Cuando se publique esta nueva versión de Pyodide, la añadiremos a Workers con una marca de compatibilidad, que solo se activa después de una fecha de compatibilidad determinada. De esta manera podemos proporcionar actualizaciones continuamente, sin riesgo de interrumpir los cambios, ampliando el compromiso que hemos adquirido para JavaScript a Python.

Cada versión de Python tiene un periodo de compatibilidad de cinco (5) años. Una vez que ha pasado este tiempo para una versión determinada de Python, ya no se aplican las actualizaciones de seguridad, por lo que no es seguro confiar en esta versión. Para mitigar este riesgo, sin dejar de intentar mantener nuestro compromiso de estabilidad y compatibilidad a largo plazo lo más fielmente posible, después de cinco años cualquier Python Worker que siga en una versión de Python que esté fuera del periodo de compatibilidad pasará automáticamente a la siguiente versión más antigua de Python. Python es un lenguaje maduro y estable, por lo que esperamos que, en la mayoría de los casos, tu Python Worker siga ejecutándose sin problemas. Sin embargo, te recomendamos que actualices la fecha de compatibilidad de tu Worker con regularidad, para mantenerte dentro del periodo de compatibilidad.

Entre lanzamientos de Python, también esperamos actualizar y añadir paquetes adicionales de Python, utilizando el mismo mecanismo de suscripción. Una marca de compatibilidad será una combinación de la versión de Python y la fecha de lanzamiento de un conjunto de paquetes. Por ejemplo, python_3.17_packages_2025_03_01.

Cómo funcionan los enlaces en Python Workers

Hemos mencionado anteriormente que Pyodide proporciona una FFI a JavaScript, lo que significa que puedes utilizar directamente objetos, métodos, funciones de JavaScript y mucho más, directamente desde Python.

De esta manera, desde el primer día, todas las API de enlace a otros recursos de Cloudflare son compatibles con Cloudflare Workers. El objeto env que proporcionan los controladores en los Python Workers es un objeto JavaScript al que Pyodide proporciona un proxy de API, que gestiona automáticamente las traducciones de tipos entre lenguajes.

from js import Response

async def on_fetch(request, env):
    await env.FOO.put("bar", "baz")
    bar = await env.FOO.get("bar")
    return Response.new(bar) # returns "baz"

Por ejemplo, para escribir y leer en un espacio de nombres KV desde un Python Worker, escribirías:

Esto también funciona para las API web: ¿ves cómo se importa Response desde el módulo js? Puedes importar código global desde JavaScript de esta manera.

¡Saca este JavaScript de mi Python!

Probablemente estés leyendo esta publicación porque quieres escribir Python en lugar de JavaScript. from js import Response simplemente no está escrito en lenguaje Python. Lo sabemos, y de hecho ya hemos abordado este desafío antes para otro lenguaje (Rust). Creemos que podemos hacerlo aún mejor para Python.

Lanzamos Workers-rs en 2021 para que fuera posible escribir Workers en Rust. Para cada API de JavaScript en Workers, nosotros, junto con los colaboradores de código abierto, hemos escrito enlaces que exponen una API de Rust más idiomática.

Planeamos hacer lo mismo con Python Workers, empezando por los enlaces a Workers AI y Vectorize. Pero mientras Workers-rs requiere que uses y actualices una dependencia externa, la API que proporcionamos con Python Workers se integrará directamente en el entorno de ejecución de Workers. Solo tienes que actualizar tu fecha de compatibilidad y conseguir la API más reciente y basada en Python.

Sin embargo, no solo se trata de hacer que los enlaces a los recursos en Cloudflare se basen en Python, sino de la compatibilidad con el ecosistema.

De forma similar a cómo convertimos recientemente Workers-rs para utilizar tipos de formato http, lo que facilita el uso de formato axum para el enrutamiento, nuestro objetivo es hacer lo mismo para Python Workers. Por ejemplo, la biblioteca estándar de Python proporciona una API de socket sin procesar, de la que dependen muchos paquetes de Python. Workers ya proporciona connect(), una API de JavaScript para trabajar con sockets sin formato. Vemos formas de proporcionar al menos un subconjunto de la API de socket de la biblioteca estándar de Python en Workers, lo que permite que un conjunto más amplio de paquetes de Python funcione en Workers, sin tanta necesidad de llevar a cabo actualizaciones.

Pero, en última instancia, esperamos impulsar la iniciativa para crear una API sin servidor estandarizada para Python. Una plataforma que sea fácil de usar para cualquier desarrollador de Python y que ofrezca las mismas funciones que JavaScript.

Estamos empezando nuestra andadura con Python Workers

La capacidad de ofrecer compatibilidad real para un nuevo lenguaje de programación es una gran inversión que va mucho más allá de hacer que "Hello World" funcione. Elegimos Python de forma muy intencionada, ya que es el segundo lenguaje de programación más popular después de JavaScript, y estamos comprometidos a seguir mejorando el rendimiento y ampliando nuestra compatibilidad con los paquetes de Python.

Estamos muy agradecidos con los mantenedores de Pyodide y la comunidad de Python en general, y nos encantaría saber de ti. Entra en el canal Python Workers en nuestro canal Discord de la plataforma para desarrolladores o abre un debate en Github sobre lo que te gustaría ver a continuación y qué paquetes de Python quieres que admitamos.

Protegemos redes corporativas completas, ayudamos a los clientes a desarrollar aplicaciones web de forma eficiente, aceleramos cualquier sitio o aplicación web, prevenimos contra los ataques DDoS, mantenemos a raya a los hackers, y podemos ayudarte en tu recorrido hacia la seguridad Zero Trust.

Visita 1.1.1.1 desde cualquier dispositivo para empezar a usar nuestra aplicación gratuita y beneficiarte de una navegación más rápida y segura.

Para saber más sobre nuestra misión para ayudar a mejorar Internet, empieza aquí. Si estás buscando un nuevo rumbo profesional, consulta nuestras ofertas de empleo.
DesarrolladoresCloudflare WorkersWebAssembly (ES)Python (ES)Developer PlatformWASM (ES)Developer Week (ES)

Síguenos en X

Dominik Picheta|@d0m96
Cloudflare|@cloudflare

Publicaciones relacionadas