Saltar a contenido

Process Instance Creation

La creación de process instances en Zeebe sigue un flujo funcional con Either-based error handling: resolver proceso → autorizar → validar → crear key → persistir variables → emitir ACTIVATE_ELEMENT command. Soporta resolución por bpmnProcessId, version, o key, más start instructions para iniciar desde puntos arbitrarios.

ProcessInstanceCreationCreateProcessor

Este processor maneja el intent PROCESS_INSTANCE_CREATION:CREATE y es el punto de entrada principal para crear nuevas instancias de proceso.

Flujo principal

flowchart TD
    Start[processRecord command] --> Find[helper.findRelevantProcess]
    Find --> F1[bpmnProcessId<br/>→ getLatestProcessVersion]
    Find --> F2[bpmnProcessId + version<br/>→ getProcessByIdAndVersion]
    Find --> F3[processDefinitionKey<br/>→ getProcessByKey]
    F1 --> Auth[helper.isAuthorized]
    F2 --> Auth
    F3 --> Auth
    Auth --> AuthReq[AuthorizationRequest<br/>CREATE_PROCESS_INSTANCE on process]
    AuthReq --> Validate[helper.validateCommand]
    Validate --> V1[Verificar que existe<br/>none start event]
    Validate --> V2[Validar business ID<br/>max 256 chars, unicidad]
    Validate --> V3[Validar start instructions<br/>si presentes]
    V1 --> Create[createProcessInstance]
    V2 --> Create
    V3 --> Create
    Create --> C1[keyGenerator.nextKey<br/>→ processInstanceKey]
    C1 --> C2[initProcessInstanceRecord<br/>process, key, tags, businessId]
    C2 --> C3[setVariablesFromDocument]
    C3 --> C4[appendFollowUpCommand<br/>ACTIVATE_ELEMENT]
    C4 --> C5[appendFollowUpEvent CREATED]
    C5 --> C6[writeEventOnCommand<br/>response al cliente]

Resolución de proceso

ProcessInstanceCreationHelper.findRelevantProcess() soporta tres modos:

Campo proporcionado Método de búsqueda Caso de uso
bpmnProcessId (sin version) getLatestProcessVersionByProcessId() Caso más común: última versión
bpmnProcessId + version getProcessByProcessIdAndVersion() Versión específica
processDefinitionKey getProcessByKey() Referencia exacta por key numérico

Si ningún campo es válido (bpmnProcessId vacío Y processDefinitionKey < 0), se rechaza con INVALID_ARGUMENT.

Either-based error handling

El flujo usa la mónada Either<Rejection, T> para encadenar validaciones sin excepciones:

persistedProcess
    .flatMap(process -> helper.isAuthorized(command, process))
    .flatMap(process -> helper.validateCommand(record, process))
    .ifRightOrLeft(
        process -> createProcessInstance(command, process),
        rejection -> reject(command, rejection.type(), rejection.reason()));

Esto produce un código limpio donde cada paso puede fallar con un Rejection(type, reason) sin romper el flujo.

Start Instructions

Si record.startInstructions() no está vacío, el proceso NO se inicia desde su start event normal. En su lugar, se activan elementos específicos:

if (record.startInstructions().isEmpty()) {
    commandWriter.appendFollowUpCommand(
        processInstanceKey, ProcessInstanceIntent.ACTIVATE_ELEMENT, processInstance);
} else {
    helper.activateElementsForStartInstructions(
        record.startInstructions(), process, processInstance);
}

Esto permite: - Iniciar ejecución desde un punto arbitrario del proceso - Útil para testing y para migración de instancias - Los elementos de tipo START_EVENT, SEQUENCE_FLOW, BOUNDARY_EVENT no son válidos como targets

Business ID

Campo opcional (max 256 caracteres) para correlación de negocio:

  • Si businessIdUniquenessEnabled es true, se verifica que no exista otra instancia activa con el mismo business ID para el mismo proceso
  • Permite a los usuarios identificar instancias de proceso por un ID de negocio en vez del key numérico interno

Optimización de variables

Un detalle de implementación no-obvio: las variables se persisten via setVariablesFromDocument() antes de escribir el event CREATED. Luego se limpian del record para ahorrar espacio en el batch:

record.setVariables(DocumentValue.EMPTY_DOCUMENT);
stateWriter.appendFollowUpEvent(entityKey, CREATED, record);

Si el command tiene requestMetadata (el cliente espera respuesta), las variables se clonan antes de limpiarlas para incluirlas en la response.

CREATE_WITH_AWAITING_RESULT

Variante que no solo crea la instancia sino que espera a que complete y devuelve el resultado:

  • Usa ProcessInstanceCreationCreateWithAwaitingResultProcessor
  • Registra un "awaiting" en ElementInstanceState
  • Cuando la instancia completa, el resultado (variables finales) se envía al cliente
  • Timeout configurable por el cliente

Implicaciones para simplificación

El flujo de creación es relativamente simple y se puede mantener casi idéntico:

  1. Mantener: resolución por bpmnProcessId (latest version) — el caso más común
  2. Mantener: Either-based validation chain — es clean code
  3. Simplificar: eliminar start instructions en MVP (feature poco usada)
  4. Simplificar: business ID como campo simple sin unicidad enforced
  5. Mantener: CREATE_WITH_AWAITING_RESULT — API muy útil
  6. Simplificar: sin partition-aware key generation (single partition)