Ir al contenido

Tutorial 3: Patrones avanzados

Con el Tutorial 1 (primer robot) y el Tutorial 2 (assets + automatización) ya tienes un proceso de producción completo. Esta última parte cubre los patrones que separan un robot que “corre” de uno gobernable: que una persona pueda intervenir, que pare limpio, que se orqueste con otros y que te avise cuando algo se desvía.

Los tres primeros patrones ya están en el código del ejemplo rpa-challenge y se activan con flags, sin alterar el flujo por defecto.

Un operador puede pulsar Stop o Kill sobre un job en marcha. Un robot bien hecho lo consulta dentro de su bucle y sale ordenadamente en vez de morir a medias. El ejemplo lo chequea antes de cada ronda:

# rpa_challenge/workflows.py — dentro de solve_challenge()
for ronda in range(1, ROUNDS + 1):
if nora.should_stop(): # ¿el operador pidió detener?
nora.log("warning", f"Detención solicitada; corto en la ronda {ronda}.")
break
item = nora.claim_next(QUEUE)
...

nora.should_stop() envuelve sdk.should_stop(), que devuelve True si la señal del job es stop o kill. Es no bloqueante y seguro: en dev local devuelve False, así que no cambia nada. Consúltalo en cualquier bucle largo.

A veces el robot necesita una decisión humana en mitad del flujo: “¿confirmo este pago?”, “¿qué sucursal proceso?”. ask_user pausa el job, muestra la pregunta en el dashboard y bloquea hasta la respuesta. En el ejemplo se activa con RPA_ASK=1:

# rpa_challenge/workflows.py — al inicio de solve_challenge()
if ASK_BEFORE_START:
if nora.ask_user("¿Empiezo a resolver el RPA Challenge?", ["", "No"]) == "No":
nora.log("info", "El operador canceló antes de empezar.")
return

ask_user(prompt, options=None, timeout=3600.0) combina request_user_input + wait_for_user_input y devuelve la opción elegida o el texto escrito por el operador (un str), así que puedes compararla directamente. Con options muestra botones; sin ellos, un campo de texto.

Ventana de terminal
# Probarlo en producción:
RPA_ASK=1 # como variable de entorno del proceso → el job pausa pidiendo confirmación

Distinto de ask_user: aquí lo que se aprueba es un item concreto de la cola. El robot lo manda a revisión, una persona ve sus data en el panel y aprueba (continúa) o rechaza (se salta). Patrón clásico human-in-the-loop para pagos, altas o cualquier paso que exija “cuatro ojos”. Se activa con RPA_REVIEW=1:

# rpa_challenge/workflows.py — dentro del bucle, antes de rellenar
if REVIEW_EACH_ITEM:
nora.send_for_review(QUEUE, item) # status -> pending_review
if nora.wait_review(QUEUE, item) == "rejected":
nora.log("warning", f"Ronda {ronda}: item rechazado; lo salto.")
continue
sequenceDiagram
    participant R as Robot
    participant N as NORA
    participant H as Revisor
    R->>N: send_for_review(item)
    Note over N: status → pending_review
    N-->>H: notificación en el panel
    H->>N: Aprobar / Rechazar
    R->>N: wait_review(item)  (bloquea)
    N-->>R: "approved" / "rejected"

Las funciones reales: sdk.send_queue_item_for_review(queue, item_id) y sdk.wait_for_queue_review(queue, item_id, timeout=3600.0) (devuelve "approved" o "rejected", o lanza TimeoutError). Quién puede revisar (revisores asignados vs. cualquier admin/operator) está en colas → aprobación humana.

Un solo robot resuelve un paso. Cuando un resultado de negocio necesita varios procesos en cierto orden —extraer → validar → cargar, con un reporte en paralelo— se modela como un flujo DAG: nodos (procesos) y aristas (dependencias source → target).

Editor de flujos DAG en NORA: nodos (procesos) conectados por aristas que definen el orden de ejecución

flowchart LR
    A[Extraer] --> B[Validar]
    A --> C[Generar reporte]
    B --> D[Cargar al ERP]
    C --> D
    D --> E[Notificar]

B y C corren en paralelo (solo dependen de A); D espera a ambos. Se crea con POST /api/v1/dags y se lanza con POST /api/v1/dags/{dag_id}/execute; cada ejecución lleva un status global y un node_states por nodo (pending/running/completed/ failed).

Crear y ejecutar flujos DAG se hace desde la consola, o por API con una sesión de dashboard de rol admin/operator (no con X-API-Key). Pasa el token de sesión en la cabecera Authorization: Bearer:

POST /api/v1/dags/3f1c…/execute HTTP/1.1
Host: nora-api.valisoftconsulting.com
Authorization: Bearer <token-de-sesion>

Cómo aplica al RPA Challenge: podrías separar cargar la cola (un proceso productor) de resolver (el consumidor) y encadenarlos con una arista. El detalle de nodos, aristas y orden topológico está en flujos DAG.

No tienes que vigilar los jobs a mano: NORA los analiza cada hora y marca lo que se sale de lo normal. Dos detectores activos:

Vista de Anomalías en NORA: jobs marcados por picos de duración o de tasa de error, con su severidad

TipoQué detectaCómo
duration_spikeUn job que tardó mucho más de lo habitualz-score vs. media de 30 días
error_rate_spikeUn proceso que de pronto falla mástasa de error semana actual vs. anterior

Severidad warning (2.0 < z < 3.0) o critical (z ≥ 3.0); las críticas de duración disparan notificación reutilizando el evento job_failed. Si tu robot del RPA Challenge normalmente tarda 40 s y un día tarda 5 min, te enteras sin mirar.

Se consultan con tu sesión del dashboard (no X-API-Key):

GET /api/v1/anomalies?severity=critical&is_resolved=false HTTP/1.1
Host: nora-api.valisoftconsulting.com

Detalle de los cálculos y cómo resolverlas en detección de anomalías.

Ya recorriste NORA de punta a punta sobre un mismo ejemplo:

TutorialQué añadiste
1 · Primer robotMáquina Online → proceso → cola, logs y progreso
2 · Assets y automatizaciónCredenciales cifradas, cron y webhook/API
3 · Patrones avanzadosStop limpio, input atendido, revisión humana, DAG, anomalías

El esqueleto no cambió en ningún momento: el robot lee de la cola, hace su parte y reporta. Todo lo demás —credenciales, disparo, gobierno, orquestación, vigilancia— lo pone NORA alrededor. Eso es lo que hace que el mismo patrón te sirva para el RPA Challenge hoy y para tu proceso de negocio mañana.