Skip to content

fix: recreate Redis stream receiver after listener failure - #157

Closed
oosuhada wants to merge 99 commits into
devxb:mainfrom
oosuhada:fix/recreate-redis-stream-receiver
Closed

fix: recreate Redis stream receiver after listener failure#157
oosuhada wants to merge 99 commits into
devxb:mainfrom
oosuhada:fix/recreate-redis-stream-receiver

Conversation

@oosuhada

@oosuhada oosuhada commented Aug 27, 2026

Copy link
Copy Markdown

요약

  • Redis Stream listener가 오류로 종료된 뒤 재구독할 때 기존 StreamReceiver 인스턴스를 재사용하던 동작을 수정했습니다.
  • 재구독마다 새로운 StreamReceiver를 생성하도록 변경해, 네트워크/연결 오류 이후 기존 receiver가 stale/terminal 상태에 남아도 listener가 복구될 수 있도록 했습니다.
  • 첫 receiver가 오류를 반환한 뒤 자동 재구독 과정에서 두 번째 receiver가 새로 생성되는 회귀 테스트를 추가했습니다.
  • 기존 릴리스 패턴에 맞춰 버전을 0.5.00.5.1로 올렸습니다.

배경

AbstractSagaListener는 listener가 종료되면 subscribeStream()을 다시 호출해 자동 복구를 시도합니다. 하지만 RedisStreamSagaListenerStreamReceiver를 프로퍼티로 한 번만 생성해 두고 있었기 때문에, receiver 자체가 연결 오류 이후 복구 불가능한 상태가 되면 재구독에서도 같은 인스턴스를 계속 사용하게 됩니다.

이 동작은 git-goods/gitanimals#501에서 관찰된 장시간 실행 API의 Saga timeout 증상을 조사하면서 확인했습니다. 해당 서비스에서는 일반 read API는 정상인 상태에서 Saga 기반 write 요청만 기본 10초/100초 결과 timeout으로 실패하고 있었습니다.

테스트

  • ./gradlew test --tests 'org.rooftop.netx.redis.RedisStreamSagaListenerTest' --console=plain
  • patched Netx를 로컬 gitanimals-api에 연결해 아래 Saga 회귀 테스트를 각각 깨끗한 Redis에서 검증했습니다.
    • GotchaFacadeV3Test
    • RegisterProductFacadeTest
    • BuyProductFacadeTest

Summary

  • recreate the Redis StreamReceiver whenever the listener subscribes again after an error
  • avoid reusing a stale/terminal receiver instance across the existing auto-restart path
  • add a regression test verifying that a receiver failure causes a new receiver to be created on resubscription
  • bump the release version from 0.5.0 to 0.5.1, following the existing release pattern

Background

AbstractSagaListener already attempts to recover by calling subscribeStream() again after termination. However, RedisStreamSagaListener previously kept one StreamReceiver instance for its entire lifetime. If that receiver itself becomes stale or terminal after a connection failure, resubscribing keeps reusing the same broken receiver.

This behavior was identified while investigating git-goods/gitanimals#501, where long-running API instances continued serving reads while Saga-based writes consistently timed out waiting for results.

Test

  • ./gradlew test --tests 'org.rooftop.netx.redis.RedisStreamSagaListenerTest' --console=plain
  • verified the patched Netx against gitanimals-api Saga tests with clean Redis instances:
    • GotchaFacadeV3Test
    • RegisterProductFacadeTest
    • BuyProductFacadeTest

devxb added 30 commits February 1, 2024 19:31
* build: gradle 의존을 설정하고 기본 라이브러리를 추가한다

* build: Netx-IDL 을 서브모듈로 추가한다

* docs: Readme.md 를 꾸민다

* build: jvmTarget을 21에서 17로 변경한다

* ci: assigner, tester, type-labeler 를 추가한다

* refactor: protobuf idl 경로를 ./api-spec에서 ./idl 로 변경한다
* feat: transaction api 를 정의한다

* feat: 실제 동작이 구현되어있는 engine 레이어를 정의하고 동작을 구현한다

* feat: Transaction의 상태별로 event 를 발행하게 한다

* refactor: Transaction start 혹은 join일때, transaction을 구독하도록한다

* feat: redis-stream 기반의 transation-manager 를 구현한다

* feat: AutoConfig 를 정의한다

* fix: TransactionIdGenerator에서 존재하지 않는 클래스 구현하고 있는 버그 수정

* refactor: transaction id 를 node-id 기반으로 생성하도록 수정

* refactor: 자동구성이 어노테이션 기반으로 동작 가능하도록 수정한다

* refactor: TransactionEvent들에 어떤 서버에서 발행되었는지 확인할 수 있도록 nodeName 필드를 추가한다

* refactor: TransactionDispatcher를 추상화시키고, 로직을 따르도록 강제화 한다

* fix: RedisStream 구독을 poll 방식이 아닌 subscirbe 방식으로 수정하고 처음부터 모든 데이터를 읽어오도록 한다

* refactor: replay 필드가 rollback 이벤트에만 존재하도록 수정한다

* refactor: exists 메소드 구현을 engine레이어로 올리고, context를 세팅한다

* refactor: transformTransactionId 이름을 mapTransactionId로 변경한다

* test: RedisStreamTransactionManager의 Test를 작성한다

* build: jitpack 배포 플러그인을 설정한다

* docs: 사용법과 다운로드 방법을 작성한다

* docs: 분산 트랜잭션 작동과정 gif를 추가한다
* build: jitpack 배포구성을 설정한다

