sobota, września 17, 2011

Push&Commit w Tibco

Zacznijmy od tego, że Tibco BusinessWorks w zasadzie nie wspiera transakcji rozproszonych XA. Napisałem "w zasadzie" dlatego, że Tibco BusinessWorks JDBC connection pooling źle działa z TIBCO BusinessWorks XA Transaction Manager (Arjuna kupiona przez Tibco w wersji OEM) - xa_suspend(xid) i xa_resume(xid) wołane na fizycznie różnych połączeniach z bazą Oracle generują błąd (podobnie jak xa_suspend(xid) i xa_start(xid) wołane na tym samym połączeniu). Obejście to ustawienie rozmiaru puli JDBC oraz FlowLimit/MaxJobs na 1. Problem wynika z architektury silnika BW. Można rozwiązać go stosując sterownik-wrapper JDBC przypinający instancję procesu Tibco do pojedynczego połączenia.

Jest inne (też złe) obejście realizowane przez następujący wzorzec projektowy: Implementacja usługi rozbita jest na dwie części - push i commit/pop. W części push klient usługi wysyła standardowy request, który jest walidowany technicznie i biznesowo. Jeśli request nie przechodzi walidacji, klient otrzymuje odpowiedź o błędzie natychmiast. Jeśli request jest poprawny, to wołany jest nowy proces w trybie spawn i zwracana jest odpowiedź o przyjęciu komunikatu do obsługi zawierająca identyfikator transakcji. Stworzony proces aktywnością Wait czeka na commit transakcji. Proszę zauważyć, że na tym etapie obsługi komunikatu nie ma czekania wątków z blokowaniem - nie czeka się na zakończenie stworzonego procesu, a aktywność Wait zwalania wątek do puli Engine Threads. Klient wysyła kolejny komunikat potwierdzający transakcję i w odpowiedzi dostaje dane, które powinien przy standardowym podejściu dostać na wyjściu operacji request-reponse lub informację o błędzie (zazwyczaj błąd grubego kalibru typu transaction rollback, end of communication stream, connection closed). W innej wersji wzorca klient może dostać odpowiedź od razu (IPC procesu rodzica z dzieckiem), wtedy operacja commit nie zwraca żadnych danych.

Czy takie podejście ma plusy? Klient między wywołaniem requestu a commitem może po swojej stronie prowadzić jakieś przetwarzanie danych, a nie bezczynnie czekać. Wzorzec dużą wagę przykłada do walidacji danych. Klient decyduje o czasie wykonania operacji commit, a więc ma dużą domniemaną kontrolę nad timeout-ami. Poprzez odpowiednie sygnalizowanie stanu przetwarzania (Notify: processing) i dobrze dobrane czasy wygasania notyfikacji, klient po wywołaniu aktywności 'Wait for response' ma dokładną odpowiedź biznesową lub status, że przetwarzanie jeszcze trwa lub że już się skończyło poprawnie lub wystąpił błąd. Istnienie statusu przetwarzania wymusza wzorzec.

Minusy: przy źle określonych uwarunkowaniach czasowych możemy mieć do czynienia z pollingiem, przeciążeniem pamięci komponentu Tibco, przedwczesnym kasowaniem odpowiedzi. Nadal nie będziemy mieli prawdziwej transakcji rozproszonej (xa_prepare jest persystentne): jeśli operacja commit dla pierwszej w kolejności usługi zwróci błąd, nie wywołamy operacji commit dla pozostałych usług i jesteśmy szczęśliwi, ale jeśli po paru udanych commitach dostaniemy błąd, to nie jesteśmy w stanie wycofać już transakcji (a przy prawdziwym xa_prepare można zrobić rollback). Jeśli nie używamy JMS-a tylko 'spawn process', to oczekująca transakcja nie przetrwa restartu pojedynczego komponentu. Prawdziwe XA radzi sobie przy błędach infrastruktury technicznej, ten wzorzec nie. Wzorzec jest trudny w poprawnej implementacji.

Wnioski: Tibco, SOA, Order Management - wybierz dowolne dwa. Nie mając prawdziwej transakcyjności zmuszeni jesteśmy do stosowania kompensacji (saga pattern), co nie jest szybkim i prostym rozwiązaniem pudełkowym.

0 komentarze: