Hub documentation

Guía de webhooks: Procesar nuevos archivos en un bucket con Jobs

Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Guía de webhooks: Procesar nuevos archivos en un bucket con Jobs

Los Storage Buckets son un buen lugar para archivos que llegan con el tiempo: exportaciones de otras herramientas, registros, grabaciones, escaneos. A menudo tendrás un flujo de trabajo que debe realizarse en estos archivos antes de que sean útiles, como convertirlos, limpiarlos o transcribirlos.

Un webhook en el bucket y un Job pueden realizar este trabajo de forma automática, sin necesidad de un servidor. Cuando los archivos cambian, el webhook inicia el Job. El Job recibe la lista de archivos modificados, los procesa y se detiene. Solo pagas mientras está en ejecución.

Esta guía explica el patrón y luego lo configura con un ejemplo: convertir archivos CSV y JSON subidos a Parquet optimizado.

Cómo funciona

file uploaded ──▶ webhook ──▶ Job runs with the event ──▶ result written to a second bucket

Un webhook puede disparar un Job en lugar de llamar a una URL. Creas el Job una vez y cada evento de webhook lo vuelve a ejecutar con el evento en su entorno. Para un bucket, WEBHOOK_PAYLOAD enumera los archivos que cambiaron:

{
  "event": { "action": "update", "scope": "repo.content" },
  "repo": { "type": "bucket", "name": "your-username/my-raw-files", ... },
  "updatedFiles": [
    { "path": "data.csv", "action": "add", "xetHash": "433b53b8...", "size": 10983 }
  ]
}

Así, el Job procesa solo los archivos nuevos y puede decidir cómo manejar cada uno antes de descargar nada.

Cada ejecución reutiliza la imagen, el comando, las variables de entorno, el tipo de hardware y el tiempo de espera del Job. No obtiene los volúmenes ni los secretos del Job. Por eso, los pasos siguientes ejecutan el script desde una URL y colocan el token en el webhook.

El Job escribe sus resultados en un segundo bucket. Si escribiera en el bucket que monitorea, su propia salida volvería a activar el webhook.

Ejemplo: convertir las cargas en Parquet optimizado

Las exportaciones en CSV y JSON son lentas de consultar y difíciles de compartir. Parquet optimizado es más rápido de filtrar y transmitir, y las cargas y descargas son más rápidas gracias a la deduplicación de Xet. En este ejemplo, cada archivo CSV, JSON o Parquet subido a un bucket aparece como Parquet optimizado en otro. El Job ejecuta optimize-parquet.py, un script listo para usar de uv-scripts.

Necesitas una cuenta de Hugging Face con créditos prepagados y la CLI hf.

Crea dos cubos

Un bucket recibe tus cargas y el otro recibe los archivos Parquet:

hf buckets create my-raw-files --private
hf buckets create my-parquet --private

Crear el trabajo

Crea el Job que ejecutará el webhook:

hf jobs run --flavor cpu-upgrade --timeout 2h \
    -e OUTPUT_BUCKET=your-username/my-parquet \
    ghcr.io/astral-sh/uv:python3.12-bookworm \
    uv run https://huggingface.co/datasets/uv-scripts/data-processing/raw/main/optimize-parquet.py

El script se ejecuta desde su URL, con hf jobs run. hf jobs uv run es la forma habitual de ejecutar un script de UV, pero sube el script a un volumen, algo que una ejecución mediante webhook no tendría. cpu-upgrade es suficiente para este trabajo, y el tiempo de espera de dos horas deja margen para archivos grandes.

El script también puede estar en un bucket o repo privado. No uses el bucket observado: subir el script iniciaría un Job. Añade --secrets HF_TOKEN al comando, con un token que pueda leer el script. Si la ejecución falla con un SyntaxError, el token no puede leerlo. El token del webhook necesita el mismo acceso, porque las ejecuciones de webhook no reciben este secreto.

hf jobs run inicia el Job de inmediato. Esta primera ejecución no tiene ningún evento de webhook y optimize-parquet.py no hace nada sin uno, por lo que el Job se detiene de inmediato. Copia el ID del Job que imprime.

Crear el webhook

Observa el primer bucket y ejecuta tu Job cuando cambie:

hf webhooks create --job-id <job ID> --watch bucket:your-username/my-raw-files \
    --domain repo --secrets HF_TOKEN

--domain repo restringe el webhook a cambios en archivos y ajustes. Los buckets solo envían esos cambios, por lo que esta opción es explícita y no estrictamente necesaria, pero mantiene el comando correcto si más adelante se observa un modelo o un conjunto de datos.

