OTP Runtime: Redis vs PostgreSQL
Scope: Dokumen ini menjelaskan pemilihan store dari sisi
merchant_core_api. Sejak schemaiamdi-drop daridb_kesles_merchant, persistensi OTP runtime dimiliki olehauth_service(port 8081,db_kesles_merchant_auth).auth_servicepunya kedua backend — Redis (internal/service/redis_otp.go) dan PostgreSQL (internal/store/auth_otp.go, tabelauth.otp_challenges+auth.otp_request_locks) — tetapi tidak memakai file bernamapostgres_otp_repository.godan tidak membaca env varOTP_RUNTIME_STORE.OTP_RUNTIME_STOREhanya dibaca olehmerchant_core_apiuntuk memilih repository mana yang dipakai.
This document compares two approaches for storing runtime OTP data in Kesles Merchant.
Discussion scope:
- OTP challenge
- resend cooldown
- OTP request rate limit
- attempts increment on failed verification
Current Implementation Status
The currently active implementation uses Redis via:
redis_repository.go
A PostgreSQL-based alternative is also available via:
postgres_otp_repository.go
This alternative no longer queries any table inside merchant_core_api's own database. Since the iam schema was dropped from db_kesles_merchant, postgres_otp_repository.go now delegates every OTP runtime operation to auth_service over HTTP (authClient.OTPReserveRequest, OTPSaveChallenge, OTPGetChallenge, OTPIncrementAttempts, OTPDeleteChallenge). auth_service (port 8081, db_kesles_merchant_auth) owns the persisted OTP runtime data.
Notes:
- the active store is selected by the
OTP_RUNTIME_STOREenv var (defaultredis) - the PostgreSQL path requires
auth_serviceto be configured and reachable
Equivalent Functions
Both Redis and PostgreSQL now have the same functions at the repository level:
ReserveRequest(...)SaveChallenge(...)GetChallenge(...)IncrementAttempts(...)DeleteChallenge(...)
Redis
Active file:
redis_repository.go
How it works:
- the cooldown is stored in a TTL key
- the rate limit is counted via a TTL counter
- the OTP challenge is stored in a hash per
request_id - challenge expiry is helped by Redis TTL
Key patterns:
auth:otp:cooldown:{phone}auth:otp:rate:{phone}auth:otp:challenge:{request_id}
Pros:
- fast
- native TTL
- well suited for ephemeral data
- simple cooldown/rate-limit implementation
- lighter PostgreSQL load
Cons:
- needs additional Redis infrastructure
- OTP state is split between PostgreSQL and Redis
- debugging sometimes requires access to two stores
PostgreSQL
Alternative file:
postgres_otp_repository.go
How it works:
- all five repository functions proxy to
auth_serviceover HTTP viaauthClient auth_servicepersists cooldown, request window, request count, and the OTP challenge in its own database (db_kesles_merchant_auth)ReserveRequest(...)callsauthClient.OTPReserveRequest(...), which returns a rate-limit error (HTTP 429) when the limit is exceeded- the consistency guarantees (transaction and row lock) live inside
auth_service, not inmerchant_core_api
Pros:
- a single primary data source in PostgreSQL (owned by
auth_service) - easier manual audit via SQL on
db_kesles_merchant_auth - no need for an extra Redis service
Cons:
- heavier for very ephemeral data
- expiry cleanup must be designed yourself
- rate limit and cooldown are more complex
- more query load on PostgreSQL
Quick Comparison
Redis is more suitable when:
- OTP traffic is fairly high
- you want native, fast TTL
- you accept an additional cache/storage component
PostgreSQL is more suitable when:
- you want to reduce infrastructure components
- traffic is still low to medium
- you accept the trade-off of heavier queries
Practical Recommendation
For the current repo state:
- keep Redis as the active OTP runtime implementation (default)
- only use the PostgreSQL OTP runtime if you want simpler infrastructure
- the PostgreSQL path now requires
auth_serviceto be configured and reachable, since persistence happens there
Steps If You Want To Switch
The minimal steps are:
- set
OTP_RUNTIME_STORE=postgres(read byselectOTPRepositoryininternal/httpapi/server.go) - make sure
auth_serviceis configured and reachable (the PostgreSQL path proxies all OTP operations to it) - re-test cooldown, rate limit, and OTP verify