Skip to content

Commit 5485a26

Browse files
committed
fixing timeout issues
1 parent 92b2050 commit 5485a26

3 files changed

Lines changed: 56 additions & 21 deletions

File tree

demo/src/main/java/pl/selvin/android/listsyncsample/provider/RequestExecutor.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,38 @@
44

55
import java.io.BufferedInputStream;
66
import java.io.IOException;
7+
import java.util.concurrent.TimeUnit;
78

9+
import okhttp3.CacheControl;
10+
import okhttp3.ConnectionPool;
811
import okhttp3.MediaType;
912
import okhttp3.OkHttpClient;
1013
import okhttp3.Request;
1114
import okhttp3.RequestBody;
1215
import okhttp3.Response;
1316
import okhttp3.ResponseBody;
1417
import okio.BufferedSink;
18+
import pl.selvin.android.listsyncsample.BuildConfig;
19+
import pl.selvin.android.listsyncsample.Constants;
1520
import pl.selvin.android.syncframework.content.BaseContentProvider;
1621

1722
public class RequestExecutor implements pl.selvin.android.syncframework.content.RequestExecutor {
18-
private final OkHttpClient client = new OkHttpClient();
23+
private final OkHttpClient client;
24+
25+
public RequestExecutor() {
26+
final int connectTimeout = 3;
27+
final int timeout = 15;
28+
final String USER_AGENT = String.format("%s(%s)(%s)(%s)", BuildConfig.APPLICATION_ID, BuildConfig.BUILD_TYPE, BuildConfig.FLAVOR, BuildConfig.VERSION_NAME);
29+
final OkHttpClient.Builder builder = new OkHttpClient.Builder().addInterceptor(
30+
chain -> chain.proceed(chain.request().newBuilder().header("User-Agent", USER_AGENT).build()));
31+
client = builder
32+
.connectTimeout(connectTimeout, TimeUnit.SECONDS)
33+
.callTimeout(timeout, TimeUnit.MINUTES)
34+
.readTimeout(timeout, TimeUnit.MINUTES)
35+
.writeTimeout(timeout, TimeUnit.MINUTES)
36+
.connectionPool(new ConnectionPool(5, 5, TimeUnit.MINUTES))
37+
.build();
38+
}
1939

2040
@Override
2141
public Result execute(int requestMethod, String serviceRequestUrl, final BaseContentProvider.ISyncContentProducer syncContentProducer) throws IOException {
@@ -43,13 +63,25 @@ public void writeTo(@NonNull BufferedSink sink) throws IOException {
4363
} catch (Exception ex) {
4464
throw new RuntimeException(ex);
4565
}
46-
return new Result(new BufferedInputStream(body.source().inputStream(), 4 * 1024 * 1024), response.code(), error) {
66+
return new Result(body.source().inputStream(), response.code(), error) {
4767
@Override
4868
public void close() {
49-
body.close();
69+
response.close();
5070
}
5171
};
5272
}
73+
response.close();
5374
throw new RuntimeException("Response body is null");
5475
}
76+
77+
@Override
78+
public void doPing() {
79+
try {
80+
final Request.Builder requestBuilder = new Request.Builder().url(Constants.SERVICE_URI + "DefaultScopeSyncService.svc/$syncscopes")
81+
.method("HEAD", null).cacheControl(new CacheControl.Builder().noCache().noStore().build());
82+
final Response response = client.newCall(requestBuilder.build()).execute();
83+
response.close();
84+
} catch (Exception ignore) {
85+
}
86+
}
5587
}

sync-framework/src/main/java/pl/selvin/android/syncframework/content/BaseContentProvider.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@
3737
import java.util.ArrayList;
3838
import java.util.Calendar;
3939
import java.util.HashMap;
40+
import java.util.concurrent.Executors;
41+
import java.util.concurrent.ScheduledExecutorService;
42+
import java.util.concurrent.ScheduledFuture;
43+
import java.util.concurrent.TimeUnit;
4044

