How to call server in conversational mode thru restincl?

Added by Andrey about 1 year ago

We reviewed EnduroX for migration from Tuxedo.
We have very old legacy service which works in conversational mode.
The reason to use conversational is "save" from frontend the big amount of data in different areas.
For example: Account data, Clients data under account, client's services data, side effects and e.t.c.
Also if we change only part of data in frontend we can save only this part. For example only client services.
All these data defined above should be saved by one DB transaction.
The conversational is "splitting" data for save by different packages in our case.
Currently WSL uses and we reviewing how we can migrate this service to communication thru restincl.

My question is - how we can perform like "conversational" communication with service thru restincl to keep possibility of commit and rollback global transaction to db?


Replies (7)

RE: How to call server in conversational mode thru restincl? - Added by Lauris about 1 year ago

Hi Andrey,

Currently restincl does not handle conversational services directly (thought technically with some development / SoW based work, restincl could be expanded for web-sockets, and that would allow data streaming in conversational way).

Currently you have following options:

- If buffer size by it self allows, you can pack all the user registration data in on big buffer and create some proxy xatmi service (called by restincl) which parses that buffer and does the conversational data load to that legacy service. If XATMI buffer size for you is too short, then registration data could be uploaded by restincl file upload interface, and then this proxy server could read that user registration file and call the conversational service as needed.

- Second option (similar to first) could be for you to create some temporary db table to which you identify and add data from several restincl requests, when full record data is uploaded to this db table, run the services which invokes that conversational service.

- Third option would be, to use global transactions, in which case the XA transaction can be started from restincl, and further web service calls can be attached to that particular transaction. In this case you refactor the conversational service to normal service which works with XA transactions. When full data is uploaded, perform commit from the restincl transaction api.

Br,
Lauris

RE: How to call server in conversational mode thru restincl? - Added by Andrey about 1 year ago

Thank you very much for the answer!

Initially we reviewed option 1 and 2 as possible option.
1 - create wrapper which can covers all required fields and works as regular service without any conversational
2 - save the blobs into DB by special service and call one more service which will take a blobs and use it to call legacy server

For now we would like to check third option. It is looks interesting.
Our global conversational service has many "sub-services" inside to save data by areas.
We can define these "sub-services" as regular services and call these one-by-one and use global transaction.
For now we need to understand 2 points.
1. How we can isolate in global transaction just these legacy services and use other regular services out of global transaction mode.
2. How we can attach them to given transaction via json.
Currently I didn't find any examples of json with tptranid.
Is it just one more additional field in json?

RE: How to call server in conversational mode thru restincl? - Added by Andrey about 1 year ago

One more question.
Initially our legacy server uses manually control of transaction to DB include instance, credentials and etc.
For this purpose was redefined tpsvrinit (initialization of DB instance and credentials) and EnduroX DB configuration which defined in ini files can't be used.
Also defined internal "sub-services" trxStart, trxCommit and trxRollback which called by frontend client in the begin/end and if something fail during "save" services
How it will work with "global transaction"? Can we have any transaction corruptions?
One more question.
Initially our legacy server uses manually control of transaction to DB include instance, credentials and etc.
For this purpose was redefined tpsvrinit (initialization of DB instance and credentials) and EnduroX DB configuration which defined in ini files can't be used.
Also defined internal "sub-services" trxStart, trxCommit and trxRollback which called by frontend client in the begin/end and if something fail during "save" services
How it will work with "global transaction"? Can we have any transaction corruptions?

RE: How to call server in conversational mode thru restincl? - Added by Lauris about 1 year ago

1. How we can isolate in global transaction just these legacy services and use other regular services out of global transaction mode.

You can put only set of the xatmi servers / clients into CCTAG which defines the distributed transaction settings. Thus some of the services will be working in XA mode, while other not.

2. How we can attach them to given transaction via json.

Firstly you need to define NULL XA group used by restincl, and define that restincl will have transaction handler:

something like this:

in ini config:


[@global/TRAN]
NDRX_XA_RES_ID=1
NDRX_XA_OPEN_STR=-
NDRX_XA_CLOSE_STR=-
NDRX_XA_DRIVERLIB=libndrxxanulls.so
NDRX_XA_RMLIB=-
NDRX_XA_LAZY_INIT=1

[@restin/TRAN]
port=8081
ip=0.0.0.0
gencore=1
defaults={}
/transactions={"transaction_handler":true}
/service1={...}
/service2={...}
...

