Hi folks,
I’m implementing an interesting migration for the customer. Here is the scenario:
Scenario
I have a process instance of process A, waiting in a wait state (user task). It was started direct via runtimeService
(top level). After changes of some requirements, the process A should now be started from a call activity of a process B. We implemented the solution and this works for new process instances. Now we need to “migrate” the old instances of A, so they look that they have been started by B. So for every instance of A I need to create an instance of B waiting in the call activity so that the engine believes that it started A. And then, if A is finally finished, it should continue the execution of B.
Additions
The instances of A can’t be restarted or modified a lot (setting additional variables is ok).
The history can be dropped / inconsistent for the old instances.
There are about 5000 instances to migrate.
My approach
Start B and run it to call activity. Since the call activity process binding is dynamic (determined during the process), I can let the call activity start a process “stub”(let call its execution newExecution
). Then I created a special process engine command that is responsible for switching the instances - more precised I want to switch toMigrateProcessInstanceId
and newExecution
.
As far as I understand, the only thing I have to do is to modify the values of member variables superExecutionId
and rootProcessInstance
…
Show me the code
class SwapChildProcessInstanceCmd(
val toMigrateProcessInstanceId: String,
val newProcessInstanceId: String
) : Command<Unit> {
companion object : KLogging()
override fun execute(commandContext: CommandContext) {
val toMigrateExecution: ExecutionEntity = requireNotNull(commandContext.executionManager.findExecutionById(toMigrateProcessInstanceId))
val newExecution: ExecutionEntity = requireNotNull(commandContext.executionManager.findExecutionById(newProcessInstanceId))
val dispatcherExecution: ExecutionEntity = requireNotNull(commandContext.executionManager.findExecutionById(newExecution.superExecutionId))
logger.info { "Setting subprocess instance of $dispatcherExecution to $toMigrateExecution (was ${dispatcherExecution.subProcessInstance})" }
dispatcherExecution.subProcessInstance = toMigrateExecution
logger.info { "Setting superExecutionId of $toMigrateExecution to ${newExecution.superExecutionId} (was ${toMigrateExecution.superExecutionId})" }
toMigrateExecution.superExecution = newExecution.superExecution
toMigrateExecution.superExecutionId = newExecution.superExecutionId
logger.info { "Setting rootProcessId of $toMigrateExecution to ${newExecution.rootProcessInstanceId} (was ${toMigrateExecution.rootProcessInstanceId})" }
toMigrateExecution.rootProcessInstanceId = newExecution.rootProcessInstanceId
commandContext.dbEntityManager.merge(dispatcherExecution)
commandContext.dbEntityManager.merge(toMigrateExecution)
commandContext.dbEntityManager.flushEntity(dispatcherExecution)
commandContext.dbEntityManager.flushEntity(toMigrateExecution)
logger.info { "Deleting $newExecution" }
newExecution.superExecution = null
newExecution.superExecutionId = null
newExecution.rootProcessInstanceId = newExecution.processInstanceId
newExecution.deleteCascade("Deleted migration process instance", true, true, true, true)
}
}
What I observe (at least in Unit test) is that rootProcessInstanceId
is changed and this value is available after I fetch the migratedExecution
again. But the reference to the superExecutionId
is set to the id of execution again (as it is before the modification).
What did I miss @thorben, @falko.menge @DanielMeyer?
Thanks for the help
Cheers,
Simon