Phase 1: 실동작 Enduro/X + PostgreSQL XA 매입 슬라이스
- Enduro/X 7.0.12 소스빌드 이미지(-DENABLE_POSTGRES=ON, libndrxxaecpg XA 스위치) - docker-compose: postgres(max_prepared_transactions=100) + endurox app - ECPG XA 서비스 3종: ACQUIRE→RECONCILE→SETTLE (tpservice + EXEC SQL) - 클라이언트 tpbegin/tpcall체인/tpcommit → tmsrv 2PC(prepare/commit) 원자 커밋 - 검증: 서비스 AVAIL, 커밋 row(status=S) psql 확인, 롤백 시 무잔존, pg_prepared_xacts=0 - 규명된 런타임 요건: sysctl fs.mqueue.*, ulimit msgqueue/nofile, XA open-str JSON - docs/architecture.md, README, service-catalog 설계 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
commit
e6e29e6b5d
19 changed files with 1005 additions and 0 deletions
7
slice/acq.fd
Normal file
7
slice/acq.fd
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
$/* @(#) Acquiring UBF field table */
|
||||
*base 6000
|
||||
T_MERCHANT 1 string - -
|
||||
T_AMOUNT 2 long - -
|
||||
T_FEE 3 long - -
|
||||
T_NET 4 long - -
|
||||
T_STATUS 5 string - -
|
||||
30
slice/acqcl.c
Normal file
30
slice/acqcl.c
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <atmi.h>
|
||||
#include <ubf.h>
|
||||
#include "acq.fd.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (tpinit(NULL) < 0) { fprintf(stderr, "tpinit FAIL: %s\n", tpstrerror(tperrno)); return 1; }
|
||||
|
||||
UBFH *b = (UBFH *)tpalloc("UBF", NULL, 1024);
|
||||
long amount = 1000000; /* 10,000.00원 */
|
||||
Bchg(b, T_MERCHANT, 0, "M0001", 0L);
|
||||
Bchg(b, T_AMOUNT, 0, (char *)&amount, 0L);
|
||||
|
||||
long rlen = 0;
|
||||
if (tpcall("ACQUIRE", (char *)b, 0L, (char **)&b, &rlen, 0L) < 0) {
|
||||
fprintf(stderr, "tpcall FAIL: %s\n", tpstrerror(tperrno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
long fee = 0, net = 0; char st[32] = ""; BFLDLEN l = sizeof(st);
|
||||
Bget(b, T_FEE, 0, (char *)&fee, 0L);
|
||||
Bget(b, T_NET, 0, (char *)&net, 0L);
|
||||
Bget(b, T_STATUS, 0, st, &l);
|
||||
printf(">>> TPCALL OK: amount=%ld fee=%ld net=%ld status=%s\n", amount, fee, net, st);
|
||||
|
||||
tpfree((char *)b); tpterm();
|
||||
return 0;
|
||||
}
|
||||
49
slice/acqsv.c
Normal file
49
slice/acqsv.c
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <atmi.h>
|
||||
#include <ubf.h>
|
||||
#include <userlog.h>
|
||||
#include "acq.fd.h"
|
||||
|
||||
void ACQUIRE(TPSVCINFO *p); /* forward decl */
|
||||
|
||||
/* 서버 프로세스 초기화/종료 콜백 (ATMI 필수) */
|
||||
int tpsvrinit(int argc, char **argv)
|
||||
{
|
||||
if (tpadvertise("ACQUIRE", ACQUIRE) < 0) {
|
||||
userlog("acqsv: tpadvertise(ACQUIRE) FAIL: %s", tpstrerror(tperrno));
|
||||
return -1;
|
||||
}
|
||||
userlog("acqsv: tpsvrinit - ACQUIRE 서비스 advertise 완료");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tpsvrdone(void)
|
||||
{
|
||||
userlog("acqsv: tpsvrdone - 종료");
|
||||
}
|
||||
|
||||
void ACQUIRE(TPSVCINFO *p)
|
||||
{
|
||||
UBFH *b = (UBFH *)p->data;
|
||||
long amount = 0, fee, net;
|
||||
char merch[64] = "";
|
||||
BFLDLEN len = sizeof(merch);
|
||||
|
||||
if (Bget(b, T_MERCHANT, 0, merch, &len) < 0) {
|
||||
userlog("ACQUIRE: missing T_MERCHANT: %s", Bstrerror(Berror));
|
||||
tpreturn(TPFAIL, 0, p->data, 0L, 0L);
|
||||
return;
|
||||
}
|
||||
Bget(b, T_AMOUNT, 0, (char *)&amount, 0L);
|
||||
|
||||
fee = amount * 25 / 10000; /* 0.25% MDR 수수료 */
|
||||
net = amount - fee;
|
||||
|
||||
Bchg(b, T_FEE, 0, (char *)&fee, 0L);
|
||||
Bchg(b, T_NET, 0, (char *)&net, 0L);
|
||||
Bchg(b, T_STATUS, 0, "ACQUIRED", 0L);
|
||||
|
||||
userlog("ACQUIRE merch=%s amount=%ld fee=%ld net=%ld", merch, amount, fee, net);
|
||||
tpreturn(TPSUCCESS, 0, p->data, 0L, 0L);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue