Process Versioning


Before starting on what process versioning exactly does, let's see what the world (or at least ODE) would be without versioning. It will be much more easier for you to understand the solution after fully seeing the problem.

So you're starting using ODE and you've just designed you first business process. It's all nice and dandy and works perfectly. It works so well that you let your users start using it. It's not really production but you know, release early, release often, so let's see what users think of it. After a couple of days you realize that a couple of steps are missing, you add them in your process and once again, it executes smoothly. So let's see what our users think of the improvement! Next thing you know, your phone starts ringing and the user on the other side is most likely pretty upset. What happened?

So when you start using a process, executions for it are created, running processes if you like (also called process instances). Depending on the type of your business these could take a variable amount of time to execute but they're usually not instantaneous. So you have all these running processes sometimes doing things, sometimes just waiting there and all of a sudden, a brand new process definition replaces the original one all these executions have been using so far. What is a process engine to do with all these executions? Well, the most logic thing on earth: just nuke them all.

At this time there's no simple automated way to migrate a running process that has been executing using one definition to another new one. Computing the differences between the 2 definitions can be very complex and chances are that they're not even compatible! When you think of all these little tasks that are arranged just so to guarantee a perfect execution using the right data types, even minor alterations can get really tricky to apply on instances without blowing them all.

So here is the crude and sad truth: without having some versioning goodness in it, a process engine will always delete all the running instances when a new process definition is deployed.

How Versioning Works

So if existing executions can't be migrated, what are you going to do with them? Well, just let them be. Versioning is based on the fact that, instead of directly updating the original process definition (leaving its instances to their dreadful fate), another new version of this definition is created. The older one is declared retired so no new executions can be started on that one, the new process is the one to be used now on. But running instances can still finish their job peacefully as the process they've been using to execute so far is still available and unchanged.

However ODE also has the concept of deployment bundles and supports 2 modes of deployment (remotely or manually directly on the filsesystem). Let's see how we get versioning to work under those conditions.

Process Versioning in ODE

In ODE, processes are deployed in what we call a deployment bundle. When you come down to it, it's just a zip file or a directory containing ODE's deployment descriptor (deploy.xml), the processes BPEL and all the other goodies necessary for your BPEL to run (WSDLs, schemas, xsl stylesheets, you name it). And what ODE is using to know you're redeploying the same thing is the deployment bundle name.

So when you're redeploying a deployment bundle in ODE, here is what happens:

  1. A new version is attributed to the bundle by incrementing the version number of the last deployment.
  2. ODE checks whether the same bundle has been deployed before, all processes in those older bundles are retired.
  3. The processes in the bundle are deployed in the engine using the same version number as the bundle itself.
  4. New executions of all newly deployed processes are ready to be started.

There are a couple of additional remarks to make. The first is that the version is a single, sequentially incremented (which is to say that 3 comes after 2 and 2 comes after 1) number. All deployed bundles share the same sequence. The second thing to be aware of is that all processes in a bundle share the same version number and it's the number of their bundle.

Let's use the notation Foo-x(Bar-x, Baz-x) to represent the deployment of the Foo bundle in version x with processes Bar and Baz (sharing the same version number as just explained). The following illustrates a valid deployment sequence:

  1. Coconut-1(Pineapple-1, Mango-1)
  2. Orange-2(Tangerine-2)
  3. Orange-3(Tangerine-3) => retires Orange-2(Tangerine-2)
  4. Coconut-4(Pineapple-4, Mango-4) => retires Coconut-1(Pineapple-1, Mango-1)
  5. Banana-5(Kiwi-5)

That's both tasty and healthy!

There's still a last question left unsolved: what happens if you take your bundle and deploy it under a different name with the same content. If you know a bit about source version control (like CVS or Subversion), that's very close to branching, only you might be executing two branches at the same time. As ODE can't find another bundle with the same, the processes will simply be deployed without retiring anything. You will effectively have twice the same process deployed under different versions. In that scenario you're supposed to know what you're doing.

If two identical process definitions are deployed at the same time, the behavior of the engine is unspecified. Which one of the two process will pick up the message? Who knows!? But this can be a very useful feature in specific cases when you want to deploy the same process twice (by same understand same name and same namespace) but the 2 definitions are actually different and enable different endpoints. This allows the parallel deployment of two different version of the same process provided that they don't overlap in their endpoint implementation.

Remote Deployment vs. Hand-Made Deployment

ODE supports 2 different ways of deploying bundles:

  • using the deployment web service or JBI deployment.
  • dropping bundles as directories under WEB-INF/processes.

The first way works just as described previously. Under the hood, your process bundle is a zip and it gets unzipped in a directory named bundlename-version. The version number is automatically generated by the engine. So you only need to provide the zip itself and a consistent bundle name.

For the second way, it's a bit more tricky. Because you're directly interacting with the deployment directory, you're allowed to create a bundle directory with any name you like (even not numbered at all). In that case ODE will still create a version number, it just won't be shown on the filesystem. However as it won't be able to find the previous bundle to retire, it will just deploy the new bundle along with all other processes, even if you already had some conflicting deployments. Basically, if you don't number your directories properly, every new deployment will be a new branch. In short, you don't really want to do that.

Another thing you're allowed to do with the file system is simply to replace (or remove and copy) all the files in the deployment bundle directory and remove the .deployed marker file to trigger redeployment. In that case ODE will simply consider you've undeployed and deployed the whole thing. So we get back to the situation where we don't have any versioning. Which can be very useful when you're in development mode because you usually don't care much about the running instances and you usually don't want to pile up versions of process definitions.