4145
import pl.selvin.android.autocontentprovider.content.AutoContentProvider;
4246
import pl.selvin.android.autocontentprovider.db.TableInfo;
@@ -48,13 +52,16 @@ public abstract class BaseContentProvider extends AutoContentProvider {
4852
public final static String DATABASE_OPERATION_TYPE_UPGRADE = "DATABASE_OPERATION_TYPE_UPGRADE";
4953
public final static String DATABASE_OPERATION_TYPE_CREATE = "DATABASE_OPERATION_TYPE_CREATE";
5054
public final static String ACTION_SYNC_FRAMEWORK_DATABASE = "ACTION_SYNC_FRAMEWORK_DATABASE";
51-
private static final String DATABASE_OPERATION_TYPE = "DATABASE_OPERATION_TYPE";
55+
private final static String DATABASE_OPERATION_TYPE = "DATABASE_OPERATION_TYPE";
56+
private final static long PING_DELAY_SECONDS = 60;
5257
protected final RequestExecutor executor;
5358
private final SyncContentHelper syncContentHelper;
59+
private final ScheduledExecutorService pingExecutor;
5460

5561
public BaseContentProvider(SyncContentHelper contentHelper, Logger logger, SupportSQLiteOpenHelperFactoryProvider supportSQLiteOpenHelperFactoryProvider, RequestExecutor executor) {
5662
super(contentHelper, logger, supportSQLiteOpenHelperFactoryProvider);
5763
syncContentHelper = contentHelper;
64+
pingExecutor = Executors.newScheduledThreadPool(1);
5865
this.executor = executor;
5966
}
6067

@@ -123,6 +130,8 @@ public Stats sync(String service, String scope, String params, Stats stats) {
123130
final String download = String.format(syncContentHelper.DOWNLOAD_SERVICE_URI, service, scope, params);
124131
final String upload = String.format(syncContentHelper.UPLOAD_SERVICE_URI, service, scope, params);
125132
final String scopeServerBlob = String.format("%s.%s.%s", service, scope, SYNC.serverBlob);
133+
final ScheduledFuture<?> scheduledFuture =
134+
pingExecutor.scheduleWithFixedDelay(executor::doPing, PING_DELAY_SECONDS, PING_DELAY_SECONDS, TimeUnit.SECONDS);
126135
String serverBlob = null;
127136
final Cursor cur = db.query(
128137
SupportSQLiteQueryBuilder.builder(BlobsTable.NAME).columns(new String[]{BlobsTable.C_VALUE})
@@ -172,7 +181,6 @@ public Stats sync(String service, String scope, String params, Stats stats) {
172181

173182
}
174183
logger.LogD(getClass(), serviceRequestUrl);
175-
long startTime = System.currentTimeMillis();
176184
result = executeRequest(requestMethod, serviceRequestUrl, contentProducer);
177185
if (result.status == 200) {
178186
if (contentProducer != null)
@@ -211,10 +219,6 @@ public Stats sync(String service, String scope, String params, Stats stats) {
211219
meta.tempId = null;
212220
values.clear();
213221
while (jp.nextToken() != JsonToken.END_OBJECT) {
214-
final long currentTime = System.currentTimeMillis();
215-
if (currentTime - startTime > 1000 * 30) {
216-
startTime = doPing(startTime, currentTime);
217-
}
218222
name = jp.getCurrentName();
219223
current = jp.nextToken();
220224
switch (current) {
@@ -318,7 +322,7 @@ public Stats sync(String service, String scope, String params, Stats stats) {
318322
logger.LogD(clazz, "*Sync* has resolve conflicts: " + resolveConflicts);
319323
} else {
320324
boolean fixed = false;
321-
final String error = result.getError();
325+
final String error = result.error;
322326
if (error != null) {
323327
if (error.contains("00-00-00-05-00-00-00-00-00-00-00-01") && !serializationException) {
324328
//nasty 500: System.Runtime.Serialization.SerializationException ... using upload instead download with the same serverBlob should help
@@ -394,14 +398,10 @@ public Stats sync(String service, String scope, String params, Stats stats) {
394398
db.insert(BlobsTable.NAME, SQLiteDatabase.CONFLICT_REPLACE, cv);
395399
}
396400
logger.LogTimeD(clazz, "*Sync* time", start);
401+
scheduledFuture.cancel(true);
397402
return stats;
398403
}
399404

400-
@SuppressWarnings("UnusedParameters")
401-
public long doPing(long startTime, long currentTime) {
402-
return currentTime;
403-
}
404-
405405
protected RequestExecutor.Result executeRequest(int requestMethod, String serviceRequestUrl, final ISyncContentProducer syncContentProducer) throws IOException {
406406
return executor.execute(requestMethod, serviceRequestUrl, syncContentProducer);
407407
}

sync-framework/src/main/java/pl/selvin/android/syncframework/content/RequestExecutor.java

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,18 @@ public interface RequestExecutor {
2121

2222
Result execute(int requestMethod, String serviceRequestUrl, final BaseContentProvider.ISyncContentProducer syncContentProducer) throws IOException;
2323

24+
/*
25+
If execution of synchronisation is longer than some 5 min(I believe)
26+
and there is no IO involved android OS kills sync process.
27+
To avoid you need to provide implementation which will called every 1 minute
28+
which will do some "internet" operation fx do HEAD request to your server
29+
*/
30+
void doPing();
2431

2532
class Result {
2633
public final int status;
27-
final InputStream inputBuffer;
28-
final String error;
34+
public final InputStream inputBuffer;
35+
public final String error;
2936

3037

3138
protected Result(InputStream inputBuffer, int status, String error) {
@@ -36,9 +43,5 @@ protected Result(InputStream inputBuffer, int status, String error) {
3643

3744
public void close() {
3845
}
39-
40-
String getError() {
41-
return error;
42-
}
4346
}
4447
}

0 commit comments

Comments
 (0)