Android okHttp 重试策略
Android okHttp Retry policy
我正在尝试创建一个简单的包装器,它将调用服务器下载信息并解析发送的二进制数据。
对于连接,我使用名为 okhttp 的库,因为 3G 上的连接不是很可靠,我决定使用以下函数实现一个非常简单的重试功能**(请注意,此方法将始终从后台线程调用)**
private InputStream callServer() throws ServerException, NoNetworkAvailableException, ConnectionErrorException {
NetworkOperation networkOperation = getNetworkOperation();
InputStream inputStream = null;
//in case of network problems we will retry 3 times separated by 5 seconds before gave up
while (connectionFailedRetryCounter < connectionFailedMaximumAllowedRetries()) {
connectionFailedRetryCounter++;
try {
inputStream = networkOperation.execute();
break;//if this line was reached it means a successfull operation, no need to retry .
} catch (ConnectionErrorException e) {
if (canRetryToConnect()) {
Utils.forceSleepThread(Constants.Communications.ConnectionFailedTrialCounter.SLEEP_BETWEEN_REQUESTS_MILLI);//retry after 5 secs (Thread.sleep)
} else {
throw e;//I give up
}
}
}
return inputStream;
}
private boolean canRetryToConnect() {
return (connectionFailedRetryCounter < connectionFailedMaximumAllowedRetries()) && !canceled;
}
这样做正确吗?还是它自己的库已经完成了(不需要实现这样的东西)?
这是方法 execute() 的作用
public InputStream execute() throws ConnectionErrorException, NoNetworkAvailableException, ServerException {
if (!Utils.isNetworkAvailable(context)) {
throw new NoNetworkAvailableException();
}
Response response = doExecute();
if (!response.isSuccessful()) {
throw new ServerException(response.code());
}
return response.body().byteStream();
}
private Response doExecute() throws ConnectionErrorException {
Response response;
try {
if (getRequestType() == RequestType.GET) {
response = executeGet();
} else {
response = executePost();
}
} catch (IOException e) {
throw new ConnectionErrorException();
}
return response;
}
如果抓到 NoNetworkAvailableException
,您可以避免重试。如果您知道以下尝试无论如何都会失败,请不要重试。
我会让 connectionFailedMaximumAllowedRetries()
成为常量。我怀疑您是否需要随时更改变量。
实施exponential back off。你可以让它重试 10 次。每次,您将延迟乘以 2(上限为几分钟)。例如:
- 尝试调用 - 失败
- 等待 1 秒
- 尝试调用 - 失败
- 等待 2 秒
- 尝试调用 - 失败
- 等待 4 秒
- ...
- 尝试调用 - 成功
这是非常典型的行为。如果发生短暂的中断,调用将很快再次进行并成功。如果停电时间较长,您不希望每隔几秒就不断呼叫。这为您的代码提供了使其调用通过的最佳机会。显然,如果 UI 更改需要此调用,则应注意不要惹恼用户。
在 Failsafe's OkHttp 支持下可以很容易地处理您的场景:
RetryPolicy<Response> retryPolicy = RetryPolicy.builder()
.handle(ConnectionErrorException.class)
.withMaxRetries(3)
.withDelay(Duration.ofSeconds(5))
.build();
Call call = client.newCall(request);
FailsafeCall failsafeCall = FailsafeCall.with(retryPolicy).compose(call);
// Execute with retries
Response response = failsafeCall.execute();
这适用于同步和异步执行并支持取消。 RetryPolicy 也支持各种其他配置。
我正在尝试创建一个简单的包装器,它将调用服务器下载信息并解析发送的二进制数据。 对于连接,我使用名为 okhttp 的库,因为 3G 上的连接不是很可靠,我决定使用以下函数实现一个非常简单的重试功能**(请注意,此方法将始终从后台线程调用)**
private InputStream callServer() throws ServerException, NoNetworkAvailableException, ConnectionErrorException {
NetworkOperation networkOperation = getNetworkOperation();
InputStream inputStream = null;
//in case of network problems we will retry 3 times separated by 5 seconds before gave up
while (connectionFailedRetryCounter < connectionFailedMaximumAllowedRetries()) {
connectionFailedRetryCounter++;
try {
inputStream = networkOperation.execute();
break;//if this line was reached it means a successfull operation, no need to retry .
} catch (ConnectionErrorException e) {
if (canRetryToConnect()) {
Utils.forceSleepThread(Constants.Communications.ConnectionFailedTrialCounter.SLEEP_BETWEEN_REQUESTS_MILLI);//retry after 5 secs (Thread.sleep)
} else {
throw e;//I give up
}
}
}
return inputStream;
}
private boolean canRetryToConnect() {
return (connectionFailedRetryCounter < connectionFailedMaximumAllowedRetries()) && !canceled;
}
这样做正确吗?还是它自己的库已经完成了(不需要实现这样的东西)?
这是方法 execute() 的作用
public InputStream execute() throws ConnectionErrorException, NoNetworkAvailableException, ServerException {
if (!Utils.isNetworkAvailable(context)) {
throw new NoNetworkAvailableException();
}
Response response = doExecute();
if (!response.isSuccessful()) {
throw new ServerException(response.code());
}
return response.body().byteStream();
}
private Response doExecute() throws ConnectionErrorException {
Response response;
try {
if (getRequestType() == RequestType.GET) {
response = executeGet();
} else {
response = executePost();
}
} catch (IOException e) {
throw new ConnectionErrorException();
}
return response;
}
如果抓到 NoNetworkAvailableException
,您可以避免重试。如果您知道以下尝试无论如何都会失败,请不要重试。
我会让 connectionFailedMaximumAllowedRetries()
成为常量。我怀疑您是否需要随时更改变量。
实施exponential back off。你可以让它重试 10 次。每次,您将延迟乘以 2(上限为几分钟)。例如:
- 尝试调用 - 失败
- 等待 1 秒
- 尝试调用 - 失败
- 等待 2 秒
- 尝试调用 - 失败
- 等待 4 秒
- ...
- 尝试调用 - 成功
这是非常典型的行为。如果发生短暂的中断,调用将很快再次进行并成功。如果停电时间较长,您不希望每隔几秒就不断呼叫。这为您的代码提供了使其调用通过的最佳机会。显然,如果 UI 更改需要此调用,则应注意不要惹恼用户。
在 Failsafe's OkHttp 支持下可以很容易地处理您的场景:
RetryPolicy<Response> retryPolicy = RetryPolicy.builder()
.handle(ConnectionErrorException.class)
.withMaxRetries(3)
.withDelay(Duration.ofSeconds(5))
.build();
Call call = client.newCall(request);
FailsafeCall failsafeCall = FailsafeCall.with(retryPolicy).compose(call);
// Execute with retries
Response response = failsafeCall.execute();
这适用于同步和异步执行并支持取消。 RetryPolicy 也支持各种其他配置。