* build: sonarProjectKey가 잘못 설정 되어있는버그수정

* build: sonarProjectKey 수정
* feat: Netx가 undo 상태를 따로 관리하도록 수정한다

* refactor: 2개로 분리된 AutoConfigure 어노테이션을 하나로 합친다
* refactor: UndoManager를 삭제하고, 메시지큐에서 전부 관리하도록 수정한다

* feat: 처리하지 못한 고아 트랜잭션을 찾아서 처리하는 recovery기능을 추가한다

* fix: RedisRetrySupporter가 Pending 상태의 메시지를 파싱하지 못하는 버그를 수정한다

* feat: pending되었지만, ack되지않은 트랜잭션을 찾아서 처리하는 기능을 추가한다

* build: netx-idl 버전 최신화
* fix: interval 과정중 에러 방출시 무시하고 계속 interval 되도록 수정한다

* refactor: 로컬 로직이 실패하면 분산트랜잭션도 ack되지 않도록 수정한다

* test: TransactionHandlerAssertions을 사용하고 항상 초기화하도록 수정한다
* test: Netx client 부하테스트를 작성한다

* perf: netx redis-stream 구현채가 하나의 커넥션으로 트랜잭션을 수신할 수 있도록 수정한다
* 자신이 발행한 transaction을 찾지 못하는 버그를 수정한다

* refactor: 사용하지 않는 메소드를 삭제한다
* feat: sync 호출을 지원한다

* docs: README에 동기 지원 방식을 추가한다

* docs: README code의 컨벤션 오류를 수정한다

* docs: 분산트랜잭션 동작과정 사진을 330 -> 365 로 증가시킨다

* docs: 분산트랜잭션 사진을 365 -> 360 으로 변경한다

* �docs: version update 0.1.9 to 0.2.0
…evxb#42)

* perf: supprot Backpressure and & auto restart transaciton listener

* docs: netx version 0.2.0 to 0.2.1

* perf: boundElastic 과 parallel 사용을 수정한다
devxb and others added 25 commits March 30, 2024 10:22
* refactor: replace word transaction to saga

* build: netx version 0.3.8 to 0.3.9
* refactor: Access modifier public to internal

* refactor: OrchestratorChain's return type to api.OrchestratorFactory
* feat: Get orchestratorFactory method to api.OrchestratorFactory

* docs: Autowired OrchestratorFactory to Instance OrchestratorFactory
* refactor: sagaManager's sync... method to ...sync

* docs: Write dokka doc
* build: Chaing publish repository jitpack to maven central

* docs: Download url to maven central and add test section

* docs: update link and test image

* docs: fixed inner tps link

* docs: update option and description of features

* docs: add blocking supports word on description
…vxb#132)

* fix: Primary to reactiveRedisTemplate and reactiveRedisConnection

* docs: version 0.4.0 to 0.4.1
* refactor: Catch toOrchestrateEvent's exception

* refactor: version 0.4.1 to 0.4.2
* test: Orchestrator Result test 를 추가한다

* refactor: Orchestrator도중에 예외가 발생하면, 이전 chain부터 rollback이 수행되도록 한다

* docs: Readme.md에 rollback 발생 순서를 수정한다

* build: version을 0.4.2에서 0.4.3으로 올린다
* refactor: abstract saga listener를 graceful하게 종료한다

* build: version to 0.4.3 -> 0.4.4-beta-1
…xb#143)

* fix: miss action in decodeResultOrThrow when using TypeReference

* docs: version upgrade
* refactor: JsonCodec fail on Unknown property

* refactor: JsonCodec Fail On Missing properties

* docs: version 0.4.5 0> 0.4.6
)

* fix: 특정 예외필드가 serialize가 안되는버그를 수정한다

* docs: version up
* fix: Infinite loading phenomenon when error encoding fails

* docs: version 0.4.7 -> 0.4.8
* feat: Rollback Consumer Dead Letter

* docs: add dead letter description

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…evxb#155)

* fix: Restrict Orchestrator process only messages from its own group

* docs: version up 0.4.9 -> 0.5.0
@oosuhada

Copy link
Copy Markdown
Author

@devxb 확인 부탁드립니다.

git-goods/gitanimals#501 운영 장애가 아직 지속 중입니다. 방금 다시 확인했을 때 Gotcha 500 누적 건수는 199 → 204로 증가했고 성공 건수는 4,025에서 그대로였으며, Auction 신규 등록도 2026-08-22 이후 멈춰 있습니다.

이 PR의 0.5.1을 사용하도록 gitanimals-api dependency bump 브랜치도 준비해두었습니다: oosuhada/gitanimals-api:fix/issue-501-shop (749c7da). 0.5.1이 merge/release되면 바로 API 쪽 PR로 이어갈 수 있습니다.


@devxb Could you please take a look when you have a chance?

The production issue tracked in git-goods/gitanimals#501 is still ongoing. The Gotcha 500 count increased from 199 to 204 while successful requests stayed at 4,025, and new Auction registrations are still stuck after 2026-08-22.

I also prepared the gitanimals-api dependency bump branch for Netx 0.5.1: oosuhada/gitanimals-api:fix/issue-501-shop (749c7da). Once 0.5.1 is merged/released, the API PR is ready to follow.

@oosuhada oosuhada closed this Aug 28, 2026
@oosuhada
oosuhada force-pushed the fix/recreate-redis-stream-receiver branch from 3b73875 to 0ec2c96 Compare August 28, 2026 08:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants