Ir al contenido

Scheduled node

El nodo Scheduled es un tipo especial de nodo Action que se ejecuta periódicamente a intervalos regulares definidos por un planificador tipo cron. A diferencia de los nodos Action normales, que se ejecutan una vez cuando el flujo de trabajo llega a ellos, los nodos Scheduled se ejecutan repetidamente hasta que se cumplen ciertas condiciones o hasta que finaliza el flujo de trabajo.

Un nodo Scheduled se crea usando un nodo Action con un nombre que empieza por el prefijo reservado scheduled_. Cuando el motor de flujos de trabajo detecta este prefijo, trata automáticamente la acción como una tarea programada que el planificador cron del sistema ejecutará periódicamente.

Propiedad Tipo Descripción
Name Texto El nombre debe empezar por el prefijo scheduled_ seguido de un nombre descriptivo (por ejemplo, “scheduled_wait_for_child_workflows”, “scheduled_check_completion”). El prefijo indica al motor de flujos de trabajo que trate este nodo como una acción programada.
Id Número Identificador único asignado al nodo. Este valor se genera automáticamente por el sistema e identifica de forma única al nodo dentro de la definición de proceso.
Description Área de texto Campo opcional para aportar detalles adicionales o documentación sobre el propósito de la acción programada y la lógica que ejecuta.
Source position Desplegable No aplica.
Los nodos Scheduled no tienen posiciones de origen ni destino, ya que no están conectados a otros nodos en el diagrama del flujo de trabajo. Se ejecutan periódicamente según la programación configurada.
Target position Desplegable No aplica.
Los nodos Scheduled no tienen posiciones de origen ni destino.
Script definition Editor de scripts Contiene el código del script que el planificador ejecutará periódicamente. El script tiene acceso completo al contexto del flujo de trabajo, a las variables y a la API de OpenKM.
Se puede acceder al editor de dos formas:
- Área de texto: editar directamente en el campo de texto
- Editor emergente: haga clic en el icono sobre el área de texto para abrir una ventana de edición más grande
El editor admite autocompletado. Pulse Ctrl+Espacio mientras escribe para ver las opciones disponibles y sugerencias de código.

Configuración de la programación de ejecución

Sección titulada «Configuración de la programación de ejecución»

Los nodos Scheduled se ejecutan periódicamente según una tarea cron cuyo intervalo se puede configurar en el fichero de configuración workflow.properties mediante el parámetro:

scheduled.actions.rate=PT60S

Este es el valor por defecto, que significa que los nodos Scheduled se ejecutan cada 60 segundos. El valor usa el formato de duración ISO 8601 (por ejemplo, PT30S para 30 segundos, PT2M para 2 minutos).

Caso de uso habitual: sincronización de flujos de trabajo padre-hijo

Sección titulada «Caso de uso habitual: sincronización de flujos de trabajo padre-hijo»

Los nodos Scheduled son especialmente útiles cuando un flujo de trabajo padre necesita ejecutar varios flujos de trabajo hijos en paralelo y esperar a que todos finalicen antes de continuar. Este patrón se usa habitualmente en procesos de aprobación en paralelo, tareas distribuidas u operaciones en varias etapas.

El flujo típico de este patrón implica:

  1. Un flujo de trabajo padre se inicia y llega a un nodo Action que lanza varios flujos de trabajo hijos en paralelo
  2. El flujo de trabajo padre espera entonces en una tarea (normalmente sin asignar) mientras se ejecutan los flujos de trabajo hijos
  3. Cada flujo de trabajo hijo, al finalizar, notifica al padre estableciendo una variable en el contexto del padre
  4. Un nodo Scheduled en el flujo de trabajo padre comprueba periódicamente si todos los flujos de trabajo hijos han finalizado
  5. Cuando todos los flujos de trabajo hijos han terminado, el nodo Scheduled completa la tarea de espera mediante programación
  6. El flujo de trabajo padre continúa al siguiente paso

Ejemplo 1: flujo de trabajo padre - lanzar flujos de trabajo hijos

Sección titulada «Ejemplo 1: flujo de trabajo padre - lanzar flujos de trabajo hijos»

Este nodo Action del flujo de trabajo padre crea e inicia varios flujos de trabajo hijos en paralelo:

import com.openkm.sdk4j.impl.OKMWebservices;
import com.openkm.sdk4j.bean.*;
import com.openkm.okmflow.util.*;
import com.openkm.okmflow.bean.*;
import com.openkm.util.*;
// Load constants
Class Constants = ScriptUtils.evaluateFromNode("library_request_contants");
//Load libraries
Class baseLibrary = ScriptUtils.evaluateFromNode("library_global_base");
// Get the workflow process definition id
def processDefinition = WorkflowUtils.getProcessDefinitionByName("Manager-voting");
long managerPdId = processDefinition.getId();
// Load data from the context
def uuid = baseLibrary.getContextValue(context, Constants.CONTEXT_UUID);
def initiator = baseLibrary.getInitiatorId(context);
def managerSelect = baseLibrary.getContextValue(context, Constants.CONTEXT_MANAGERS);
def managerList = managerSelect.value.tokenize(";");
long processInstanceId = baseLibrary.getProcessInstanceId(context);
// Keep user list in the context
baseLibrary.setContextValue(context, Constants.CONTEXT_MANAGERS_LIST, managerList);
// Run parallel workflows
def actorNum = 0;
managerList.each { manager ->
actorNum++;
def props = [uuid: uuid, initiator: initiator, actor: manager, srcProcInsId: processInstanceId];
def result = WorkflowUtils.runProcessDefinition(managerPdId, props);
context.put("pi_" + manager, result.get());
}
// Keep numbers of manager in the context
baseLibrary.setContextValue(context, Constants.CONTEXT_ACTOR_NUM, actorNum);

