Migrating an execution to become a sub-execution (process become sub-process)

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

1 Like

Hi Simon,

I don’t see obvious mistakes (the entity manager interaction shouldn’t be necessary, but I don’t see anything clearly wrong with it). Can you please share a test project where I could debug it?

Cheers,
Thorben

Hi. I have the same problem. Have you found solution to the problem?

Yes. My code worked at the end. You have to change the executionId of the child execution of the call activity to the new one and replace the parent executionId of the child. You don’t need to save the entity. I also set the references of the fake child to null prior to deleting the fake child.

1 Like