Ir al contenido
mcpd
sin daemon
Código

Workers

Un worker es un proceso tuyo que sirve al daemon los cuerpos de los pasos. Esta página es el protocolo que habla, y por qué está ahí cada llamada.

Qué es un worker

Un worker guarda los cuerpos de los pasos reclamables y le pide trabajo al daemon. Se ejecuta donde se ejecuta tu código, con tus imports, tu pool de conexiones y tus credenciales, y el daemon no llega a ver nada de eso. El daemon le entrega un lease con la entrada renderizada y los pasos anteriores; el worker ejecuta el cuerpo e informa de cómo fue. Toda la relación es esa.

Cada SDK trae uno. Registra los workflows que guarda, hace long polling para pedir leases, manda heartbeats mientras corre un cuerpo, y responde a cada rechazo según su motivo. El ejemplo de abajo es el mismo programa que el de la página de Workflows; esta es la parte que lo sirve.

servir los cuerpos

// Serve step bodies for as long as this process lives. The worker registers
// the definition, long-polls for leases, heartbeats while a body runs, and
// answers every 409 by its reason.
const worker = new Worker(mcpd, { concurrency: 8 }).register(support)
void worker.serve()

El protocolo

Cinco llamadas, y un worker que las hable se puede escribir contra la API HTTP sin ningún SDK. El worker de cada SDK es un cliente de estas cinco y nada más.

One lease

The daemon learns that a body is running from started, that the worker is alive from the heartbeats, and how the step ended from complete or fail. Miss the heartbeats and the lease is reclaimed; a later call about it is refused with a reason, never lost.

Worker Daemon the body runs POST /steps/claim long poll, up to 60 s a lease input, prior steps, ids POST /steps/{lease}/started before the body, always heartbeat every 10 s while it runs heartbeat heartbeat POST /steps/{lease}/complete output, state, usage run_status, next or a 409, one of four
LlamadaQué hace
POST /v1/api/workers/register Anuncia el worker y almacena las definiciones que guarda. La respuesta lleva lease_ttl_ms y heartbeat_ms, los dos números con los que funciona el resto del protocolo.
POST /v1/api/steps/claim Ofrece hasta max pasos ejecutables, y mantiene la solicitud abierta hasta wait_ms cuando no hay ninguno. El daemon sostiene una reclamación como mucho cuatro quintos de su tiempo máximo de solicitud, 24 segundos con el valor por defecto, y responde en el acto cuando deja de sostenerla, así que una reclamación puede volver vacía antes de wait_ms: reclama otra vez. Una reclamación se puede limitar a una sola ejecución, que es como un script lleva su propia ejecución hasta el final.
POST /v1/api/steps/{lease}/started Declara que el cuerpo está corriendo. Siempre antes del cuerpo: es lo que le dice al daemon la diferencia entre ofrecido y en marcha.
POST /v1/api/steps/{lease}/heartbeat Extiende el lease. La única prueba que tiene el daemon de que un worker sigue vivo.
POST /v1/api/steps/{lease}/complete, /fail Termina el paso: la salida, un parche al estado de la ejecución y el consumo al que el daemon pone precio; o un error con la clase que decide si se reintenta.

Leases

Un lease es un intento, en manos de un worker, por un tiempo acotado. Lleva la entrada renderizada, los pasos anteriores indexados por id, el estado y la correlación de la ejecución, una clave que es estable entre reintentos de este paso, y los ids de traza y de span del span de paso que abrió el daemon. Un cuerpo que registra sus propios spans a través del contexto del paso los cuelga bajo ese span, así que la llamada al modelo dentro de un paso aterriza en la traza de la ejecución a la profundidad correcta.

Un lease al que el worker deja de mandar heartbeats caduca. El daemon marca el intento como huérfano y, pasada una ventana de recuperación, lo vuelve a encolar bajo at_least_once o lo falla bajo at_most_once. A un worker que vuelve de una pausa y publica contra un lease ya recuperado no se le ignora: se le avisa.

Los cuatro rechazos

Una llamada de worker que el daemon no puede aceptar se rechaza con un 409 que lleva uno de cuatro motivos. La lista es cerrada, y el worker de cada SDK trata cada motivo por su nombre, porque un worker que los mete todos en la misma rama abandona pasos que ya había terminado o informa de un fallo donde hubo un éxito.

