> ## 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 con un schedule

> 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 trigger de schedule 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 ocurrencias retenidas hasta que lo ejecutas o lo descartas.

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

## Antes de empezar

***

* Un workflow en estado `draft`. Solo un workflow en draft acepta una edición, así que escribe el trigger antes de activarlo. Consulta [Primeros pasos con Flowker](/es/reference/flowker/flowker-api-quick-start) para el camino de creación y activación.
* El binario worker en ejecución con el scheduler habilitado. `SCHEDULER_ENABLED` se resuelve como `true` a menos que lo pongas en `false`, y la cola necesita `SCHEDULER_REDIS_HOST`: sin host, el binario worker no arranca y ningún workflow programado se dispara. Revisa esa variable primero cuando tus schedules nunca se disparan. Consulta [Variables del scheduler](/es/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 node del trigger de schedule

***

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

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

El trigger de schedule es un node con `type: "trigger"` y estos campos en su `data`:

| Campo         | Cuándo lo defines | Valor                                                                                                                            |
| ------------- | ----------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `triggerType` | Siempre           | `"schedule"`.                                                                                                                    |
| `cron`        | Siempre           | La cadencia, como una expresión cron estándar de 5 campos: `minuto hora día-del-mes mes día-de-la-semana`.                       |
| `timezone`    | Opcional          | El identificador IANA de la zona a la que pertenecen los campos del cron, por ejemplo `"America/Sao_Paulo"`. Por defecto, `UTC`. |
| `enabled`     | Opcional          | `false` impide que el schedule se dispare mientras el workflow sigue activo. Por defecto, `true`.                                |

### Qué acepta la expresión cron

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 `0` y `7` significan domingo. Cuando restringes el día del mes y el día de la semana a la vez, el schedule se dispara en un día que coincide con cualquiera de los dos campos: `0 9 13 * 5` se dispara el día 13 y todos los viernes.

Un minuto es la cadencia más fina que una expresión de 5 campos puede expresar. Para algo más rápido, atiende la llamada en el momento en que llega con un [trigger de webhook](/es/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 se sostiene. Estas formas no se sostienen:

* 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 hora de reloj de pared en la zona que nombras, y cada hora que devuelve la API es UTC. Un schedule `0 9 * * *` en `America/Sao_Paulo` reporta `12:00Z`. Una zona que observa horario de verano mantiene la hora de reloj de pared 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 diario theme={null}
  {
    "id": "trigger-1",
    "type": "trigger",
    "name": "Liquidación diaria",
    "position": { "x": 0, "y": 0 },
    "data": {
      "triggerType": "schedule",
      "cron": "0 9 * * *",
      "timezone": "America/Sao_Paulo"
    }
  }
  ```

  ```json cada 15 minutos theme={null}
  {
    "id": "trigger-1",
    "type": "trigger",
    "name": "Consultar nuevos extractos",
    "position": { "x": 0, "y": 0 },
    "data": {
      "triggerType": "schedule",
      "cron": "*/15 * * * *"
    }
  }
  ```

  ```json días hábiles, en pausa theme={null}
  {
    "id": "trigger-1",
    "type": "trigger",
    "name": "Conciliación de días hábiles",
    "position": { "x": 0, "y": 0 },
    "data": {
      "triggerType": "schedule",
      "cron": "30 7 * * 1-5",
      "timezone": "America/Sao_Paulo",
      "enabled": false
    }
  }
  ```

  ```json mensual theme={null}
  {
    "id": "trigger-1",
    "type": "trigger",
    "name": "Lote de apertura de mes",
    "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 node con el resto de tu workflow a [Crear un workflow](/es/reference/flowker/create-workflow), o a [Actualizar un workflow](/es/reference/flowker/update-workflow) si el draft ya existe. Flowker valida el cron aquí.
  </Step>

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

    ```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 por defecto es `10`. Un valor fuera de ese rango responde `FLK-0304`.
  </Step>

  <Step title="Actívalo">
    Llama a [Activar un workflow](/es/reference/flowker/activate-workflow). En menos de un minuto el engine registra la próxima ocurrencia y la encola para su horario.

    ```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 próximo disparo, nunca un calendario de disparos futuros. Cuando esa ocurrencia se ejecuta, el engine registra el disparo siguiente, así que la cadencia se sostiene sola, una ocurrencia a la vez.

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

***

Una ocurrencia queda **retenida** cuando el engine llega a ella más de un minuto después de su horario y nadie ha pedido que ese horario se ejecute: el servicio estaba caído, la cola venía atrasada, el proceso se reinició. Flowker nunca ejecuta una ocurrencia retenida por su cuenta: la guarda para tu decisión, en el estado `pending-review`. Retener es el único resultado que no es terminal: una ocurrencia retenida sigue accionable hasta que la ejecutes o la descartes.

Flowker nunca rellena un horario que pasó. Así que la lista de retenidas guarda los disparos que Flowker ya había registrado y no pudo ejecutar — no una entrada por cada horario que pasó durante una caída — y la cadencia misma se reanuda desde el próximo horario futuro.

Una ocurrencia queda **omitida** cuando el engine la tomó y la cerró sin ejecutar el workflow. Una ocurrencia omitida es terminal y lleva un `skipReason`:

| `skipReason`          | Qué pasó                                                                                                                              |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `active-run`          | Otra ejecución de este workflow todavía estaba en curso. Un schedule ejecuta una ocurrencia a la vez, así que este disparo se apartó. |
| `workflow-gone`       | El workflow fue eliminado, o no estaba activo cuando la ocurrencia llegó al engine.                                                   |
| `execution-duplicate` | El trabajo de ese horario ya se había ejecutado, así que el engine no lo ejecutó dos veces.                                           |

Las dos clases no se separan por el momento del disparo. Una cosa sí la decide ese momento: un horario tardío que nunca pediste ejecutar aparece en la lista de retenidas, nunca en la de omitidas. Después de que pides que un horario retenido se ejecute, su antigüedad deja de detenerlo. El engine lo toma entonces como cualquier otra ocurrencia, y los tres motivos de arriba pueden cerrarlo. Así que un `scheduledFor` muy antiguo es normal en la lista de omitidas, y no significa que el horario se disparó a tiempo. El [Paso 4](#paso-4-ejecuta-o-descarta-una-ocurrencia-retenida) 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/flowker/list-parked-scheduled-occurrences) las devuelve de la más antigua a la más reciente.

    ```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 el horario que representa la ocurrencia, y `status` es lo que decide si puedes actuar sobre ella.

    Esta ruta no acepta `limit` ni cursor de paginación, y devuelve como máximo 100 ocurrencias. Planea una recuperación masiva con eso en mente: trabaja las filas que recibes y vuelve a leer la lista. El conteo de más abajo informa el total real. Descartar la lista completa también cubre todas las ocurrencias pendientes de revisión, no solo las 100 que muestra una sola lectura.
  </Step>

  <Step title="Lista las ocurrencias omitidas">
    [Listar ocurrencias programadas omitidas](/es/reference/flowker/list-skipped-scheduled-occurrences) las devuelve de la más antigua a la más reciente, cada una con su `skipReason`. `limit` acepta de `1` a `50`.

    ```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" }
    ```

    Una serie de omisiones `active-run` significa 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/flowker/count-pending-review-occurrences) responde por todo el tenant en una sola llamada, que es lo que consultas para un badge de revisión. El mapa es disperso: un workflow sin nada en espera no aparece en é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 limitar los conteos a los workflows que te interesan.
  </Step>
</Steps>

Las dos 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 "nada que revisar aquí".

<Tip>
  El Console muestra las mismas tres lecturas. Abre el panel **Schedule** desde la lista de workflows para ver el estado del schedule, las próximas ejecuciones y las ejecuciones pendientes de revisión. Consulta [Visión general de workflows](/es/flowker/console/workflows-overview).
</Tip>

## Paso 4: Ejecuta o descarta una ocurrencia retenida

***

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

Una ejecución que pides sale de la lista de retenidas al instante, y la antigüedad del horario ya no la detiene. No promete que el workflow se ejecute:

* **El workflow se ejecuta.** La ejecución aparece en [Listar ejecuciones](/es/reference/flowker/list-executions) para ese workflow.
* **El engine cierra la ocurrencia como omitida.** Sale de la lista de retenidas hacia la de omitidas con uno de los tres motivos de arriba. `active-run` significa que otra ejecución del workflow todavía estaba en curso. `workflow-gone` significa que el workflow no estaba activo cuando tu ejecución llegó al engine. `execution-duplicate` significa que el trabajo de ese horario ya se había ejecutado.

Una omisión de tu propia ejecución es tan terminal como cualquier otra, así que una segunda ejecución o un descarte sobre ella responden `FLK-0755`. Lee las dos listas antes de concluir algo sobre un horario que intentaste recuperar. La fila omitida puede registrar el rechazo de tu recuperación, no 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/flowker/run-parked-occurrence) la mueve a `queued` y la entrega al mismo camino de ejecución que usa un disparo programado. Arranca en uno o dos segundos.

    ```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 ese único horario. No desplaza la cadencia: el próximo disparo sigue siendo el que el engine ya planeó.
  </Step>

  <Step title="Descarta una ocurrencia">
    [Descartar una ocurrencia retenida](/es/reference/flowker/discard-parked-occurrence) la mueve a `discarded`, que es terminal. La ocurrencia nunca se ejecuta y sale de 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/flowker/discard-all-parked-occurrences) descarta, en una sola escritura, todas las ocurrencias de ese workflow que están pendientes 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, que están pendientes de revisión. Deja el schedule funcionando, deja intactas las próximas ocurrencias y no toca las ocurrencias de otro workflow ni las que ya se ejecutaron, fallaron, fueron omitidas o fueron descartadas antes.
</Warning>

## Confirma que funcionó

***

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

## Cambia o pausa una cadencia

***

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

1. [Desactiva el workflow](/es/reference/flowker/deactivate-workflow). Flowker deja de registrar nuevas ocurrencias para él.
2. [Muévelo a draft](/es/reference/flowker/move-workflow-to-draft).
3. [Actualiza el workflow](/es/reference/flowker/update-workflow) con el nuevo valor de `cron`, `timezone` o `enabled`.
4. [Actívalo](/es/reference/flowker/activate-workflow). En menos de un minuto el engine registra la próxima ocurrencia de la nueva cadencia.

Flowker no rellena los horarios que pasaron mientras el workflow estuvo inactivo, y las ocurrencias retenidas sobreviven a los cuatro pasos: siguen listadas y siguen accionables una vez que el workflow está activo de nuevo.

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

## Cuando algo falla

***

| 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](#qué-acepta-la-expresión-cron).                                                                                                        |
| `FLK-0118` | Listas las próximas ocurrencias.                | El workflow no lleva un trigger de schedule, o su cron no es una expresión que Flowker pueda calcular. Revisa el `triggerType` y el `cron` del node trigger.                                                                          |
| `FLK-0100` | Listas las próximas ocurrencias.                | Ningún workflow de tu tenant tiene ese id.                                                                                                                                                                                            |
| `FLK-0002` | Cualquiera de estas llamadas.                   | Un id del path no es un UUID válido.                                                                                                                                                                                                  |
| `FLK-0304` | Listas las próximas ocurrencias o las omitidas. | `limit` está fuera de `1`–`50`.                                                                                                                                                                                                       |
| `FLK-0755` | Ejecutas o descartas una ocurrencia.            | La ocurrencia no está pendiente de revisión. Puede que tu propia ejecución ya la haya movido, o que se haya ejecutado, haya sido omitida o haya sido descartada. Lee la lista de retenidas y la 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:

* **Las próximas ocurrencias se listan, pero nada se ejecuta nunca.** La API calcula la cadencia por su cuenta, mientras que el binario worker es el que la dispara. Confirma que el worker está en ejecución y que `SCHEDULER_REDIS_HOST` está definido. Consulta [Variables del scheduler](/es/flowker/flowker-environment-variables#scheduler).
* **No se registra nada nuevo para un workflow activo.** Revisa `enabled` en el node trigger: `false` mantiene el workflow activo y su schedule en silencio.

## Qué sigue

***

<CardGroup cols={2}>
  <Card title="Configurar un trigger de webhook" icon="webhook" href="/es/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/flowker/workflow-design-guide">
    Construye el resto del grafo al que entra el trigger.
  </Card>
</CardGroup>