Ejemplo 2: flujo de trabajo hijo - notificar al padre al finalizar

Sección titulada «Ejemplo 2: flujo de trabajo hijo - notificar al padre al finalizar»

Este nodo Action, presente en cada flujo de trabajo hijo, notifica al padre cuando finaliza:

import com.openkm.sdk4j.impl.OKMWebservices;
import com.openkm.sdk4j.bean.*;
import com.openkm.okmflow.util.*;
import com.openkm.okmflow.bean.*;
import com.openkm.util.*;
// Load constants
Class Constants = ScriptUtils.evaluateFromNode("library_request_contants");
// Load library
Class baseLibrary = ScriptUtils.evaluateFromNode("library_global_base");
// Notify the parent workflow that the workflow has finished.
def piId = baseLibrary.getContextValue(context, Constants.CONTEXT_SOURCE_PROCESS_INSTANCE_ID);
def actor = baseLibrary.getContextValue(context, Constants.CONTEXT_ACTOR);
def wfVar = Constants.VARIABLE_STATUS_PREFIX + actor;
WorkflowUtils.addProcessInstanceVariable(piId, wfVar, Constants.STATUS_ENDED);

Ejemplo 3: flujo de trabajo padre - comprobación programada de finalización

Sección titulada «Ejemplo 3: flujo de trabajo padre - comprobación programada de finalización»

Este nodo Scheduled del flujo de trabajo padre comprueba periódicamente si todos los flujos de trabajo hijos han finalizado y, cuando es así, completa la tarea de espera:

import com.openkm.sdk4j.impl.OKMWebservices;
import com.openkm.sdk4j.bean.*;
import com.openkm.okmflow.util.*;
import com.openkm.okmflow.bean.*;
import com.openkm.util.*;
// Load constants
Class Constants = ScriptUtils.evaluateFromNode("library_request_contants");
//Load libraries
Class baseLibrary = ScriptUtils.evaluateFromNode("library_global_base");
// Load data from the context
long processInstanceId = baseLibrary.getProcessInstanceId(context);
def managerList = baseLibrary.getContextValue(context, Constants.CONTEXT_MANAGERS_LIST);
def actorNum = baseLibrary.getContextValue(context, Constants.CONTEXT_ACTOR_NUM);
def uuid = baseLibrary.getContextValue(context, Constants.CONTEXT_UUID);
def props = [uuid: uuid];
def actorResp = 0;
// When managers completed the sub workflow and task is the waiting task, must complete it
String waitingTask = "Waiting Task";
def taskInstance = WorkflowUtils.getCurrentTaskInstance(processInstanceId);
if (waitingTask.equals(taskInstance.getName())) {
if (managerList != null) {
managerList.each { manager ->
def wfVar = Constants.VARIABLE_STATUS_PREFIX + manager;
if (context.get(wfVar) != null) {
actorResp++;
}
}
} else {
// Never should go into because managerList should not be empty
}
if (actorResp == actorNum) {
// All the managers have answered
WorkflowUtils.setTaskInstanceValues(processInstanceId, waitingTask, null, props);
} else {
// Still waiting for managers
}
}

En este patrón:

  • El nodo Action lanza N flujos de trabajo hijos y guarda su número y listado en el contexto del padre
  • El flujo de trabajo padre espera en una tarea sin asignar (“Waiting Task”)
  • Cada flujo de trabajo hijo notifica al padre añadiendo una variable de estado al finalizar
  • El nodo Scheduled se ejecuta cada minuto (o en el intervalo configurado), comprobando si todos los flujos de trabajo hijos han finalizado
  • Cuando se han recibido todas las respuestas, el nodo Scheduled completa la tarea de espera mediante programación, permitiendo que el flujo de trabajo padre continúe

Los scripts de los nodos Scheduled tienen acceso completo a todas las variables de contexto del flujo de trabajo. Puede:

  • Leer variables existentes usando métodos de ayuda o directamente desde el contexto
  • Crear nuevas variables almacenando valores en el contexto
  • Modificar valores de variables existentes
  • Comprobar la presencia de variables establecidas por flujos de trabajo hijos u otros procesos

Normalmente se accede a las variables mediante métodos de ayuda de biblioteca (como en los ejemplos anteriores) o directamente a través del objeto de contexto de ejecución del flujo de trabajo.

  • Use nombres descriptivos que indiquen claramente el propósito de la acción programada (por ejemplo, scheduled_check_approvals, scheduled_sync_child_workflows)
  • Mantenga los scripts programados eficientes: se ejecutan repetidamente, así que optimícelos para el rendimiento
  • Incluya condiciones de salida temprana para evitar procesamiento innecesario cuando no se cumplen las condiciones
  • Sea prudente con la frecuencia de ejecución: una ejecución demasiado frecuente puede afectar al rendimiento del sistema
  • Registre los eventos importantes dentro de los scripts programados para facilitar la resolución de problemas
  • Pruebe a fondo la lógica programada para asegurarse de que gestiona todos los casos límite
  • Documente la frecuencia de ejecución esperada y las condiciones en el campo Description
  • Considere los escenarios de timeout: ¿qué ocurre si los flujos de trabajo hijos nunca finalizan?
  • Use lógica condicional para evitar que la acción programada se ejecute indefinidamente