MotivoQué significaQué hace el worker
already_applied El complete o el fail anteriores de este mismo lease sí llegaron, y se perdió su respuesta. Lo toma como un éxito y no publica nada más.
fenced Existe un intento posterior, u otro lease terminó este. Abandona el trabajo y no publica nada más por este lease. Un heartbeat rechazado así cancela además el cuerpo en marcha a través de su contexto.
run_terminal La ejecución ha terminado, sea por acabar, por fallar, por agotar su plazo o por haber sido cancelada. Para, y deja de reclamar pasos de esa ejecución.
not_started Llegó un complete o un fail para un intento at_most_once cuyo started nunca llegó. Lo denuncia sin disimulo como un error del worker. Los workers de los SDK no pueden producirlo; uno escrito a mano sí.

El cuerpo

Un cuerpo recibe un contexto, su entrada renderizada y los pasos anteriores. El contexto es donde informa de lo que el daemon debe guardar: un parche al estado de la ejecución, que se fusiona en el complete y donde las claves de primer nivel reemplazan; los tokens que gastó, a los que el daemon pone precio con el mismo libro con el que tarifa los spans; y una señal de cancelación que se dispara cuando se pierde el lease o termina la ejecución, para que un cuerpo que se la pase a su propia E/S pare cuando debe. Los tokens se suman solos: un span que el cuerpo registre por el contexto, y todo span por debajo de él, añade su consumo al del paso cuando acaba, así que un cuerpo que registra sus llamadas al modelo como spans nunca suma a mano, y set_usage es la anulación explícita para uno que no registra ninguno.

Un cuerpo acaba devolviendo su salida o lanzando un error. Lanza el error retryable del SDK para que se reintente dentro del presupuesto del paso; lanza un fallo de paso tipado para nombrar cualquier otra clase; lo demás es fatal. El mensaje se envía al daemon y se muestra en el diario. La traza de pila no.

Un lease de una definición, de una versión o de un paso que el worker no guarda se falla como unservable y el cuerpo no llega a ejecutarse. El intento vuelve a la cola para un worker que sí lo guarde, sin gastar presupuesto de reintentos, y eso es lo que permite que dos versiones de un worker convivan durante un despliegue.

Escalar en horizontal

Ejecuta tantos workers como quieras contra un mismo daemon. Cada uno reclama hasta su propia concurrencia, el daemon entrega cada intento a exactamente uno de ellos, y el fencing hace que un lease que dos workers sostengan a la vez, por lo que sea, se resuelva con un único ganador. El id del worker queda registrado en cada intento que tomó, así que el diario dice qué proceso ejecutó un paso. Dale un nombre a cada proceso, o deja que el SDK lo derive del host.

Una reclamación es un long poll, así que una flota inactiva le cuesta al daemon una solicitud abierta por worker y ningún tráfico. Mientras espera, una reclamación busca trabajo cuando arranca una ejecución, termina un paso, se dispara un plazo o un evento reanuda una espera, y en los demás casos como mucho dos veces por segundo. Una flota ocupada está acotada por la concurrencia de los propios workers, y un cuerpo que tarda una hora cuesta un heartbeat cada diez segundos y nada más.

Claves

Las llamadas de worker piden el ámbito worker; arrancar, señalizar y cancelar ejecuciones piden execute. Los dos recurren a las claves de escritura cuando no están definidos, y una clave de administración tiene los dos. Un worker que solo sirve pasos no necesita una clave capaz de arrancar una ejecución, y un webhook que solo publica eventos no necesita una capaz de reclamar un paso. Consulta Configuración para los flags.

Las llamadas de worker no quedan anotadas en el registro de auditoría, aunque un lease lleva la entrada del paso y las salidas de los pasos anteriores. Son un bucle de máquina que reclama muchas veces por minuto, y una fila por reclamación enterraría las lecturas que hizo una persona. Volver a leer una ejecución por los endpoints de ejecuciones sí queda anotado; consulta Seguridad.

A continuación

  • Arrancar y seguir una ejecución, y responder a una espera: Ejecuciones.
  • La definición que sirve el worker: Workflows.
  • Todos los endpoints del protocolo de workers, generados a partir de la especificación: API HTTP, Workers.