--secrets HF_TOKEN almacena un token con el webhook, cifrado. Cada Job que inicia el webhook lo recibe como un secreto y lo utiliza para leer y escribir en los buckets. El valor proviene de HF_TOKEN en su entorno, o del token con el que inició sesión. Un token de grano fino con solo los permisos que el Job necesita es la opción más segura.

Para usar un token creado solo para este pipeline, pase el valor explícitamente con --secrets HF_TOKEN=hf_…, o evite que quede en el historial de su shell mediante una tubería: printf 'HF_TOKEN=hf_…\n' | hf webhooks create … --secrets-file -.

El comando imprime el ID del webhook. Para detener la pipeline más tarde, elimina el webhook con hf webhooks delete <webhook ID>.

Subir un archivo

hf buckets cp data.csv hf://buckets/your-username/my-raw-files/data.csv

Un minuto después, un Job aparece en tu página de Jobs. Si no aparece, abre la pestaña Activity del webhook en tu configuración de webhooks para ver la entrega y lee la salida de un Job con hf jobs logs <job ID>. Cuando el Job termina, el archivo Parquet está en el segundo bucket:

hf buckets ls your-username/my-parquet -R
data.csv/README.md
data.csv/data/train-00000-of-00001.parquet

Para convertir muchos archivos, súbelos con un solo hf buckets sync. Los archivos subidos juntos suelen llegar como un solo evento, por lo que un solo Job los convierte todos, hasta 10.000 archivos por evento. Consulta Webhooks para ver la carga completa del bucket y qué ocurre al superar ese límite.

Lo que hace el script

La parte específica de los webhooks es la lectura del evento:

event = json.loads(os.environ.get("WEBHOOK_PAYLOAD", "{}"))  # empty when you run the Job yourself
input_bucket = os.environ.get("WEBHOOK_REPO_ID")

for changed_file in event.get("updatedFiles", []):
    if changed_file["action"] != "add":
        continue  # skip deleted files
    path, size = changed_file["path"], changed_file["size"]
    ...  # convert the file (see the full script)

Para cada archivo nuevo, el script lo carga con datasets directamente desde el bucket (hf://buckets/...). Si el archivo es mayor que un tercio del disco libre del Job, se transmite en streaming en lugar de descargarse. A continuación, push_to_hub lo escribe en el bucket de salida como Parquet con chunking definido por el contenido, un índice de páginas y grupos de filas de como máximo 100 MB.

Usa el patrón para tu propia tarea

Mantén la configuración y cambia el script. Por ejemplo:

  • Elimina los datos personales antes de entrenar. Recopila el texto sin procesar en un bucket privado, redacta la información personal con un modelo como GLiNER2 PII filter y sube solo el texto redactado a tu conjunto de datos de entrenamiento.
  • Evaluar nuevos puntos de control. Un Job de entrenamiento guarda puntos de control en un bucket, y cada nuevo punto de control inicia un Job de evaluación. Si un punto de control se sube en varias partes, reacciona solo cuando aparezca en updatedFiles el archivo marcador que escribas al final; los eventos pueden llegar desordenados.
  • Transcribe o incrusta nuevos archivos. Convierte nuevas grabaciones en transcripciones o nuevos documentos en incrustaciones para búsqueda.

Al escribir tu script, decide qué hace en la primera ejecución, cuando WEBHOOK_PAYLOAD no está definido. Puede salir, como hace optimize-parquet.py, o realizar trabajo real, como procesar los archivos que ya estaban en el bucket. Si la primera ejecución necesita un token, por ejemplo para leer el bucket o un script privado, añade --secrets HF_TOKEN a hf jobs run. Las ejecuciones de webhook no reciben este secreto. Obtienen su token del webhook.

¿Webhook o programación?

Un webhook inicia un Job para cada evento, por lo que los nuevos archivos se procesan aproximadamente un minuto después de llegar. Si no necesitan procesarse con tanta rapidez, un Job programado es una alternativa: se ejecuta cada hora o cada día y procesa todo lo que haya llegado desde la última ejecución. Esto agrupa el trabajo en menos Jobs, lo cual es útil para tareas de GPU que tardan en iniciarse, y evita el límite de webhook de 1.000 activaciones por 24 horas. En ese caso, el script debe encontrar los nuevos archivos por sí mismo, por ejemplo, comparando los cubos de entrada y salida.

Update on GitHub