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
businessIdUniquenessEnabledes 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:
- Mantener: resolución por bpmnProcessId (latest version) — el caso más común
- Mantener: Either-based validation chain — es clean code
- Simplificar: eliminar start instructions en MVP (feature poco usada)
- Simplificar: business ID como campo simple sin unicidad enforced
- Mantener: CREATE_WITH_AWAITING_RESULT — API muy útil
- Simplificar: sin partition-aware key generation (single partition)