Alejandro described in a recent post how to use the Transaction Manager to implement parallel processing. Here's another great Transaction Manager concept - forwarding a transaction from one manager instance to another...
The guts of any jPOS implementation is its Transaction Manager. There (in addition to other important concepts like session and space information), you define your valid transaction set and transaction participants. You can then dictate the processing sequence of each transaction type in the valid set, like is done in this example (the property name are just some examples of a scheme that IDs transaction types from incoming messages):
<participant class="org.jpos.example.Switch" logger="Q2" realm="switch">
<property name="X.01" value="EmployeeVerification LogAndReply" />
<property name="Y.11" value="CreateDebit Decrypt DebitSale" />
<property name="Y.12" value="CreateDebit Decrypt DebitSaleReversal LogAndReply" />
<property name="Z.21" value="CreateCredit Decrypt CreditSale" />
<property name="Z.22" value="CreateCredit Decrypt CreditSaleReversal LogAndReply" />
<property name="Z.23" value="CreateCredit Decrypt CreditReturn" />
<property name="Z.24" value="CreateCredit Decrypt CreditReturnReversal LogAndReply" />
<!-- Unhandled transactions -->
<property name="Unhandled" value="Unhandled" />
</participant>
in that real-life example, the Credit and Debit transactions are actually switched out real-time (or via store-and-forward in the case of the reversals) via a 'query_host' participant (not shown here). when that query is done, you're really reliant on the external authorizers reply times to keep your Transaction Manager free and clear to perform more incoming transactions. In this example, we've configured 80 simultaneous sessions to process transactions in this one application node:
<ev-txnmgr class="org.jpos.transaction.TransactionManager" logger="Q2">
<property name="sessions" value="80" />
<property name="space" value="tspace:default" />
<property name="queue" value="INCOMING.TXN" />
<property name="debug" value="@debug@" />
If you're doing 20 TPS sustained across your enterprise and the remote authorizers are responding in < 1 second, no problem. But if the remote authorizer suddenly skyrockets to 15-second response time, well, you've got problems. It's a 'weakest link' type thing - by pushing all transactions through that main Transaction Manager, your entire transaction mix is susceptible to backup due to your "weakest" endpoint. Here, I define "weakest" as the authorizer most prone to slowdown during seasonal or holiday-related volume increases.
In general, our experiences are that we're on solid ground routing the 'big' transaction types through a single, 'main' Transaction Manager. I'm referring here to your Debit, EBT and Credit (Amex, MC, Visa, Discover) traffic. This is because you're dealing with huge entities on the other side with massive authorization complexes engineered to handle peaks. And, more importantly, for Debit, EBT and Credit, a seasonal peak tends to be of the 1.5 to 2.5x variety. We can handle those.
Where the concern comes into play is with smaller issuer/authorizers and/or authorizers with massive seasonal peaks. Specifically, I have in mind stored value ('SV') endpoints. This post isn't meant as a critique of their processing capabilities. Rather, I'm pointing out that these endpoints are typically subjected to massive run-ups before Christmas. Looking at 2006 holiday 'actuals' from one of our client sites, it's not unusual to get a 15x-style run-up in volume (looking at the pre-Christmas week vs. a mid-year week). And those endpoints may, in turn, act as a gateway to another, weaker endpoint.
This is a situation where we make use of the Transaction Manager's ability to transfer control of a specific set of defined transactions from one manager to another. In doing so, the objective is to keep the main Transaction Manager free and clear to handle the 'less peak-y' Debit/EBT/Credit traffic. In other words, you're looking to isolate potential weak links.
To do so, you can define a participant the Transaction Manager to forward transactions from one manager to another thereby shifting control and freeing up sessions in the 'main' manager to process more incoming traffic. So, suppose we have three 'SV' transaction types where we want to isolate them just in case the endpoint is afflicted with seasonal slowdowns. In the main transaction manager (continuing the previous example), you add entries like this to the 'switch' participant:
<property name="S.31" value="ForwardToSVTxnMgr" />
<property name="S.32" value="ForwardToSVTxnMgr" />
<property name="S.33" value="ForwardToSVTxnMgr" />
Then, also in the main Transaction Manager, we have a participant like this:
<group name="ForwardToSVTxnMgr">
<participant class="org.jpos.transaction.Forward">
<property name="queue" value="SV.TXN" />
<property name="timeout" value="60000" />
</participant>
</group>
Then, you have another Transaction Manager in the deploy directory that handles these forwarded transactions! In there, you define participants like this:
<sv-txnmgr class="org.jpos.transaction.TransactionManager" logger="Q2">
<property name="sessions" value="8" />
<property name="queue" value="SV.TXN" />
<property name="debug" value="@debug@" />
<participant class="org.jpos.example.Switch" logger="Q2" realm="switch">
<property name="S.31" value="CreateSV SVActivate LogAndReply" />
<property name="S.32" value="CreateSV SVRefresh LogAndReply" />
<property name="S.33" value="CreateSV SVDeactivate LogAndReply" />
</participant>
Of course, your Transaction Manager needs additional partipants that define each of those referenced steps. For example, here's an 'SVActivate' participant from one of our clients:
<group name="SVActivate">
<participant class="org.jpos.ev.PopulateSVTranLog"
logger="Q2" realm="populate-sv-tranlog">
<property name="itc" value="09000" />
<property name="cardType" value="SV" />
<property name="checkpoint" value="populate-sv-tranlog" />
</participant>
<participant class="org.jpos.SV.CreateSVRequest"
logger="Q2" realm="create-sv-request">
<property name="mti" value="0100" />
<property name="pcode" value="229000" />
<property name="template" value="cfg/sv-template.xml" />
<property name="space" value="jdbm:sv-stan" />
<property name="checkpoint" value="create-sv-request" />
</participant>
&query_sv_host_or_reverse;
&svc_response;
</group>
Comments