Then in xml configuration, you need to define tmsrv for the NULL group and restincl handler by it self:

...
<endurox>
...
    <servers>
    ...
                <server name="tmsrv">
                        <min>1</min>
                        <max>1</max>
                        <cctag>TRAN</cctag>
                        <srvid>200</srvid>
                        <sysopt>-e ${NDRX_APPHOME}/log/tmsrv-rm1.log -r -- -t1 -l${NDRX_APPHOME}/tmlogs/rm1</sysopt>
                </server>
    </servers>
    ...
        <clients>
        ...
                <client cmdline="restincl">
                        <exec tag="TRAN" autostart="Y" cctag="TRAN" subsect="" log="${NDRX_APPHOME}/log/restin-tran.log"/>
                </client>
        ...
        </clients>

!! remember to create ${NDRX_APPHOME}/tmlogs/rm1 directory.

Now you can use /transactions handler for http POST operations with following bodies:

{
    "operation":"tpbegin" 
    ,"timeout":60
    ,"flags":0
}

in response you will get something like this:


{
    "operation":"tpcommit" 
    "flags":0
    ,"tptranid":"AABZWlQzb1VCQWtKUXdQNVF2UyttVTlpMlh5cDdyc0FFQUFnREkAAAAAAAAAAAAAAAAAAAEAAgDIAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA" 
}

then you can call the /service1 and /service2 by putting "tptranid" in "endurox-tptranid-req" header, each service response ther will be endurox-tptranid-rsp available,
if so then for next service call response header tptranid shall be used for next call (however that is not mandatory, as tptranid is appended with some meta data each time).

When calls are done you invoke /transactions with POST body (also use last tptanid if possible):

{
    "operation":"tpcommit" 
    ,"error_code":0
    ,"error_message":"Succeed" 
    ,"tptranid":"AABZWlQzb1VCQWtKUXdQNVF2UyttVTlpMlh5cDdyc0FFQUFnREkAAAAAAAAAAAAAAAAAAAEAAgDIAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAA" 
}

Basically when call to service will be made with "endurox-tptranid-req" http header set, the XA transaction is started by restincl and destination service is invoked in global transaction mode.

When writing service for handling XA transactions, you need to perform following steps:

- For server, at tpsvrinit() call tpopen();
- When server is finished, at tpsvrdone, call tpclose().
- For example, if using Pro*C, then connection will be assigned to Pro*C libraries automatically.
- If using Oracle OCCI API, then check here: https://docs.oracle.com/database/121/LNCPP/xa.htm#LNCPP20474, use the xaoSvcCtx() and xaoEnv() to get the connection handle. To access the XA open string, you can read the environment variable NDRX_XA_OPEN_STR.

When such server binary is built, you need to define XA group setting for your legacy services. If using Oracle DB, then it would look like:

ini configuration:


#
# Oracle XA
#
[@global/ORAXA]
# Remember to give different ID:
NDRX_XA_RES_ID=2
NDRX_XA_OPEN_STR=ORACLE_XA+SqlNet=ORACLESID1+ACC=P/dbuser/dbpass111+SesTM=180+LogDir=./+nolocal=f+Threads=true
NDRX_XA_CLOSE_STR=${NDRX_XA_OPEN_STR}
NDRX_XA_RMLIB=/path/to/oracle/libclntsh.so
NDRX_XA_LAZY_INIT=1
NDRX_XA_FLAGS=RECON:*:3:100
NDRX_XA_DRIVERLIB=libndrxxaoras.so

Append the XML configuration file with tmsrv and legacy services (services shall be put in ORAXA cctag):

<endurox>
...
    <servers>
    ...
    <server name="tmsrv">
        <min>1</min>
        <max>1</max>
        <srvid>40</srvid>
        <cctag>ORAXA</cctag>
        <sysopt>-e ${NDRX_ULOG}/tmsrv-rm2.log -r -- -t1 -l${NDRX_APPHOME}/tmlogs/rm2</sysopt>
    </server>

    <server name="your_server1">
        <min>1</min>
        <max>1</max>
        <srvid>50</srvid>
        <cctag>ORAXA</cctag>
        <sysopt>-e ${NDRX_ULOG}/you_server1.log -r</sysopt>
    </server>
    <server name="your_server2">
        <min>1</min>
        <max>1</max>
        <srvid>60</srvid>
        <cctag>ORAXA</cctag>
        <sysopt>-e ${NDRX_ULOG}/you_server1.log -r</sysopt>
    </server>
..

