Thursday, April 12, 2007

How to implement service versioning in an SOA



In this pattern every versioned service has a proxy. There is one proxy for the whole collection of versions per service. The proxy decides which version of the service must be accessed.

This is accomplished by use of a version identifier in the SOAP-message. This version identifier identifies the version of the WSDL document that the calling component used to call the service. There is always a WSDL document for every service version. At design-time the concerning version of the WSDL document must be known, because the program code of the calling component must be aligned with this particular WSDL. The version identifier of the WSDL document in use at design time is added to the SOAP-message.

The services are registered in a registry. For every version of the service the registry holds the version identifier of the corresponding WSDL document. In addition, for each registration of a version of a service the registry holds a backward compatiblity list; with every newly registered version of a service a list of compatible earlier versions is registered. Backward compatibility means that a version of a service can be called by components that were built with earlier WSDL versions.

The proxy queries the registry with the version identifier from the SOAP-message and looks for the highest operational version of the concerning service that is compatible with the version identifier from the SOAP-message. Once the correct version of the service is determined the proxy passes the message to that determined version of the service.

In case of a component calling a service using an old version identifier of which no compatible service versions are operational anymore (e.g. after end-of-life of a service version) an adequate error message may be returned by the proxy to the calling component.

The specific versions of the services to which the proxy passes the messages are identified by their URI (URN and/or URL).

Why?

Support of multiple concurrent operational versions of a service leads to more flexible and robust systems. Separating the callable service name (represented by the proxy) from its version identifier has advantages:

  • Calling components automatically make use of the highest available compatible version of the service on the fly without any modification.
  • Multiple incompatible versions of a service may exist concurrently without any effect on the calling components.
  • New versions of a service can easily be tested in a production environment, without disturbing the current version. After approval just add the backward compatibility list for this version to the registry and all compatible calls are directed instantly to the new version.
  • Superfluous versions - versions of which higher compatible versions are available - won't be called anymore and can be removed without any modifications to the calling components.
  • The process needs not be aborted to pass control to the infrastructure layer if an old version identifier is detected that is not supported anymore by an operational service. If desired control can be maintained at the application level where an appropriate action or message can be generated.


7 comments:

Tom Kerigan said...

If we're identifying the WSDL for each version in a unique fashion (using namespace or some other attribute), I'm not sure what benefit the proxy service is providing us with.

Assuming that we only create a new version when we introduce a non-backwards compatible change to the contract, we can continue to add function (and implementation) as long as it doesn't impact the consumer. This means that the client is always consuming the latest and greatest service offering that is compatible with their contract (hence, negating the need to maintain a list of versions that are compatible with the client).

The only benefit that I can see a proxy service providing is routing (ie. mapping a version to a URL). To me, this is infrastructure, and not something we should be coding for.

Am I missing something?

Jack van Hoof said...

You are right, Tom. Your pattern is an option as well. There are more solutions for the service versioning topology. The pattern you describe is known as the "multiple endpoint adresses" pattern and mine as the "covenant" pattern.

When rolling back a buggy version in your case you redeploy the previous version, whereas in my case I deactivate the backward compatiblity list, so I configure in stead of redeploy. I can easily test new versions in an operational environment by using some test software to the new WSDL-version while not activating the backward compatibility list, if I would like that. The services registry maintains the full versions documentation of the deployed services. Even the superfluous and buggy ones, if you wish; including deployment and revocation date/timestamps, if you wish (might be useful in case of compliancy regulations). All version deployments remain available, if you wish (might be useful in case of running redo scenarios based on log files for debugging or analyzing reasons). Additional functionality can be added to the version resolution functionality, if you wish.

But it is very well possible that you don't need all of this. In that case it is very appropriate to choose another more pragmatic pattern.

And, of course, the routing part of the proxy service may be delegated to the infrastructure layer.

Jack

Tom Kerigan said...

All very good points, Jack. You've given me some excellent food for thought ... thanks!

Jason Henriksen said...

Doesn't it seem better to implement your proxy via JNDI?

If I look up my soap service at "/service/v00" and then come out with "/service/v01" I can make the lookup for v00 point to the next service, or point to a re-usable service that gives the 'no longer available'. I could even change v00 to point at some new service which re-maps a v00 request into a valid v01 request.

This way, my service code doesn't have to worry about version number or plumbing at all. Plus, I simply update my JNDI config instead of recompiling and re-deploying my proxy service.

Jack van Hoof said...

Thanks for your contribution, Jason. In your case the client side must be aware of the availability of a newer service version. In a loosely coupled environment, e.g. when crossing borders beyond your control, I think it is more appropriate to have the server side offer the most recent - or best suitable - service version. Determining the best suitable service version may be based on custom coded algoritms of the version resolution component under control of the service provider.

Anonymous said...

The Proxy allows for more operations, especially for managing services:

For example can you monitor whether certain versions of services are still used or have been abandoned for months...

Terry said...

Any thoughts about best practices for assigning service versions to EARs in a JEE environment. We have had the practice of all versions in the same EAR, which means that a change to any versions means a redploy of all versions. Will there by any impact to the unchanged versions? No, there *should* not be. But a change was made to the running footprint, so cannot guarantee it.