[!GOLD] Status dokumen
Dokumen ini adalah analisis fase pertama. Isinya belum merupakan SRS, HLD, LLD, atau Impact Analysis, dan belum menyatakan rancangan sudah diimplementasikan. Empat dokumen tersebut baru dibuat setelah scope dan keputusan di bagian akhir disetujui secara eksplisit.
Menyusun flow High Availability SHIFRAUD berdasarkan source aplikasi di shifraud-core dan konfigurasi infrastruktur di /home/goy/shifor/shifraud-ha-conf.
Analisis membedakan empat jenis evidence:
| Label | Arti |
|---|---|
CONFIRMED |
Terlihat langsung di source, config, atau log yang diperiksa |
REFERENCE |
Diklaim oleh README/playbook, tetapi belum dibuktikan oleh runtime test |
DERIVED |
Kesimpulan teknis dari beberapa evidence |
PROPOSED |
Target design yang belum diimplementasikan |
| Area | Klaim/dokumen | Config yang aktif | Runtime evidence yang tersedia | Kesimpulan |
|---|---|---|---|---|
| PostgreSQL | Empat node Patroni dalam satu stretched cluster | Empat node, tiga etcd, failover_priority DC 100 dan DRC 1 |
Tidak ada hasil test terisi | Logika election tersedia, hasil failover belum terbukti |
| DB entry point | haproxy-dc:5000 mengikuti leader lintas site |
Satu instance HAProxy di DC | Belum ada runtime evidence continuity | Masih single point of failure |
| App | app-dc dan app-drc active-active |
Kedua app dan Nginx di-comment/nonaktif; upstream DRC juga di-comment | Log lama DRC menunjukkan gagal resolve haproxy-drc |
Active-active belum terwujud |
| Redis | Master/replica dengan Sentinel failover | Local test: satu Sentinel, quorum 1; production template: tiga Sentinel, quorum 2 |
Belum ada hasil failover terukur | Local bukan HA; topology production gagal quorum jika dua Sentinel DC hilang |
| Ingress | Nginx membagi trafik ke dua app | Nginx production hanya mengaktifkan app DC | Tidak ada continuity evidence | App ingress masih DC-centric |
| Data durability | PostgreSQL replication lintas site | Asynchronous; synchronous_mode tidak aktif |
Tidak ada RPO test | Committed transaction terakhir masih berisiko hilang saat failover |
| Idempotency | Retry transaksi aman | Ada unique key (stan, local_date, pid) pada changelog utama |
Belum ada test retry lintas failover | Fondasi ada, kontrak replay end-to-end belum terbukti |
| Observability | Failover audit tersedia | FailoverAuditLogger ada |
Dua file failover-audit.log kosong |
Belum cukup untuk audit failover produksi |
CONFIRMED — docker-compose.yml membentuk satu cluster Patroni fds-cluster: dua node DC, dua node DRC, dan tiga etcd pada site logis berbeda.CONFIRMED — HAProxy port 5000 memeriksa endpoint Patroni /primary; port 5001 memeriksa /replica.CONFIRMED — node DRC ditandai backup pada HAProxy, sementara Patroni memberi failover_priority: 100 pada DC dan 1 pada DRC.CONFIRMED — DataSourceConfig membuat datasource WRITE dan READ; TransactionRoutingDataSource memilih READ hanya saat transaksi Spring berstatus read-only, selain itu WRITE.CONFIRMED — Liquibase hanya dijalankan melalui writeDataSource.CONFIRMED — app dan Nginx tidak menjadi service aktif pada compose lokal.CONFIRMED — production Nginx hanya mengaktifkan upstream app DC; semua upstream app DRC masih berupa komentar.CONFIRMED — local Redis mempunyai satu Sentinel dengan quorum 1. Playbook sendiri mengakui Sentinel dan HAProxy lokal masih SPOF.CONFIRMED — file audit failover DC dan DRC ada tetapi kosong pada snapshot yang diperiksa.CONFIRMED — log 27 Februari 2026 menunjukkan app DRC gagal start karena UnknownHostException: haproxy-drc. Log 2 Maret 2026 menunjukkan app DC gagal inisialisasi karena database shifraud belum ada. Log ini adalah snapshot lama, bukan bukti kondisi live saat ini.Diagram tersebut adalah gabungan source/config yang dimaksud, bukan runtime proof. Compose aktif saat ini tidak menjalankan Nginx DC atau App DC.
REFERENCE — playbook mengharapkan recovery sekitar 10–30 detik. Nilai tersebut belum dianggap hasil karena metrics sheet masih kosong dan tidak ada test artifact yang membuktikannya.
Playbook test 2.5 memerintahkan stop haproxy-dc, lalu memverifikasi write melalui haproxy-dc:5000. Langkah tersebut kontradiktif. Setelah HAProxy dihentikan, endpoint yang diuji juga hilang.
| Observed problem | Evidence | Root cause / status | Dampak | Required change |
|---|---|---|---|---|
| Database bisa promote di DRC tetapi service belum tentu dapat diakses | HAProxy dan Nginx production hanya ada di DC | CONFIRMED — entry point tidak redundant lintas site |
Full outage walau DB DRC sehat | Sediakan ingress dan DB proxy per site dengan health-based traffic steering |
| Klaim app active-active tidak sama dengan config | App services dan upstream DRC nonaktif | CONFIRMED |
Tidak ada failover app layer | Deploy minimal satu app sehat per site dan aktifkan health check |
| Test full-site tidak executable sesuai tujuan | Stop haproxy-dc, lalu query hostname yang sama |
CONFIRMED |
False confidence dari test plan | Query melalui endpoint DRC/global yang memang tetap hidup |
| Redis production kehilangan majority saat DC hilang | Dua Sentinel di DC, satu di DRC, quorum 2 |
DERIVED, sesuai aturan majority Redis Sentinel |
Redis DRC tidak dapat melakukan failover otomatis | Sebar Sentinel 1 DC + 1 DRC + 1 witness/third site |
| Potensi kehilangan committed write | Patroni memakai asynchronous replication; synchronous_mode tidak ada |
CONFIRMED |
RPO lebih besar dari nol saat primary/site hilang | Putuskan RPO; aktifkan synchronous mode hanya jika bisnis mewajibkan dan latency sudah diuji |
| Retry bisa menggandakan side effect | Response dapat hilang setelah commit; client/LB dapat retry | DERIVED; constraint (stan, local_date, pid) hanya melindungi insert transaksi utama |
Alert, reaction, notification, atau external call dapat terduplikasi | Definisikan idempotency boundary dan replay response untuk seluruh side effect |
| In-flight transaction tidak bisa dipindahkan ke node lain | TCP connection dan Server_Collection berada di memory node |
CONFIRMED |
Client timeout/reconnect; status transaksi bisa UNKNOWN |
Reconciliation berdasarkan business key; jangan blind retry |
| In-memory state berbeda antar app node | SSE emitter, TCP connection, velocity write-behind, dan beberapa cache bersifat node-local | CONFIRMED |
Missed push, skewed counters, lost buffered aggregate saat crash | Klasifikasikan state: rebuildable, replicated, sticky, atau harus dipindah ke shared store |
| Semua scheduler akan aktif pada setiap app node | Sebagian scheduler memakai ShedLock, sebagian tidak | CONFIRMED |
Duplicate job/cleanup/file processing | Audit seluruh @Scheduled; gunakan distributed lock atau leader-only worker sesuai semantics |
| Audit failover belum membuktikan event runtime | Audit files kosong; logDbReconnect dan logTransactionInFlight belum terbukti terpanggil |
CONFIRMED |
RCA dan bukti regulator lemah | Wire event secara nyata dan kirim ke centralized immutable logging |
| Config dependency tidak reproducible | Dockerfile.patroni memasang Patroni tanpa pin versi |
CONFIRMED |
Behavior build dapat berubah | Pin versi Patroni dan lock artifact/image digest |
| README mengandung dua arsitektur | Bagian stretched auto-failover berdampingan dengan manual DR/standby_cluster lama |
CONFIRMED |
Operator dapat menjalankan runbook yang salah | Hapus/arsipkan flow lama setelah target disetujui |
HA saat ini dirancang per komponen, belum sebagai satu service flow end-to-end. Patroni election, HAProxy routing, Sentinel, Nginx, dan app node dibahas terpisah. Akibatnya sebuah komponen dapat dinyatakan berhasil failover walau jalur client → app → DB/cache sudah putus.
Untuk sistem finansial, status sukses harus ditentukan pada boundary bisnis: apakah request diterima, commit terjadi, response terkirim, side effect hanya sekali, dan transaksi dapat direkonsiliasi ketika response tidak diketahui.
UP; readiness harus memastikan write path, cache path, dan konfigurasi kritis dapat digunakan.UNKNOWN. Reconciliation mendahului retry.| Layer | DC | DRC | Witness/third site | Mekanisme |
|---|---|---|---|---|
| Global entry | Endpoint DC | Endpoint DRC | Control/health only | Global LB, DNS failover, atau network VIP TBD |
| App LB | Dua instance/VIP atau managed LB | Dua instance/VIP atau managed LB | Not Applicable | Active health check, connection drain |
| App | Minimal satu node, jumlah final TBD |
Minimal satu node, jumlah final TBD |
Not Applicable | Stateless request processing; state eksternal/rebuildable |
| DB proxy | HAProxy pair/site atau managed equivalent | HAProxy pair/site atau managed equivalent | Not Applicable | Keduanya probe semua Patroni node; write mengikuti /primary |
| PostgreSQL | Patroni priority tinggi | Patroni priority rendah | Not Applicable | Satu fds-cluster, satu primary |
| DCS | etcd1 | etcd2 | etcd3 | Majority 2/3 |
| Redis data | Master/replica candidate | Replica/master candidate | Not Applicable | Replication dan controlled promotion |
| Redis Sentinel | Sentinel 1 | Sentinel 2 | Sentinel 3 | Quorum 2, majority tetap tersedia saat satu site hilang |
| Observability | Local collector | Local collector | Central store TBD |
Metrics, logs, traces, audit lintas site |
| Area | Before | After | Dampak | Requirement/Decision |
|---|---|---|---|---|
| Service health | Health per proses/komponen | Readiness end-to-end per site | Mengurangi false-ready | DEC-INFRA-001 |
| App ingress | Nginx hanya DC; DRC upstream nonaktif | Endpoint/LB independen di DC dan DRC | DRC tetap reachable | DEC-INFRA-001 |
| DB proxy | Satu HAProxy di DC | Proxy redundant per site | Hilangkan DB entry-point SPOF | DEC-INFRA-002 |
| PostgreSQL | Stretched async Patroni | Single-writer tetap; durability mode diputuskan dari RPO | Availability vs latency eksplisit | DEC-DB-001 |
| Redis Sentinel | Local satu Sentinel; prod 2 DC + 1 DRC | 1 DC + 1 DRC + 1 witness | Majority survive one-site loss | DEC-CACHE-001 |
| Retry | Generic retry belum dibatasi | Retry dengan business idempotency + reconciliation | Mencegah duplicate financial side effect | DEC-APP-001 |
| Scheduler | Campuran locked/unlocked | Semua job diklasifikasi dan dikoordinasikan | Hindari duplicate job | DEC-APP-002 |
| SSE/TCP | Node-local connection | Reconnect-aware; tidak menjanjikan seamless transfer | Client behavior eksplisit | DEC-APP-003 |
| Failback | Manual, gate belum lengkap | Controlled switchover setelah lag/health gate | Mengurangi second outage | DEC-OPS-001 |
| Testing | Banyak expected result, metrics kosong | Evidence bundle per scenario | Klaim HA dapat diaudit | DEC-OPS-002 |
App dapat active-active. PostgreSQL dalam design ini tidak: hanya satu primary yang menerima write. Redis juga mempunyai satu master. Istilah yang lebih tepat adalah active-active application, active-passive stateful services, multi-site automatic failover.
Dengan ttl: 30, election dan reconnection mempunyai failure window. Koneksi TCP lama putus dan tidak dapat dipindahkan. Request yang sudah commit tetapi response belum sampai menjadi UNKNOWN. Karena itu target “zero downtime” atau “zero failed transaction” tidak boleh disetujui tanpa protocol-specific retry/reconciliation dan hasil test.
failover_priority bukan larangan absolutPatroni mengutamakan node dengan WAL receive/replay LSN paling maju; priority membedakan kandidat ketika posisi WAL setara. Jadi klaim “DRC hanya pernah promote setelah semua node DC mati” perlu diuji terhadap lag/timeline aktual, bukan hanya dibaca dari nilai 100 versus 1.
Konfigurasi sekarang mengutamakan availability dan latency, tetapi dapat kehilangan committed write yang belum sampai ke replica. Dokumentasi resmi Patroni menjelaskan bahwa batas data loss juga dipengaruhi WAL yang ditulis selama window ttl. Untuk transaksi finansial, pemilik bisnis harus menyetujui RPO. synchronous_mode tidak boleh diaktifkan otomatis tanpa latency dan WAN partition test.
Semua transaksi Spring readOnly=true diarahkan ke port 5001. Setelah write, request berikutnya dapat membaca replica yang belum catch up. Flow yang membutuhkan read-your-write harus tetap ke primary atau menggunakan consistency rule yang eksplisit.
Config Nginx open-source baru menandai backend bermasalah setelah request error/timeout. Untuk financial traffic, routing idealnya memakai active readiness probe yang memeriksa dependency penting. Tetap perlu batas agar health check tidak memperparah load saat DB/cache terganggu.
| Area | Current state | Target state | Gap | Required change |
|---|---|---|---|---|
| Infrastructure | LB/proxy utama di DC | Endpoint independen per site | Belum ada DRC entry point | Tambah LB/proxy DRC dan global steering |
| Application | DRC app belum aktif | App runnable dan ready di kedua site | Deployment/config belum tersedia | Buat profile/env contract yang sama, berbeda endpoint/node ID |
| Database | Election tersedia | Election + reachable proxy + measured RPO | Proxy dan RPO belum selesai | Redundant proxy, version pin, failover test |
| Cache | Sentinel placement tidak tahan DC loss | Majority lintas tiga failure domain | Penempatan salah | Pindah salah satu Sentinel DC ke witness |
| Idempotency | Unique transaction tuple tersedia | Semua duplicate side effect dibatasi | Coverage belum terbukti | Trace transaction, alert, reaction, notification, external call |
| Scheduler | Sebagian memakai ShedLock | Semua job safe multi-node | Beberapa job tidak locked | Audit dan pilih lock/leader/outbox |
| Stateful memory | Banyak state node-local | State loss/rebuild behavior eksplisit | Belum diklasifikasi | Inventory dan test node crash |
| Observability | Log audit kosong | Correlated failover audit dan metric | Wiring/centralization belum terbukti | Instrument event dan immutable sink |
| Operations | Runbook lama dan baru bercampur | Satu approved runbook | Operator ambiguity | Hapus flow manual lama setelah migration |
| Security | Placeholder credential dan plaintext endpoints | Secret management + TLS sesuai environment | Production config belum final | Integrate vault/secret store dan certificate lifecycle |
| Skenario | Perilaku yang diharapkan | Risiko | Penanganan | Status/evidence |
|---|---|---|---|---|
| Commit berhasil, response putus | Retry mengembalikan outcome yang sama | Double debit/reaction | Reconcile by business key; replay result | PROPOSED |
| DC-Witness partition, DRC punya quorum | Hanya partition mayoritas boleh primary | Split brain | etcd majority + fencing test | Config ada, test belum terbukti |
| DRC tertinggal > allowed lag | Jangan promote kandidat yang unsafe | Data loss | Lag gate dan alert | maximum_lag_on_failover ada |
| Read segera setelah write | Data terbaru terbaca | Stale decision | Primary read/read-your-write rule | NEEDS_CLARIFICATION |
| Redis master hilang bersama dua Sentinel DC | DRC tetap dapat authorize promotion | Cache outage | Sentinel ketiga di witness | Current prod topology gagal criterion |
| App mati saat write-behind buffer terisi | Raw transaction tetap durable; aggregate direbuild | Temporary scoring skew | Recovery/warmup test dan metric buffer | Source menyebut rebuildable, runtime unverified |
| TCP client reconnect ke node lain | Session baru diterima, old in-flight direkonsiliasi | Duplicate/timeout | Client contract + business idempotency | NEEDS_CLARIFICATION |
| SSE client pindah node | Client reconnect dan refresh state | Missed notification | SSE sebagai hint, state diambil dari API/DB | PROPOSED |
| Dua app menjalankan scheduler tanpa lock | Hanya satu side effect terjadi | Duplicate batch/cleanup | ShedLock/leader-only/idempotent worker | Gap ditemukan |
| Liquibase start pada dua app | Migration serialized atau dipisah dari app start | Startup race/lock contention | Dedicated migration job disarankan | PROPOSED |
| DC pulih dengan timeline lama | Node rejoin sebagai replica | Divergent history | pg_rewind, timeline verification |
Config use_pg_rewind ada |
| Global LB menganggap app sehat saat DB write path gagal | Site tidak menerima write traffic | Error storm | Dependency-aware readiness dengan timeout | PROPOSED |
| Opsi | Manfaat | Kekurangan | Risiko | Kompleksitas/upaya | Rekomendasi |
|---|---|---|---|---|---|
| A. Pertahankan satu stretched Patroni cluster, tambah ingress/proxy per site | Perubahan paling dekat dengan config sekarang; automatic election tetap | Bergantung WAN dan DCS lintas site | Latency replication, partition handling | Menengah | Direkomendasikan sebagai baseline, setelah RPO dan network topology disetujui |
| B. Dua cluster terpisah dengan manual DR | Isolasi site lebih kuat; operasi DR eksplisit | RTO lebih lama; promote/failback rumit | Human error, stale replica, split brain saat salah prosedur | Menengah-tinggi | Pilih jika governance melarang stretched DCS |
| C. Dua cluster dengan logical/CDC replication | Fleksibel untuk regional topology | Conflict, ordering, schema compatibility jauh lebih kompleks | Duplicate/lost financial side effect | Tinggi | Tidak direkomendasikan tanpa kebutuhan multi-writer yang nyata |
| D. Managed PostgreSQL multi-AZ/multi-region | Mengurangi operasi Patroni/etcd | Vendor/cost/network constraint; belum tentu tersedia on-prem | Lock-in dan capability mismatch | Bergantung platform | Evaluasi hanya bila environment mengizinkan |
Rekomendasi awal adalah opsi A, tetapi istilah “active-active” dibatasi pada app layer. Database dan Redis tetap single-primary dengan automatic promotion.
| ID | Keputusan | Domain/Jenis | Status | Rationale/Evidence | Dampak | Relasi |
|---|---|---|---|---|---|---|
DEC-INFRA-001 |
Sediakan ingress sehat dan independen di DC/DRC, lalu global traffic steering | Infrastructure | PROPOSED |
Ingress sekarang hanya DC | DRC dapat menerima trafik saat DC hilang | Full-site flow |
DEC-INFRA-002 |
Jalankan DB proxy redundant per site | Infrastructure | PROPOSED |
haproxy-dc adalah SPOF |
App DRC tidak bergantung proxy DC | DEC-INFRA-001 |
DEC-DB-001 |
Pertahankan PostgreSQL single-writer dan putuskan async/sync berdasarkan RPO | Database | NEEDS_CLARIFICATION |
Async memberi availability, tetapi RPO > 0 | Mempengaruhi latency dan durability | RPO/RTO |
DEC-CACHE-001 |
Tempatkan Sentinel pada tiga failure domain | Cache | PROPOSED |
Majority harus bertahan dari satu site loss | Redis failover tetap authorized | Full-site flow |
DEC-APP-001 |
Wajibkan idempotency + reconciliation untuk financial retry | Application | PROPOSED |
Unique tuple belum membuktikan semua side effect aman | Mengurangi duplicate dan status UNKNOWN |
Retry flow |
DEC-APP-002 |
Audit dan koordinasikan semua scheduled job untuk multi-node | Application | PROPOSED |
Ada scheduler tanpa @SchedulerLock |
Hindari duplicate processing | App active-active |
DEC-APP-003 |
Perlakukan TCP/SSE sebagai reconnectable, bukan transparently movable | Application | PROPOSED |
Connection state berada di memory node | Client contract dan UX harus jelas | Failover flow |
DEC-OPS-001 |
Failback selalu controlled switchover setelah health/lag gate | Operations | PROPOSED |
Automatic failback berisiko second outage | Recovery lebih aman | Recovery flow |
DEC-OPS-002 |
Klaim HA hanya setelah evidence bundle test terisi | Operations | PROPOSED |
Metrics sheet dan audit log masih kosong | Status readiness dapat diaudit | Semua decision |
DEC-SEC-001 |
Production menggunakan secret management dan encrypted transport | Security | PROPOSED |
Template masih berisi placeholder dan local config terbuka | Mengurangi credential/network exposure | Production deployment |
(perlu dilengkapi).TBD.STAN + localDate + pid yang stabil, dan bagaimana response duplicate harus dibentuk? NEEDS_CLARIFICATION.NEEDS_CLARIFICATION.(perlu dilengkapi).Approval yang disarankan:
Jika scope ini disetujui dengan APPROVED atau GENERATE DOCUMENTATION, fase berikutnya akan menghasilkan tepat empat artefak: SRS, HLD, LLD, dan Impact Analysis.
src/main/java/com/shifor/shifraud/GeneralComponent/Config/DataSource/DataSourceConfig.javasrc/main/java/com/shifor/shifraud/GeneralComponent/Config/DataSource/TransactionRoutingDataSource.javasrc/main/java/com/shifor/shifraud/ISO8583/Server/TCP/TcpServerInit.javasrc/main/java/com/shifor/shifraud/ISO8583/Server/TCP/TcpServerHandler.javasrc/main/java/com/shifor/shifraud/ISO8583/Audit/FailoverAuditLogger.javasrc/main/java/com/shifor/shifraud/Rule/Engine/CoreNew/Logic/Velocity/WriteBehindBuffer.javasrc/main/java/com/shifor/shifraud/AlertManagement/Distribution/Notification/AlertSSEManager.javasrc/main/java/com/shifor/shifraud/Dashboard/Service/DashboardSSEManager.javasrc/main/resources/db/changelog/db.changelog-2026-02-24-failover.xml/home/goy/shifor/shifraud-ha-conf/docker-compose.yml/home/goy/shifor/shifraud-ha-conf/docker-compose.override.yml/home/goy/shifor/shifraud-ha-conf/HAProxy/haproxy-dc.cfg/home/goy/shifor/shifraud-ha-conf/prod/haproxy/haproxy-dc.cfg/home/goy/shifor/shifraud-ha-conf/prod/nginx/nginx-app.conf/home/goy/shifor/shifraud-ha-conf/patroni/*.yml/home/goy/shifor/shifraud-ha-conf/prod/patroni/*.yml/home/goy/shifor/shifraud-ha-conf/prod/redis/*.conf/home/goy/shifor/shifraud-ha-conf/HA-TESTING.md/home/goy/shifor/shifraud-ha-conf/PRODUCTION.md/home/goy/shifor/shifraud-ha-conf/README.mddocker compose -f /home/goy/shifor/shifraud-ha-conf/docker-compose.yml config berhasil mem-parsing base compose.docker compose config berhasil mem-parsing base compose bersama local override.