BPEL et Transaction – Partie 1

Lors de la mise en place de processus complexe, vous serez certainement amené à vous assurer de l’intégrité des données.
Voici quelques informations qui vous permettront de partir sur de bonnes bases !

Concept général

Le concept n’a rien de spécifique à la SOA-Suite ou tout autre produit : il s’agit d’un standard que vous retrouverez régulièrement.
En simplifiant la problématique : vous souhaitez effectuer une opération via un premier composant, puis une autre opération via un second composant. Votre souhait est que si les 2 opérations se déroulent correctement, elles soient effectivement réalisées. Cependant, si une des 2 opérations venaient à échouer, aucune des 2 ne doit être réellement effectuée.
L’exemple classique est celui du débit d’un compte pour créditer un autre compte. Imaginez si vous pouviez créditer le compte sans que finalement le débit se fasse réellement… intéressant si vous possédez le compte débiteur, mais nettement moins si vous êtes la banque…
La manière la plus répandue de réaliser ces transactions distribuées est d’utiliser des composants supportant les transactions XA. Cette interface définit tous les éléments nécessaires pour faire en sorte que les traitements ne soient effectifs qu’à la fin de la transaction.
Les composants utilisant cette interface permettent d’assurer le pattern « Two-Phase commit ». Celui-ci va consister en plusieurs étapes :

  • Phase de requête : chaque participant se voit demandé d’effectuer une opération par le coordinateur. Chacun répondra par Yes/No suivant qu’il a réussi son opération. Il stocke également le nécessaire pour un retour arrière, et attend une confirmation.
  • Phase de commit : chaque participant reçoit un message confirmant la validation (commit) ou non (rollback) des opérations qui lui ont été demandées. En cas de commit, les participants signaleront la réussite, ou l’échec de cette validation. Si un seul échec remonte au coordinateur, il demandera à tous de revenir en arrière.

Présentation du cas pratique

Dans la suite nous allons évoquer un cas pratique : vous souhaitez appeler 2 composants via le DBAdapter (ici des procédures PL/SQL) et souhaitez que l’ensemble soit associé à une transaction générale.
Ces 2 procédures mettront à jour 2 tables différentes (CompteBanqueEasy et CompteBanqueTeam), qui ont chacune un compte ayant un solde respectivement de 100 et 0.
create or replace

procedure debitAccountEasy (
  numcompte         INT,
  montant           NUMBER
)
is
   currentSolde                NUMBER;
   total NUMBER;
BEGIN
  select solde into currentSolde  from compte_banque_team where numero = numcompte;
  total := currentSolde - montant;
  update COMPTE_BANQUE_TEAM set solde = total where numero = numcompte;
END;
create or replace
procedure creditAccountTeam (
  numcompte         INT,
  montant           NUMBER
)
is
   plafondatteint EXCEPTION;
   currentSolde                NUMBER;
   total NUMBER;
BEGIN
  select solde into currentSolde  from compte_banque_team where numero = numcompte;
  total := currentSolde + montant;
  if (total > 100) then
    RAISE plafondatteint;
  end if;
  update COMPTE_BANQUE_TEAM set solde = total where numero = numcompte;
END;

Ceci est la représentation du processus mis en place :

[TODO : santony-bpeltransac-1/01-processus.png]

Pour simplifier la remontée d’une erreur, on sait que si le solde dépasse 100 pour le compte de la banque Team, la procédure creditBanqueTeam renverra une exception car le plafond est atteint.

  • Virement de 10 : les 2 tables sont bien à jour avec les nouveau (soldes de 90 et 10)
  • Virement de 100 : erreur remontée… CompteBanqueEasy a bien les 100 de débités, mais CompteBanqueTeam ne les a pas reçus !!! (soldes de -10 et 10)

Mettre en place la transaction

La datasource

Dans l’interface d’administration du serveur weblogic, vous pouvez définir des datasources. Il est possible de choisir le driver utilisé, et notamment des drivers XA.
Si vous souhaitez mettre en place des transactions distribuées, il est possible de le réaliser même sans datasource XA, grâce aux options pour simuler le two-phase commit, mais ces configurations sont moins sûres, des problèmes peuvent subsister.

Le DBAdapter

Au niveau du dbadapter, pour utiliser cette datasource XA, la seule chose particulière est que le JNDI est à positionner dans la partie datasource XA.

Le BPEL

Configuration

Par défaut aucune configuration particulière n’est à mettre en place : un processus BPEL est transactionnel par définition. Sans modification, il mettra en place une transaction au début de son traitement, et la terminera en fin de processus.
Certaines activités permettent à priori un découpage plus précis en plusieurs transactions. On peut également jouer sur la portée de la transaction : le processus est-il dans une transaction spécifique, ou peut-il s’insérer dans des transactions existantes. Ces derniers points mériteraient davantage de détails, et feront l’objet d’un prochain article.

Rollback

Pour effectuer un rollback, rien de plus simple : faire remonter du processus une exception qui va casser la transaction !
Pensez également qu’un processus BPEL ne se termine pas forcément sur un reply : vous pouvez effectuer une réponse propre au client appelant, puis ensuite, remonter l’exception pour casser la transaction.

Le résultat obtenu

A présent, nous avons toutes les configurations nécessaires pour que le processus soit bien transactionnel. Testons si les opérations se déroulent bien tel qu’on le souhaite :

  • Virement de 10 : les 2 tables sont bien à jour à (soldes de 90 et 10)
  • Virement de 100 : une erreur est remontée, et les 2 comptes sont dans l’état précédent cette demande ! (soldes toujours de 90 et 10)

Conclusion

Avec ce type de processus, vous assurerez la cohérence des données entre diverses source de base de données. Ici nous avons fait une entrée en la matière qui sera développée au fur à mesure pour détailler comment bien mettre en place des transactions.
Si vous utilisez des composants qui ne sont pas XA-aware, il vous sera possible d’utiliser le mécanisme de compensation : utile, mais je trouve qu’on tombe rapidement sur le schéma du serpent qui se mort la queue… que fait-on si la compensation échoue ?? A utiliser mais pour des actions simples et non vitales à mon sens.
Bien souvent, vous allez utiliser les web-services. L’un des problèmes c’est qu’il ne sont pas transactionnels. Cependant il existe des standards qui permettraient de les rendre transactionnels (WS-Transaction / WS-Coordination). Je ne connais pas ces implémentations, leurs limites et ne m’étendrait pas dessus aujourd’hui, elles feront peut être l’objet d’un futur article !
Dans tous les cas, comme toujours : pensez simplicité ! Réfléchissez bien si vous nécessitez vraiment un processus transactionnel, une solution plus simple existe peut être, et généralement on se rend compte que c’est la meilleure.