> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Ejecutar un workflow según una programación

> Inicia un workflow de Flowker con una cadencia, lee las ocurrencias que planea ejecutar y decide qué pasa con una ocurrencia que no pudo ejecutarse a tiempo.

Un disparador de programación inicia un workflow con una cadencia que escribes como una expresión cron. Flowker registra cada disparo como una ocurrencia, así que un disparo que no pudo ocurrir a tiempo no se pierde. Espera en una lista de retenidas hasta que lo ejecutes o lo descartes.

Usa esta página para escribir el disparador, confirmar la cadencia y trabajar la lista de retenidas.

## Antes de empezar

***

* Un workflow en estado `draft`. Solo un workflow en borrador acepta una edición, así que escribe el disparador antes de activarlo. Consulta [Primeros pasos con Flowker](/es/reference/products/flowker/flowker-api-quick-start) para conocer el camino de creación y activación.
* El binario del worker en ejecución con el scheduler habilitado. La variable `SCHEDULER_ENABLED` se resuelve a `true` a menos que la establezcas en `false`, y la cola necesita `SCHEDULER_REDIS_HOST`. Sin host, el binario del worker no arranca y ningún workflow programado se dispara. Revisa esa variable primero cuando tus programaciones nunca se disparan. Consulta [Variables del scheduler](/es/products/flowker/flowker-environment-variables#scheduler).
* El permiso `read` sobre el recurso `workflows` para listar ocurrencias y conteos, y `update` sobre el mismo recurso para ejecutar o descartar una.

## Paso 1: Escribe el nodo disparador de programación

***

Los disparadores vienen integrados. Los descubres en el catálogo y nunca creas uno. [Obtener un disparador del catálogo](/es/reference/products/flowker/get-catalog-trigger) devuelve el JSON Schema del disparador de programación desde la instancia en ejecución:

```bash theme={null}
curl -s http://localhost:4021/v1/catalog/triggers/schedule | jq -r '.schema' | jq .
```

El disparador de programación es un nodo con `type: "trigger"` y estos campos en su `data`:

| Campo         | Cuándo lo estableces | Valor                                                                                                                                                                                                                   |
| ------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `triggerType` | Siempre              | `"schedule"`.                                                                                                                                                                                                           |
| `cron`        | Siempre              | La cadencia, como una expresión cron estándar de 5 campos: `minute hour day-of-month month day-of-week`.                                                                                                                |
| `timezone`    | Opcional             | El identificador IANA de la zona a la que pertenecen los campos del cron, como `"America/Sao_Paulo"`. De forma predeterminada es `UTC`; una zona horaria vacía o que no se puede resolver también se evalúa como `UTC`. |
| `enabled`     | Opcional             | `false` impide que la programación se dispare mientras el workflow sigue activo. De forma predeterminada es `true`.                                                                                                     |

<h3 id="what-the-cron-expression-accepts">
  Qué acepta la expresión cron
</h3>

Cinco campos, separados por espacios. Cada campo acepta `*`, un valor, una lista (`0,30`), un rango (`9-17`) o un paso (`*/15`, `9-17/2`). El día de la semana va de `0` a `7`, donde tanto `0` como `7` significan domingo. Cuando restringes el día del mes y el día de la semana al mismo tiempo, la programación se dispara en un día que coincide con cualquiera de los dos campos. La expresión `0 9 13 * 5` se dispara el día 13 y cada viernes.

Un minuto es la cadencia más fina que puede expresar una expresión de 5 campos. Para algo más rápido, recibe la llamada según llega con un [disparador de webhook](/es/products/flowker/configuring-a-webhook-trigger).

Flowker verifica la expresión cuando guardas el workflow y otra vez cuando lo activas, y responde `FLK-0117` cuando no es válida. Estas formas no son válidas:

* Una expresión de seis campos, como `*/30 * * * * *`.
* Una macro, como `@daily` o `@every 5m`.
* Un día o un mes con nombre, como `MON`, `MON-FRI` o `sun`.
* Un token `L` o `#`, como `0 9 L * *` o `0 9 * * 5#2`.
* Un valor fuera del rango de su campo, como `60` minutos, `24` horas, día del mes `0` o `32`, mes `13`, o día de la semana `8`.
* Un paso `/0`.

### Cómo funciona la zona horaria

Los campos del cron son la hora de reloj en la zona que nombras, y cada hora que devuelve la API es UTC. Una programación `0 9 * * *` en `America/Sao_Paulo` reporta `12:00Z`. Una zona que observa el horario de verano mantiene la hora de reloj a través del cambio: la misma expresión en `America/New_York` reporta `14:00Z` en invierno y `13:00Z` en verano.

<CodeGroup>
  ```json daily theme={null}
  {
    "id": "trigger-1",
    "type": "trigger",
    "name": "Daily settlement",
    "position": { "x": 0, "y": 0 },
    "data": {
      "triggerType": "schedule",
      "cron": "0 9 * * *",
      "timezone": "America/Sao_Paulo"
    }
  }
  ```

  ```json every 15 minutes theme={null}
  {
    "id": "trigger-1",
    "type": "trigger",
    "name": "Poll for new statements",
    "position": { "x": 0, "y": 0 },
    "data": {
      "triggerType": "schedule",
      "cron": "*/15 * * * *"
    }
  }
  ```

  ```json weekdays, paused theme={null}
  {
    "id": "trigger-1",
    "type": "trigger",
    "name": "Weekday reconciliation",
    "position": { "x": 0, "y": 0 },
    "data": {
      "triggerType": "schedule",
      "cron": "30 7 * * 1-5",
      "timezone": "America/Sao_Paulo",
      "enabled": false
    }
  }
  ```

  ```json monthly theme={null}
  {
    "id": "trigger-1",
    "type": "trigger",
    "name": "Month-open batch",
    "position": { "x": 0, "y": 0 },
    "data": {
      "triggerType": "schedule",
      "cron": "0 3 1 * *",
      "timezone": "UTC"
    }
  }
  ```
</CodeGroup>

## Paso 2: Activa el workflow y lee la cadencia

***

<Steps>
  <Step title="Guarda el workflow">
    Envía el nodo con el resto de tu workflow a [Crear un workflow](/es/reference/products/flowker/create-workflow), o a [Actualizar un workflow](/es/reference/products/flowker/update-workflow) si el borrador ya existe. Flowker valida el cron aquí.
  </Step>

  <Step title="Revisa la cadencia antes de comprometerte con ella">
    [Listar las próximas ocurrencias programadas](/es/reference/products/flowker/list-upcoming-scheduled-occurrences) calcula los próximos disparos directamente desde el disparador, así puedes leerlos mientras el workflow sigue siendo un borrador.

    ```bash theme={null}
    curl -s "http://localhost:4021/v1/workflows/019c96a0-0ac0-7de9-9f53-9cf842a2ee5a/schedule/upcoming?limit=3" | jq .
    ```

    ```json theme={null}
    {
      "occurrences": [
        { "scheduledFor": "2026-08-01T12:00:00Z" },
        { "scheduledFor": "2026-08-02T12:00:00Z" },
        { "scheduledFor": "2026-08-03T12:00:00Z" }
      ]
    }
    ```

    `limit` acepta de `1` a `50` y de forma predeterminada es `10`. Un valor fuera de ese rango responde `FLK-0304`.
  </Step>

  <Step title="Actívalo">
    Llama a [Activar un workflow](/es/reference/products/flowker/activate-workflow). El productor con control de liderazgo barre en un intervalo predeterminado de 60 segundos. Después de un barrido exitoso, Flowker registra y encola la siguiente ocurrencia para su franja.

    ```bash theme={null}
    curl -s -X POST http://localhost:4021/v1/workflows/019c96a0-0ac0-7de9-9f53-9cf842a2ee5a/activate | jq .
    ```
  </Step>
</Steps>

Flowker registra solo el siguiente disparo, nunca un calendario de disparos futuros. Cuando esa ocurrencia se ejecuta, el motor registra el disparo posterior, así que la cadencia se lleva hacia adelante una ocurrencia a la vez.

## Paso 3: Ve qué ocurrencias no se ejecutaron

***

Una ocurrencia **queda retenida** cuando el motor la alcanza más de un minuto después de su franja y nadie ha pedido que esa franja se ejecute. Las causas comunes son un servicio que estaba caído, una cola atrasada o un proceso que se reinició. Flowker nunca ejecuta una ocurrencia retenida por su cuenta. La guarda para tu decisión, en el estado `pending-review`. Una ocurrencia retenida sigue disponible para los endpoints de ejecución y de descarte.

Flowker nunca rellena en retroactivo una franja que pasó. Por eso la lista de retenidas contiene los disparos que Flowker ya había registrado y no pudo ejecutar. No contiene una entrada por cada franja que pasó durante una caída. La cadencia misma se reanuda desde la siguiente franja futura.

Una ocurrencia queda **omitida** cuando el motor la tomó y la cerró sin ejecutar el workflow. El scheduler nunca vuelve a ejecutar una ocurrencia omitida. Una ocurrencia omitida lleva un `skipReason`, y los endpoints de ejecución y de descarte no la aceptan:

| `skipReason`          | Qué pasó                                                                                                                           |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `active-run`          | Otra ejecución de este workflow seguía en curso. Una programación ejecuta una ocurrencia a la vez, así que este disparo se retiró. |
| `workflow-gone`       | El workflow se eliminó, o no estaba activo cuando la ocurrencia llegó al motor.                                                    |
| `execution-duplicate` | El trabajo de esa franja ya se había ejecutado, así que el motor no lo ejecutó dos veces.                                          |

Las dos clases no se separan por el momento. Una cosa sí decide el momento: una franja tardía que nunca pediste ejecutar cae en la lista de retenidas, nunca en la lista de omitidas. Después de que pides que una franja retenida se ejecute, su antigüedad deja de frenarla. El motor la toma entonces como cualquier otra ocurrencia, y las tres razones de arriba pueden cerrarla. Por eso un `scheduledFor` muy en el pasado es normal en la lista de omitidas, y no significa que la franja se disparó a tiempo. El [Paso 4](#step-4-run-or-discard-a-parked-occurrence) cubre en qué puede terminar tu propia ejecución.

Tres lecturas cubren el panorama completo:

<Steps>
  <Step title="Lista las ocurrencias retenidas de un workflow">
    [Listar ocurrencias programadas retenidas](/es/reference/products/flowker/list-parked-scheduled-occurrences) las devuelve con las más antiguas primero.

    ```bash theme={null}
    curl -s http://localhost:4021/v1/workflows/019c96a0-0ac0-7de9-9f53-9cf842a2ee5a/schedule/missed | jq .
    ```

    ```json theme={null}
    {
      "occurrences": [
        {
          "id": "019c96a0-3f21-7b44-8d0e-5a1c7e2b9f30",
          "workflowId": "019c96a0-0ac0-7de9-9f53-9cf842a2ee5a",
          "status": "pending-review",
          "cronExpr": "0 9 * * *",
          "timezone": "America/Sao_Paulo",
          "scheduledFor": "2026-07-29T12:00:00Z",
          "attempts": 0,
          "createdAt": "2026-07-29T11:00:04Z",
          "updatedAt": "2026-07-30T08:12:41Z"
        }
      ]
    }
    ```

    `scheduledFor` es la franja que representa la ocurrencia, y `status` es lo que decide si puedes actuar sobre ella.

    Esta ruta no acepta `limit` ni cursor de página, y devuelve como máximo 100 ocurrencias. Planifica una recuperación masiva alrededor de eso: trabaja las filas que obtienes y luego lee la lista de nuevo.

    El conteo de abajo reporta el total en `pending-review`. La lista de retenidas puede contener más filas que ese conteo, porque también incluye ocurrencias `missed`. El estado `missed` dura poco: una franja tardía lo mantiene mientras el motor retiene la franja como `pending-review`. Los endpoints de ejecución y de descarte no aceptan ese estado, así que lee la lista de nuevo y actúa cuando la fila muestre `pending-review`. Descartar la lista completa también cubre cada ocurrencia pendiente de revisión, no solo las 100 que te muestra una sola lectura.
  </Step>

  <Step title="Lista las ocurrencias omitidas">
    [Listar ocurrencias programadas omitidas](/es/reference/products/flowker/list-skipped-scheduled-occurrences) las devuelve con las más antiguas primero, cada una con su `skipReason`. Cuando se proporciona, `limit` acepta de `1` a `50`. Cuando se omite, de forma predeterminada es `100`.

    ```bash theme={null}
    curl -s "http://localhost:4021/v1/workflows/019c96a0-0ac0-7de9-9f53-9cf842a2ee5a/schedule/skipped?limit=10" | jq '.occurrences[] | {scheduledFor, skipReason}'
    ```

    ```json theme={null}
    { "scheduledFor": "2026-07-28T12:00:00Z", "skipReason": "active-run" }
    ```

    Omisiones repetidas por `active-run` significan que el workflow tarda más que el intervalo entre dos disparos. Amplía la cadencia, o haz que el workflow termine más rápido.
  </Step>

  <Step title="Cuenta lo que espera en todos los workflows">
    [Contar ocurrencias pendientes de revisión](/es/reference/products/flowker/count-pending-review-occurrences) responde por todo el tenant en una sola llamada, que es lo que consultas para una insignia de revisión. El mapa es disperso: un workflow sin nada en espera está ausente de él.

    ```bash theme={null}
    curl -s http://localhost:4021/v1/workflows/schedule/pending-review-counts | jq .
    ```

    ```json theme={null}
    {
      "counts": {
        "019c96a0-0ac0-7de9-9f53-9cf842a2ee5a": 2
      }
    }
    ```

    Agrega `?workflowIds=<id>,<id>` para acotar los conteos a los workflows que te interesan.
  </Step>
</Steps>

Ambas listas responden `200` con un arreglo `occurrences` vacío para un id de workflow que tu tenant no posee, así que una lista vacía significa "aquí no hay nada que revisar".

Flowker expone los datos subyacentes de la programación a través de sus APIs de próximas, de retenidas y de conteo de pendientes de revisión. Consulta la documentación de Console para orientación sobre la UI.

<h2 id="step-4-run-or-discard-a-parked-occurrence">
  Paso 4: Ejecuta o descarta una ocurrencia retenida
</h2>

***

La ejecución y el descarte actúan sobre una ocurrencia cuyo `status` es `pending-review`. Cualquier otro estado responde `FLK-0755`, lo que también hace segura una llamada repetida: la segunda llamada responde el mismo error en lugar de actuar dos veces. Tu propia ejecución pone la ocurrencia en uno de esos otros estados: deja `pending-review` de inmediato.

Una ejecución que pides deja la lista de retenidas de inmediato, y la antigüedad de la franja ya no la frena. No promete que el workflow se ejecute:

* **El workflow se ejecuta.** La ejecución aparece en [Listar ejecuciones](/es/reference/products/flowker/list-executions) para ese workflow.
* **El motor cierra la ocurrencia como omitida.** Deja la lista de retenidas por la lista de omitidas con una de las tres razones de arriba. Una razón `active-run` significa que otra ejecución del workflow seguía en curso. Una razón `workflow-gone` significa que el workflow no estaba activo cuando tu ejecución llegó al motor. Una razón `execution-duplicate` significa que el trabajo de esa franja ya se había ejecutado.

Después de tu ejecución, el scheduler nunca vuelve a ejecutar una ocurrencia omitida, y los endpoints de ejecución y de descarte no la aceptan. Lee ambas listas antes de concluir algo sobre una franja que intentaste recuperar. La fila omitida puede registrar el rechazo de tu recuperación, no el del disparo original.

Mantén el workflow activo mientras trabajas la lista. Una ejecución recarga el workflow, y un workflow que no está activo cierra la ocurrencia como una omisión `workflow-gone` en lugar de ejecutarla.

<Steps>
  <Step title="Ejecuta una ocurrencia">
    [Ejecutar una ocurrencia retenida](/es/reference/products/flowker/run-parked-occurrence) la mueve a `queued` y encola una ejecución forzada en el mismo camino de ejecución que usa un disparo programado. El reenviador de tareas diferidas revisa cada segundo de forma predeterminada. La hora de inicio real depende de la disponibilidad del worker y de la capacidad de la cola.

    ```bash theme={null}
    curl -s -X POST http://localhost:4021/v1/workflows/019c96a0-0ac0-7de9-9f53-9cf842a2ee5a/schedule/missed/019c96a0-3f21-7b44-8d0e-5a1c7e2b9f30/run | jq '{id, status}'
    ```

    ```json theme={null}
    { "id": "019c96a0-3f21-7b44-8d0e-5a1c7e2b9f30", "status": "queued" }
    ```

    La ejecución cubre esa única franja. No desplaza la cadencia: el siguiente disparo sigue siendo el que el motor ya planeó.
  </Step>

  <Step title="Descarta una ocurrencia">
    [Descartar una ocurrencia retenida](/es/reference/products/flowker/discard-parked-occurrence) la mueve a `discarded`, que es terminal. La ocurrencia nunca se ejecuta y deja la lista de retenidas.

    ```bash theme={null}
    curl -s -X POST http://localhost:4021/v1/workflows/019c96a0-0ac0-7de9-9f53-9cf842a2ee5a/schedule/missed/019c96a0-3f21-7b44-8d0e-5a1c7e2b9f30/discard | jq '{id, status}'
    ```

    ```json theme={null}
    { "id": "019c96a0-3f21-7b44-8d0e-5a1c7e2b9f30", "status": "discarded" }
    ```
  </Step>

  <Step title="Limpia toda la lista de retenidas de un workflow">
    [Descartar todas las ocurrencias retenidas](/es/reference/products/flowker/discard-all-parked-occurrences) descarta, en una sola escritura, cada ocurrencia de ese workflow pendiente de revisión, y reporta cuántas movió.

    ```bash theme={null}
    curl -s -X POST http://localhost:4021/v1/workflows/019c96a0-0ac0-7de9-9f53-9cf842a2ee5a/schedule/missed/discard-all | jq .
    ```

    ```json theme={null}
    { "discarded": 7 }
    ```

    Sin nada pendiente de revisión responde `200` con `"discarded": 0`, así que una llamada repetida es segura.
  </Step>
</Steps>

<Warning>
  Un descarte no se puede deshacer, y nunca ejecuta nada. Lee la lista de retenidas antes de limpiarla.

  Descartar todas las ocurrencias retenidas cubre exactamente las ocurrencias de ese único workflow, en tu tenant, pendientes de revisión. Deja la programación misma en marcha y no toca las próximas ocurrencias. No toca las ocurrencias de otro workflow, ni las ocurrencias que ya se ejecutaron, fallaron, fueron omitidas o fueron descartadas antes.
</Warning>

## Confirma que funcionó

***

* La cadencia está sana cuando [Listar las próximas ocurrencias programadas](/es/reference/products/flowker/list-upcoming-scheduled-occurrences) devuelve franjas futuras y la lista de retenidas se mantiene corta.
* Una ejecución funcionó cuando la ocurrencia ha dejado la lista de retenidas y la ejecución aparece en [Listar ejecuciones](/es/reference/products/flowker/list-executions) para ese workflow.
* Un descarte funcionó cuando la ocurrencia ha dejado la lista de retenidas y el conteo de pendientes de revisión de ese workflow ha bajado.

## Cambia o pausa una cadencia

***

Solo un workflow en borrador acepta una edición, así que un cambio de cadencia son cuatro llamadas:

1. [Desactiva el workflow](/es/reference/products/flowker/deactivate-workflow). Flowker deja de registrar nuevas ocurrencias para él.
2. [Muévelo a borrador](/es/reference/products/flowker/move-workflow-to-draft).
3. [Actualiza el workflow](/es/reference/products/flowker/update-workflow) con el nuevo valor de `cron`, `timezone` o `enabled`.
4. [Actívalo](/es/reference/products/flowker/activate-workflow). El productor con control de liderazgo barre en un intervalo predeterminado de 60 segundos. Después de un barrido exitoso, Flowker registra y encola la siguiente ocurrencia de la nueva cadencia.

Flowker no rellena en retroactivo las franjas que pasaron mientras el workflow estuvo inactivo. Las ocurrencias retenidas sobreviven a los cuatro pasos. Siguen listadas y siguen siendo accionables una vez que el workflow está activo de nuevo.

<Note>
  Una ocurrencia retenida que Flowker registró antes del cambio sigue pendiente de revisión. Lee la lista de retenidas después de un cambio de cadencia, y limpia lo que ya no quieras.
</Note>

## Cuando algo sale mal

***

| Código     | Cuándo ocurre                           | Qué hacer                                                                                                                                                                                                                                   |
| ---------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FLK-0117` | Guardas o activas el workflow.          | El cron no es una expresión estándar de 5 campos. Compáralo con [Qué acepta la expresión cron](#what-the-cron-expression-accepts).                                                                                                          |
| `FLK-0118` | Listas las próximas ocurrencias.        | El workflow no lleva un disparador de programación, o su cron no es una expresión que Flowker pueda calcular. Revisa el `triggerType` y el `cron` del nodo disparador.                                                                      |
| `FLK-0100` | Listas las próximas ocurrencias.        | Ningún workflow de tu tenant tiene ese id.                                                                                                                                                                                                  |
| `FLK-0002` | Cualquiera de estas llamadas.           | Un id de la ruta no es un UUID válido.                                                                                                                                                                                                      |
| `FLK-0304` | Listas ocurrencias próximas u omitidas. | `limit` está fuera de `1`–`50`.                                                                                                                                                                                                             |
| `FLK-0755` | Ejecutas o descartas una ocurrencia.    | La ocurrencia no está pendiente de revisión. Tu propia ejecución puede haberla movido ya, o puede haberse ejecutado, haber sido omitida o haber sido descartada. Lee la lista de retenidas y la lista de omitidas antes de volver a llamar. |
| `FLK-0760` | Ejecutas o descartas una ocurrencia.    | Ninguna ocurrencia de ese workflow tiene ese id. Toma el id de la lista de retenidas del mismo workflow.                                                                                                                                    |

Dos fallas no responden ningún código de error:

* **La lista de próximas muestra ocurrencias, pero nunca se ejecuta nada.** La API calcula la cadencia por su cuenta, mientras que el binario del worker es lo que la dispara. Confirma que el worker se ejecuta y que estableciste `SCHEDULER_REDIS_HOST`. Consulta [Variables del scheduler](/es/products/flowker/flowker-environment-variables#scheduler).
* **Flowker no registra nada nuevo para un workflow activo.** Revisa `enabled` en el nodo disparador: `false` mantiene el workflow activo y su programación en silencio.

## Qué sigue

***

<CardGroup cols={2}>
  <Card title="Configurar un disparador de webhook" icon="webhook" href="/es/products/flowker/configuring-a-webhook-trigger">
    Inicia el mismo workflow desde una llamada HTTP entrante en lugar de una cadencia.
  </Card>

  <Card title="Guía de diseño de workflows" icon="diagram-project" href="/es/products/flowker/workflow-design-guide">
    Construye el resto del grafo al que entra el disparador.
  </Card>
</CardGroup>
