|
| 1 | +## Use Case 1 - Using a Migration Island with Limited Batch Sizes |
| 2 | + |
| 3 | +In this use case, we have a process that loses a User Task from version 1 to version 2. |
| 4 | + |
| 5 | +**Version 1** looks like this. Notice on path 2 that there is a "User Task 0". |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +In **Version 2**, "user task 0" no longer exists, so we need to migrate all existing tokens on "user task 0" to "user task 2" over on path 3. The problem is that the development team is telling us that if we do this token migration directly then those process instances might not function properly. Some kind of "data massage" is required in order to make sure that migration from "user task 0" to "user task 2" happens without incident. |
| 10 | + |
| 11 | +(NOTE: For the purposes of this exercise, the actual data that needs to be prepped for this to work correctly is irrelevant and out of scope. Let us just pretend that many things needs to be carefully changed for the migration to work correctly) |
| 12 | + |
| 13 | + |
| 14 | + |
| 15 | +So the development team decides to use a "Migration Island" pattern for this migration. They will use the process migration functionality of Camunda to migrate tokens of "user task 0" from v1 to the "Migration Task" user task shown in version 2. The only purpose of this "island" is to accept tokens during a process migration process. The process model design should allow no other means to arrive at this island in the flow. |
| 16 | + |
| 17 | +The DevOps team also has a concern during this migration. They are concerned that there might be over 50,000 instances to migrate on deployment night, and that the migration itself might cause unexpected load on the infrastructure. Therefore, they are asking the development team to migrate in controlled batches, setting a proper maximum number of process instances to migrate during each batch. For instance, let us say 500 at a time. |
| 18 | + |
| 19 | + |
| 20 | + |
| 21 | +## Use Case 1 - Solution |
| 22 | + |
| 23 | +The development team decides to create a process to handle the migration. |
| 24 | + |
| 25 | + |
| 26 | + |
| 27 | +Migration is triggered by creating a process instance of this Migration process using the REST API. The payload that initializes process instance variables in our local example looks like this: |
| 28 | + |
| 29 | + |
| 30 | + |
| 31 | +``` |
| 32 | +{ |
| 33 | + "variables": { |
| 34 | + "processDefKey": { |
| 35 | + "value": "use-case-1", |
| 36 | + "type": "String" |
| 37 | + }, |
| 38 | + "fromVersion": { |
| 39 | + "value": 1, |
| 40 | + "type": "Integer" |
| 41 | + }, |
| 42 | + "toVersion": { |
| 43 | + "value": 2, |
| 44 | + "type": "Integer" |
| 45 | + }, |
| 46 | + "fromUserTaskKey": { |
| 47 | + "value": "user-task-0", |
| 48 | + "type": "String" |
| 49 | + }, |
| 50 | + "toUserTaskKey": { |
| 51 | + "value": "migration-task", |
| 52 | + "type": "String" |
| 53 | + }, |
| 54 | + "maxPerBatch": { |
| 55 | + "value": 50, |
| 56 | + "type": "Integer" |
| 57 | + }, |
| 58 | + "skipIoMappings": { |
| 59 | + "value": true, |
| 60 | + "type": "Boolean" |
| 61 | + }, |
| 62 | + "skipCustomListeners": { |
| 63 | + "value": true, |
| 64 | + "type": "Boolean" |
| 65 | + } |
| 66 | + } |
| 67 | +} |
| 68 | +``` |
| 69 | + |
| 70 | +Notice the "maxPerBatch" variable. In our local example, we will create 120 instances of version 1 with a token sitting on "user task 0". Then we will run this migration process, instructing it to migrate in batches of 50 at a time. |
| 71 | + |
| 72 | +The migration process will loop for each batch of process instances to migrate. For each batch, it will: |
| 73 | + |
| 74 | +- suspend the processes |
| 75 | +- execute the migration |
| 76 | +- activate the processes |
| 77 | +- using the API, complete the User migration task. This will trigger the "Prepare Data After Migration" service task, and allow the token to rest at it's final destination, the "user task 2" task. |
| 78 | + |
| 79 | +### Steps to execute the solution locally |
| 80 | + |
| 81 | +1. Start the Spring Boot application. The application class is CamundaApplication.java. Use either your IDE, or using maven with: |
| 82 | + |
| 83 | + ``` |
| 84 | + mvn spring-boot:run |
| 85 | + ``` |
| 86 | + |
| 87 | +This will start Camunda BPM, as well as auto-deploy the first version of the process (case1.bpmn). |
| 88 | + |
| 89 | +2. Open Postman. Import the following 4 files into Postman. They are located in the src/test/resources directory: |
| 90 | + |
| 91 | +  |
| 92 | + |
| 93 | +Once the environment file is loaded, make sure it is selected in your Postman IDE: |
| 94 | + |
| 95 | + |
| 96 | + |
| 97 | +Once all files are imported, you should see the following three collections: |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | +3. Notice that the "Step 1" collection for generating the data actually does the following: |
| 102 | + |
| 103 | + - Starts a process instance that will go down path 1 after the gateway. That process will auto-complete. |
| 104 | + - Starts a process instance that will go down path 2 after the gateway. It will stop at "user task 1". |
| 105 | + - Get that task instance and complete it, to push the token to "user task 0". |
| 106 | + - Starts a process instance that will go down path 3, then push that token all the way to completion. |
| 107 | + |
| 108 | + This means that every time we run this collection of calls, we will have two completed instances (path 1 and 3), and one incomplete instance with a token sitting at "user task 0". |
| 109 | + |
| 110 | + We want to run this collection 120 times by using the Collection Runner. Select the "play" button in the upper right portion of the collection. It should take you to this interface: |
| 111 | + |
| 112 | +  |
| 113 | + |
| 114 | +Select "Run", then enter "120" for iterations, with a delay of 20 milliseconds. Run the collection. When it is complete, log into Cockpit (http://localhost:8080/app/cockpit/default/) with demo/demo. Select the "use-case-1" process definition. You should see 120 tokens on "user task 0". If you are running Camunda EE and have History view, it should look like this: |
| 115 | + |
| 116 | + |
| 117 | + |
| 118 | +4. In Postman, go to the "Deploy Version 2" request in the Step 2 collection. Select the "Body" tab of the request, and reload the file provided for the "data" parameter. It is the "case1_ver2_template.bpmn" file that is located in the root of the Spring Boot project. Once complete, select the "Save" button, then the "Run" button. This should deploy version 2 of the use-case-1 process. Confirm deployment by going into Cockpit to see both versions. |
| 119 | + |
| 120 | +5. In Postman, go to the "Start process migrate-case-1" request in the "Case 1 - Step 3" collection. Run the request to start the migration. Observe the log in Spring Boot to watch the process navigation. When complete, go into Cockpit to see the results. |
| 121 | + |
| 122 | + The migration should have run in three batches (50, 50, 20). History would show this: |
| 123 | + |
| 124 | +  |
| 125 | + |
| 126 | + |
| 127 | + |
| 128 | +Migration success would look like this: |
| 129 | + |
| 130 | + |
| 131 | + |
| 132 | + |
| 133 | + |
| 134 | + |
| 135 | + |
0 commit comments