Browse Source

Reconstructed retry System an 15 Minute limitation

Added more logs
master
Bianca Steffes 2 years ago
parent
commit
06b60a0533
  1. 210
      export/src/export/Main.java

210
export/src/export/Main.java

@ -15,8 +15,10 @@ import java.net.URL;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Calendar; import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -44,28 +46,31 @@ public class Main
private static String testRequest; private static String testRequest;
private static File errorFile; private static File errorFile;
// TODO: enduco needs to insert the correct request limits here // TODO: enduco needs to insert the correct request limits here
private static final int requestLimit15Minutes = 100;
private static final int requestLimit15Minutes = 100 / 3;
private static final int requestLimitDay = 1000 / 3; private static final int requestLimitDay = 1000 / 3;
private static int simpleActivityId=0;
private static int dailyRequestCount = 0; private static int dailyRequestCount = 0;
private static int waitTimeMil = 60000 * 3 * 15 / requestLimit15Minutes;
private static long lastRequestTimeInMillis = 0;
private static int fifteenMinuteRequestCount = 0;
private static long firstRequestTimeInCurrent15MinInterval = 0;
private static String accessToken = ""; private static String accessToken = "";
/** /**
* a is client_id, b is client_secret, c is refresh_token * a is client_id, b is client_secret, c is refresh_token
*/ */
private static Triplet refreshInfo; private static Triplet refreshInfo;
private static void writeError(String text, InputStream errorStream)
private static void writeLog(String text, InputStream errorStream)
{ {
SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy HH:mm:ss");
if (errorFile == null) if (errorFile == null)
{ {
errorFile = new File("error_" + System.currentTimeMillis() + ".txt");
errorFile = new File("log_" + System.currentTimeMillis() + ".txt");
} }
try (BufferedWriter bout = new BufferedWriter(new FileWriter(errorFile, true))) try (BufferedWriter bout = new BufferedWriter(new FileWriter(errorFile, true)))
{ {
bout.write(text);
bout.write(format.format(new Date(System.currentTimeMillis()))+": "+text);
bout.newLine(); bout.newLine();
if (errorStream!= null) if (errorStream!= null)
{ {
@ -87,9 +92,9 @@ public class Main
} }
} }
private static void writeError(String text)
private static void writeLog(String text)
{ {
writeError(text, null);
writeLog(text, null);
} }
@ -122,7 +127,7 @@ public class Main
} }
catch (NoAccessException e1) catch (NoAccessException e1)
{ {
writeError("Athlete " + athleteId + ": Access expired and no new token possible");
writeLog("Athlete " + athleteId + ": Access expired and no new token possible");
return null; // no data at all. Stop right away return null; // no data at all. Stop right away
} }
if (athleteInfo == null) // error getting General Information if (athleteInfo == null) // error getting General Information
@ -133,7 +138,7 @@ public class Main
// for each activity: save streams // for each activity: save streams
JSONArray allActivities = new JSONArray(); JSONArray allActivities = new JSONArray();
int simpleActivityId = 0;
simpleActivityId = 0;
for (String id : activities.keySet()) for (String id : activities.keySet())
{ {
JSONObject data; JSONObject data;
@ -143,7 +148,7 @@ public class Main
} }
catch (NoAccessException e) catch (NoAccessException e)
{ {
writeError("Athlete " + athleteId + ": Access expired and no new token possible");
writeLog("Athlete " + athleteId + ": Access expired and no new token possible");
break; //stop the loop and save what you got up to there break; //stop the loop and save what you got up to there
} }
data.put("activity_id", simpleActivityId); data.put("activity_id", simpleActivityId);
@ -164,7 +169,7 @@ public class Main
} }
catch (IOException e) catch (IOException e)
{ {
writeError("Athlete " + athleteId + ": Error writing temp file: " + e.toString());
writeLog("Athlete " + athleteId + ": Error writing temp file: " + e.toString());
} }
return null; return null;
} }
@ -203,7 +208,7 @@ public class Main
} }
catch (ParseException | NumberFormatException e) catch (ParseException | NumberFormatException e)
{ {
writeError("Athlete " + athleteId + ": Error parsing json (Streams): " + e.toString());
writeLog("Athlete " + athleteId + ": Error parsing json (Streams): " + e.toString());
} }
return data; return data;
} }
@ -238,10 +243,8 @@ public class Main
{ {
String requestExtension = "athlete/activities?per_page=100&page=" + pageIndex; String requestExtension = "athlete/activities?per_page=100&page=" + pageIndex;
String json = makeGetRequestWithRetry(requestExtension); String json = makeGetRequestWithRetry(requestExtension);
if (json == null || json.isEmpty() || json.isBlank() || json.equals("") || json.equals("[]")) // don't know
// where the
// last page
// is...
if (json == null || json.isEmpty() || json.isBlank() || json.equals("") || json.equals("[]"))
// don't know where the last page is...
{ {
break; break;
} }
@ -270,10 +273,11 @@ public class Main
} }
catch (ParseException | NumberFormatException e) catch (ParseException | NumberFormatException e)
{ {
writeError("Athlete " + athleteId + ": Error parsing json (Activities): " + e.toString());
writeLog("Athlete " + athleteId + ": Error parsing json (Activities): " + e.toString());
} }
pageIndex++; pageIndex++;
} }
writeLog("Athlete " + athleteId + ": Found "+result.size()+"Activities");
return result; return result;
} }
@ -301,7 +305,31 @@ public class Main
catch (InterruptedException e1) catch (InterruptedException e1)
{ {
} }
//Write info what you did today
writeLog("Daily requests done. Current status: Athlete "+athleteId+", Activity "+simpleActivityId);
dailyRequestCount=0;
}
//check fifteen Minute limit
if (System.currentTimeMillis() - firstRequestTimeInCurrent15MinInterval > 15*60*1000 )
{
//more than 15 Minutes have passed, so we have a new 15 minute limit
fifteenMinuteRequestCount =0;
} }
else if(fifteenMinuteRequestCount >= requestLimit15Minutes)
{
//we are still in the old interval and reached the limit
long sleeptime = 15*60*1000 - (System.currentTimeMillis() - firstRequestTimeInCurrent15MinInterval);
//sleep for the rest of the interval and start in a new interval
try
{
TimeUnit.MILLISECONDS.sleep(sleeptime);
fifteenMinuteRequestCount=0;
}
catch (InterruptedException e)
{
}
}
} }
/** /**
@ -323,45 +351,65 @@ public class Main
try try
{ {
json = makeOneGetRequest(urlExtension); json = makeOneGetRequest(urlExtension);
dailyRequestCount++;
} }
catch (ResponseCodeWrongException e) catch (ResponseCodeWrongException e)
{ {
// tried enough times, so stop now
if (count >= retryTimes)
count = handleWrongResponseCode(count, e);
if (count == -1)
{ {
writeError(
"Athlete: " + athleteId + " Retry limit reached. Last error code: " + e.getResponseCode());
return null; return null;
} }
if (e.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED)
{ //token might have expired
if(!getAccessToken()) //token doesn't work anymore and we can't get a new one
{
throw new NoAccessException();
}
}
else if (e.getResponseCode() == httpCodeLimitReached)
{// request limit is reached, try again later
count++;
}
else // some other error: try only one other time!
{
count = retryTimes;
}
// Sleep for 5 minutes and try to get the next 15 min request window
try
{
TimeUnit.MINUTES.sleep(5);
}
catch (InterruptedException e1)
{
}
} }
} while (json == null); } while (json == null);
return json; return json;
} }
/**
* Method processed the wrong response code and adjusts the retry times as needed:
* When the retry limit is reached, -1 is returned.
* When the access limit is reached, the retry count is increased.
* When an unknown error appears, the retry count is set to max to allow only one more retry.
* After that, the method sleeps for 5 Minutes.
* @param count Retry count
* @param e Exception containing the information
* @return the new retry count or -1 if there are no more tries left
* @throws NoAccessException if no AccessToken could be requested
*/
static int handleWrongResponseCode(int count, ResponseCodeWrongException e) throws NoAccessException
{
// tried enough times, so stop now
if (count >= retryTimes)
{
writeLog(
"Athlete: " + athleteId + " Retry limit reached. Last error code: " + e.getResponseCode());
return -1;
}
if (e.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED)
{ //token might have expired
if(!getAccessToken()) //token doesn't work anymore and we can't get a new one
{
throw new NoAccessException();
}
}
else if (e.getResponseCode() == httpCodeLimitReached)
{// request limit is reached, try again later
count++;
}
else // some other error: try only one other time!
{
count = retryTimes;
}
// Sleep for 5 minutes and try to get the next 15 min request window
try
{
TimeUnit.MINUTES.sleep(5);
}
catch (InterruptedException e1)
{
}
return count;
}
/** /**
* Extracts an athletes general information. * Extracts an athletes general information.
@ -396,12 +444,12 @@ public class Main
} }
catch (ParseException e) catch (ParseException e)
{ {
writeError("Athlete " + athleteId + ": Error parsing general information.");
writeLog("Athlete " + athleteId + ": Error parsing general information.");
return null; return null;
} }
catch (NullPointerException e) catch (NullPointerException e)
{ {
writeError("Athlete " + athleteId + ": No general information found.");
writeLog("Athlete " + athleteId + ": No general information found.");
return null; return null;
} }
} }
@ -454,19 +502,6 @@ public class Main
HttpsURLConnection connection = null; HttpsURLConnection connection = null;
try try
{ {
long timeSinceLastRequest = System.currentTimeMillis() - lastRequestTimeInMillis;
if (timeSinceLastRequest < waitTimeMil)
{
try
{
TimeUnit.MILLISECONDS.sleep(waitTimeMil - timeSinceLastRequest);
}
catch (InterruptedException e)
{
}
}
;
lastRequestTimeInMillis = System.currentTimeMillis();
// Create connection // Create connection
URL url = new URL(baseUrl + requestUrlExtension); URL url = new URL(baseUrl + requestUrlExtension);
connection = (HttpsURLConnection) url.openConnection(); connection = (HttpsURLConnection) url.openConnection();
@ -477,7 +512,7 @@ public class Main
} }
catch (IOException e) catch (IOException e)
{ {
writeError("Athlete: " + athleteId + " Error while handling GET request: " + e.toString());
writeLog("Athlete: " + athleteId + " Error while handling GET request: " + e.toString());
} }
return ""; return "";
} }
@ -495,12 +530,20 @@ public class Main
{ {
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
int responseCode = connection.getResponseCode(); int responseCode = connection.getResponseCode();
if( fifteenMinuteRequestCount == 0) //first request in a 15 Min Interval
{
firstRequestTimeInCurrent15MinInterval = System.currentTimeMillis();
}
dailyRequestCount++;
fifteenMinuteRequestCount++;
if (responseCode != HttpURLConnection.HTTP_OK) if (responseCode != HttpURLConnection.HTTP_OK)
{ {
// excluded error messages appearing on missing streams and reached rate limit // excluded error messages appearing on missing streams and reached rate limit
if (responseCode != HttpURLConnection.HTTP_NOT_FOUND && responseCode != httpCodeLimitReached) if (responseCode != HttpURLConnection.HTTP_NOT_FOUND && responseCode != httpCodeLimitReached)
{ {
writeError("Athlete: " + athleteId + " Wrong response code: " + responseCode, connection.getErrorStream());
writeLog("Athlete: " + athleteId + " Wrong response code: " + responseCode, connection.getErrorStream());
} }
throw new ResponseCodeWrongException(responseCode); throw new ResponseCodeWrongException(responseCode);
} }
@ -564,7 +607,7 @@ public class Main
} }
catch (IOException e) catch (IOException e)
{ {
writeError("Athlete: " + athleteId + "Error while handling POST request: " + e.toString());
writeLog("Athlete: " + athleteId + "Error while handling POST request: " + e.toString());
} }
return ""; return "";
} }
@ -588,39 +631,20 @@ public class Main
try try
{ {
json = makeOnePostRequest(); json = makeOnePostRequest();
dailyRequestCount++;
} }
catch (ResponseCodeWrongException e) catch (ResponseCodeWrongException e)
{ {
// tried enough times, so stop now
if (count >= retryTimes)
{
return false;
}
if (e.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED)
{ //token might have expired
if(!getAccessToken()) //token doesn't work anymore and we can't get a new one
{
return false;
}
}
else if (e.getResponseCode() == httpCodeLimitReached)
try
{ {
// request limit is reached, try again later
count++;
count = handleWrongResponseCode(count, e);
} }
else // some other error: try only one other time!
catch (NoAccessException e2)
{ {
count = retryTimes;
}
// Sleep for 5 minutes and try to get the next 15 min request window
try
{
TimeUnit.MINUTES.sleep(5);
return false;
} }
catch (InterruptedException e1)
if (count == -1)
{ {
return false;
} }
} }
@ -635,7 +659,7 @@ public class Main
} }
catch (ParseException e) catch (ParseException e)
{ {
writeError("Athlete " + athleteId + ": Error parsing refresh info.");
writeLog("Athlete " + athleteId + ": Error parsing refresh info.");
} }
return false; return false;
} }
@ -658,7 +682,7 @@ public class Main
athleteId++; athleteId++;
if (!getAccessToken()) if (!getAccessToken())
{ {
writeError("Couldn't get new access token for client " + athleteId);
writeLog("Couldn't get new access token for client " + athleteId);
continue; continue;
} }
@ -680,7 +704,7 @@ public class Main
} }
catch (IOException e) catch (IOException e)
{ {
writeError("Files coulnd't be zipped");
writeLog("Files coulnd't be zipped");
} }
} }
} }
@ -691,7 +715,7 @@ public class Main
} }
catch (IOException e) catch (IOException e)
{ {
writeError("Files coulnd't be zipped");
writeLog("Files coulnd't be zipped");
} }
} }
} }
Loading…
Cancel
Save