!! also here remember to create directory ${NDRX_APPHOME}/tmlogs/rm2 where transaction manager will keep the logs.

After all this the calls routed to your_server1/your_server2 services shall work in global transaction and will have single commit or abort.

Also defined internal "sub-services" trxStart, trxCommit and trxRollback which called by frontend client in the begin/end and if something fail during "save" services
How it will work with "global transaction"? Can we have any transaction corruptions?

You do not need to manage transactions in your processes any more, they will be joined to automatically to transaction. And the only place where you will do begin/commit/rollback will be form WS handle.

Corruptions are not expected, there are some conditions like timeouts, which are handled tmsrv processes - i.e. perform rollback of the data, and for journal log corruptions tmrecovercl/tmrecoversv helps to recover. Additionally transaction branches which for some reason was open but not logged, shall be housekpeed by resource managers timeouts (e.g.

However, there are some trade-offs with XA transactions, like some specifics with Oracle RAC (particularly all XA transactions shall land on the same RAC node - it is RAC configuration) and secondly, transaction logs currently are stored on the local servers disks (tmsrv -l folders), which means some challenges if willing to failover the given.

For this purpose was redefined tpsvrinit (initialization of DB instance and credentials) and EnduroX DB configuration which defined in ini files can't be used.

to access the configuration settings in ini files, you can use cconfsrv's service "@CCONF". Just call the service in way as described here: https://www.endurox.org/dokuwiki/doku.php?id=endurox:v8.0.x:manuals:cconfsrv.8 it will return UBF (FML) buffer with key/value entries resolved for the ini files used. You can safely use this API for access your application ini settings. Just do not call your sections with symbol in start.

For example:

$ cat  test.ud
SRVCNM    @CCONF
EX_CC_CMD    g
EX_CC_LOOKUPSECTION    @global/RM1TMQ" 

$ ud32 < test.ud

SENT pkt(1) is :
EX_CC_CMD    g
EX_CC_LOOKUPSECTION    @global/RM1TMQ" 

RTN pkt(1) is :
EX_CC_CMD    g
EX_CC_LOOKUPSECTION    @global/RM1TMQ" 
EX_CC_SECTION    @global
EX_CC_SECTION    @global
EX_CC_SECTION    @global
...
EX_CC_KEY    NDRX_CLUSTERISED
EX_CC_KEY    NDRX_CMDWAIT
EX_CC_KEY    NDRX_CONFIG
...
EX_CC_VALUE    1
EX_CC_VALUE    1
EX_CC_VALUE    /home/user1/conf/ndrxconfig.xml

reads the merged

[@global]
...

[@global/RM1TMQ]
...

sections

RE: How to call server in conversational mode thru restincl? - Added by Andrey about 1 year ago

Thank you very much for the answer!

We will try to create MVP based on this.

Currently we are using Oracle, but in the future plan to use Postgre in parallel for new and migrated services.

RE: How to call server in conversational mode thru restincl? - Added by Lauris about 1 year ago

You are welcome!

For PostgreSQL we also support distributed transactions. However due to PostgreSQL limitations, every time service joins the global transaction, new transaction branch is created, and this particular transaction branch does not see changes form other branches, thus you cannot add foreign keys in one service to data added by other service in the same global transaction. However full commit / rollback will work.

Additionally for yesterdays post, pls add flags "FDATASYNC;DSYNC" to NDRX_XA_FLAGS which will ensure the log consistency on the disk:


[@global/TRAN]
NDRX_XA_RES_ID=1
NDRX_XA_OPEN_STR=-
NDRX_XA_CLOSE_STR=-
NDRX_XA_DRIVERLIB=libndrxxanulls.so
NDRX_XA_RMLIB=-
NDRX_XA_LAZY_INIT=1
NDRX_XA_FLAGS=FDATASYNC;DSYNC

[@global/ORAXA]
# Remember to give different ID:
NDRX_XA_RES_ID=2
NDRX_XA_OPEN_STR=ORACLE_XA+SqlNet=ORACLESID1+ACC=P/dbuser/dbpass111+SesTM=180+LogDir=./+nolocal=f+Threads=true
NDRX_XA_CLOSE_STR=${NDRX_XA_OPEN_STR}
NDRX_XA_RMLIB=/path/to/oracle/libclntsh.so
NDRX_XA_LAZY_INIT=1
NDRX_XA_FLAGS=RECON:*:3:100;FDATASYNC;DSYNC
NDRX_XA_DRIVERLIB=libndrxxaoras.so

(1-7/7)