RxJava2, RxAndroid2

[RxJava2] 예외처리2 - 재시도 : retry(), retryUntil(), retryWhen()

알통몬_ 2018. 10. 11. 14:47
반응형


공감 및 댓글은 포스팅 하는데

 아주아주 큰 힘이 됩니다!!

포스팅 내용이 찾아주신 분들께 

도움이 되길 바라며

더 깔끔하고 좋은 포스팅을 

만들어 나가겠습니다^^

 



이번 포스팅에서는 예외처리 두 번째

재시도 함수들에 대해 공부합니다.


서버와 통신을 할 때 인터넷이 일시적으로 안되거나 서버에 일시적으로 장애가

발생하면 클라이언트에서는 일정 시간 후에 다시 통신을 요청하는 기능을

구현해놓을 필요가 있습니다.

이 때 1개의 API가 아닌 다수의 API 를 연속하여 호출해야 하는 시나리오가 있다면

꽤나 복잡해질 수도 있겠죠?


RxJava2에서는 이런 것들을 단순하게 처리할 수 있도록

retryXXX() 함수들을 제공합니다.


retry()

Observable에서 onError() 이벤트 발생 시 바로 다시 subscribe()를 호출해

재구독하도록 되어 있음.

예제)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package rx.java.chapter07;
 
import java.io.IOException;
 
import com.yudong80.reactivejava.common.Log;
 
import io.reactivex.Observable;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
 
public class RetryEx {
 
    static OkHttpClient client = new OkHttpClient();
    static String url = "https://api.github.com/zen";
 
    public static void main(String[] args) {
 
        final int RETRY = 5;
 
        Observable<String> src = Observable.just(url).map(RetryEx::get).retry((count, e) -> {
            System.out.println("count : " + count);
            try {
            Thread.sleep(1000);
            } catch (Exception ex) {
                // TODO: handle exception
            }
            return count < RETRY ? true : false;
        }).onErrorReturn(e -> "-500");
 
        src.subscribe(data -> System.out.println("result => " + data));
    }
 
    public static String get(String url) throws IOException {
        Request request = new Request.Builder().url(url).build();
        try {
            Response res = client.newCall(request).execute();
            return res.body().string();
        } catch (IOException e) {
            Log.et(e.getMessage());
            throw e;
        }
    }
 
}
 
cs

onError() 발생시 바로 재시도가 되면 의미가 없으므로 1초의 Thread.sleep()을

주었습니다. 이 예제는 인터넷이 안되는 상황에서 실행해야 합니다 ㅎㅎ

인터넷이 되는 상황이면 정상동작합니다.


retryUntil()

특정 조건이 충족될 때까지 재시도하는 함수

retry() 는 재시도록 지속할 조건이 없을 때 재시도를 중단하고,

retryUntil() 은 재시도 중단 조건이 발생할 때까지 재시도함.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package rx.java.chapter07;
 
import java.io.IOException;
import java.net.InetAddress;
 
import com.yudong80.reactivejava.common.Log;
 
import io.reactivex.Observable;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
 
public class RetryUntilEx {
 
    static OkHttpClient client = new OkHttpClient();
    static String url = "https://api.github.com/zen";
 
    public static void main(String[] args) {
        
        Observable<String> src = Observable.just(url)
                .map(RetryUntilEx::get)
                .subscribeOn(Schedulers.io())
                .retryUntil(() -> {
                    if(isNetworkAvailable()) {
                        return true;
                    }
                    Thread.sleep(1000);
                    return false;
                });
 
        src.subscribe(data -> System.out.println("result => " + data));
        try {
            Thread.sleep(5000);
        } catch (Exception e) {
            // TODO: handle exception
        }
    }
 
    public static String get(String url) throws IOException {
        Request request = new Request.Builder().url(url).build();
        try {
            Response res = client.newCall(request).execute();
            return res.body().string();
        } catch (IOException e) {
            Log.et(e.getMessage());
            throw e;
        }
    }
    
    public static boolean isNetworkAvailable() { 
        try {
            return InetAddress.getByName("www.naver.com").isReachable(1000);
        } catch (IOException e) {
            Log.v("Network is not available");    
        }
        return false;
    }
    
}
 
cs

isNetworkAvailable() 함수는 현재 네트워크가 사용 가능한 상태인지를 파악하기 위한

함수 입니다. 우리 모두가 알 고 있는 네이버에 접근시도를 해서 접근이 되면 true

안되면 false를 반환합니다.

동작은 역시 네트워크가 안되는 상황에서 하셔야 에러발생을 확인할 수 있습니다.


retryWhen()

재시도 조건을 동적으로 설정해야하는 복잡한 로직을 구현할 때 활용하면 좋습니다.

단, retryWhen()의 인자가 Observable<Throwable> 이고 이해하기 어려운 함수이므로

충분한 공부가 필요할 듯 합니다.

아래는 총 5회 재시도를 하고 1번 실패할 때마다 딜레이를 1초씩 늘려나가는

예제입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package rx.java.chapter07;
 
import java.util.concurrent.TimeUnit;
 
import io.reactivex.Observable;
 
public class RetryWhenEx {
 
    public static void main(String[] args) {
 
 
        Observable.<String>create(emit -> {
            emit.onError(new RuntimeException("fails"));
        }).retryWhen(rw -> {
            return rw.zipWith(Observable.range(15), (a, b) -> b)
                    .flatMap(m -> {
                        System.out.println("delay " + m + "seconds");
                        return Observable.timer(m, TimeUnit.SECONDS);
                    });
        }).blockingForEach(System.out::println);
        
    }
 
}
 
cs


이상입니다.

다음 포스팅에서는 Observable이 데이터를 발행하는 속도와 옵저버가 데이터를 받아

처리하는 속도의 차이가 발생할 때 사용하는 흐름 제어 함수에 대해 공부합니다.


반응형