Channel은 코루틴 사이에서 데이터를 주고받기 위한 통신 수단입니다.Flow가 값을 순차적으로 방출하고 수집하는 구조라면, Channel은 송신자와 수신자가 서로 다른 코루틴에서 데이터를 주고받을 수 있도록 연결하는 역할을 합니다. Channel 기본Channel은 데이터를 보내는 SendChannel과 데이터를 받는 ReceiveChannel을 모두 구현합니다.public interface Channel : SendChannel, ReceiveChannel데이터를 보낼 때는 send(), 받을 때는 receive()를 사용합니다.val channel = Channel()launch { channel.send("데이터1") channel.send("데이터2")}launch { pri..
Flow를 테스트할 때는 Flow가 완료되는지, 무한히 방출되는지, 시간에 따라 값이 변하는지에 따라 테스트 방법을 다르게 선택해야 합니다.코루틴 테스트 라이브러리만으로도 테스트할 수 있지만, Turbine을 사용하면 Flow에서 발생하는 이벤트를 보다 직관적으로 검증할 수 있습니다. Flow의 값 테스트하기Flow가 방출하는 모든 값을 확인하려면 toList()를 사용할 수 있습니다.val result = flowOf(1, 2, 3).toList()assertEquals(listOf(1, 2, 3), result) toList()는 Flow가 완료될 때까지 모든 값을 수집합니다.따라서 완료되는 Flow에는 적합하지만, 무한히 값을 방출하는 Flow에 사용하면 수집이 끝나지 않고 계속 메모리에 값을 저..
이번 장에서는 차가운 Flow를 SharedFlow, StateFlow로 변환하는 방법과 MutableSharedFlow의 버퍼, emit/tryEmit, 뜨거운 Flow의 캡슐화 방법을 다룹니다. 차가운 Flow를 뜨거운 Flow로 변환하기차가운 Flow는 collect될 때마다 새로운 데이터 스트림이 생성됩니다.여러 구독자가 하나의 데이터 스트림을 공유해야 한다면 shareIn, stateIn을 사용해 뜨거운 Flow로 변환할 수 있습니다. shareInshareIn은 차가운 Flow를 SharedFlow로 변환합니다.flow.shareIn( scope = scope, started = SharingStarted.WhileSubscribed(), replay = 0) 핵심 설정은..
Flow는 데이터 스트림이 생성되는 방식에 따라 차가운 Flow(Cold Flow)와 뜨거운 Flow(Hot Flow)로 나눌 수 있습니다. 일반적인 Flow는 차가운 Flow이며, SharedFlow, StateFlow는 뜨거운 Flow입니다. 차가운 Flow (Cold Flow)collect 일시 중단 함수가 호출되는 시점에 비로소 데이터 생산을 시작하는 게으른(lazy) 스트림입니다.collect를 호출할 때마다 매번 새로운 데이터 스트림이 생성됩니다.여러 곳에서 수집할 경우 동일한 데이터 생산 작업이 중복 실행되어 네트워크나 DB 리소스 낭비가 발생할 수 있습니다.뜨거운 Flow (Hot Flow)collect 호출 여부와 관계없이 데이터를 생성하고 방출할 수 있는 스트림입니다.여러 수집기(구독..
결합 연산자 (Combining Operators)는 여러 Flow에서 발생하는 데이터 스트림을 결합하여 하나의 Flow로 만드는 연산자입니다. 대표적으로 zip과 combine이 있으며, 데이터 결합 시점과 완료 조건에서 동작 차이가 있습니다. zip 연산자zip은 두 Flow에서 방출되는 원소들을 순서대로 1:1 매칭하여 새로운 값으로 결합합니다. 동작 방식: 두 Flow의 원소가 모두 수집될 때까지 일시 중단(suspend) 상태로 대기합니다. 스트림의 발행 속도가 다르더라도 데이터 순서에 맞춰 짝이 구성될 때까지 기다린 후 결합을 진행합니다. 완료 조건: 두 Flow 중 어느 한쪽이라도 방출이 완료되면 zip 연산이 종료되며, 아직 완료되지 않은 다른 쪽 Flow에는 취소(cancel)가 요청됩..
비동기 스트림에서 데이터를 생산하는 속도(업스트림)와 이를 소비하여 처리하는 속도(다운스트림)가 다를 때, 시스템 과부하를 막고 효율적으로 흐름을 제어하기 위해 배압(Backpressure) 제어가 필수적입니다. 코틀린 Flow는 단일 코루틴 내 순차 실행을 기본으로 하되, 비동기 경계가 분리되는 시점에서 배압을 통제할 수 있는 다양한 연산자들을 제공합니다.배압(Backpressure)이 발생하는 원인단일 코루틴의 순차 실행 (배압 없음): 기본적으로 Flow의 생산(emit)과 수집(collect)은 동일한 코루틴 내에서 순차적으로 실행됩니다. 소비자가 이전 데이터를 처리하기 전까지는 생산자도 일시 중단(suspend)되어 다음 데이터를 생산하지 않으므로 데이터가 누적되지 않습니다.비동기 경계 분리 (..
Flow의 생명주기 연산자(Lifecycle Operator)는 데이터 스트림의 시작, 값의 방출, 완료 및 취소, 비어 있는 스트림 처리 등 Flow 파이프라인의 전반적인 생명주기 흐름을 감시하고 제어할 때 사용됩니다. onStart (수집 시작 시점 제어)onStart는 Flow의 수집(collect)이 시작되기 직전에 특정 동작을 수행하도록 정의하는 연산자입니다.대상 Flow가 실제 수집을 시작하기 전에 초기화 작업이나 사전 대기 상태 등을 구현할 때 활용하기 좋습니다. val flow = flowOf(1, 2, 3) .onStart { println("Flow 수집을 시작합니다") }flow.collect { println(it) }/*[실행 결과]Flow 수집을 시작합니다123*/ onCo..
Flow에서 비동기 데이터 스트림을 처리할 때 예외(Exception)를 어떻게 다루는지는 어플리케이션의 안정성에 직접적인 영향을 미칩니다. 예외 투명성(Exception Transparency) 원칙Flow의 예외 처리 설계에서 가장 중요한 원칙은 예외 투명성입니다.예외 투명성: 예외를 처리하는 연산자가 자신보다 상위인 업스트림에서 발생한 예외만 처리하고, 다운스트림에서 발생한 예외는 처리하지 않도록 설계하는 원칙만약 중간 연산자가 내부에서 무분별하게 try-catch 블록으로 방출 및 소비 흐름 전체를 감싸버리면, 최종 소비자(collect)가 데이터를 처리하다가 터뜨린 예외까지 의도치 않게 삼켜버리거나 꼬이게 됩니다.이는 예외가 발생한 실제 위치와 예외를 처리하는 위치를 명확하게 구분하기 어렵게 ..
Flow 취소의 기본 메커니즘Flow의 collect는 일시 중단 함수(suspend function)이므로, 수집을 호출한 코루틴(Job)을 취소하는 것이 기본적인 취소 방식입니다. 코루틴이 취소되면 Flow의 데이터 방출과 수집도 함께 중단됩니다.val job = launch { numberFlow.collect { value -> println(value) }}delay(1000L)job.cancel() // 코루틴을 취소하여 수집 중단 SafeFlow의 자동 취소 검증flow { ... } 빌더로 생성되는 SafeFlow는 내부적으로 SafeCollector를 사용합니다. SafeCollector는 emit이 호출될 때마다 코루틴의 활성 상태(ensureActive()..
코틀린에서 flow { ... }를 선언하고 collect를 호출하는 과정은 간결해 보이지만, 실제로는 단순한 인터페이스 호출의 연속입니다. Flow와 FlowCollector 인터페이스는 매우 심플하게 정의되어 있습니다.public interface Flow { public suspend fun collect(collector: FlowCollector)}public interface FlowCollector { public suspend fun emit(value: T)}이 추상화된 관계를 이해하기 위해, 익명 객체를 활용해 Flow의 실체를 직접 구현해 보면 다음과 같습니다.// 1. Flow 인터페이스를 직접 구현하는 객체 생성 (생산자)val numberFlow: Flow = obje..

