Changes for Java 8 and the Buildservers

We properly close the HttpURLConnection between App Engine (the App
Inventor server) and the buildserver infrastructure. If we don’t App
Engine sends RST packets which causes issues for some buildserver
infrastructures.

Also limit project size to 10MB up-front (rather then after an
IOException is thrown). Add reporting to the buildserver status page to
report the number of Java threads.

Change-Id: I934df537dfe9419f5f8effafe80f0a2460091cdd
parent c1e9dc7e
...@@ -677,6 +677,25 @@ public final class YoungAndroidProjectService extends CommonProjectService { ...@@ -677,6 +677,25 @@ public final class YoungAndroidProjectService extends CommonProjectService {
zipFile = fileExporter.exportProjectSourceZip(userId, projectId, false, zipFile = fileExporter.exportProjectSourceZip(userId, projectId, false,
/* includeAndroidKeystore */ true, /* includeAndroidKeystore */ true,
projectName + ".aia", true, false, true, false); projectName + ".aia", true, false, true, false);
// The code below tests the size of the compressed project before
// we send it off to the buildserver. When using URLFetch we know that
// this size is limited to 10MB based on Google's documentation.
// It isn't clear if this is also enforced in the Java 8 environment
// when not using URLFetch. However we are being conservative for now.
// Keep in mind that large projects can lead to large APK files which
// may not be loadable into many memory restricted devices, so we
// may not want to encourage large projects...
if (zipFile.getContent().length > 10*1024*1024) { // 10 Megabyte size limit...
int zipFileLength = zipFile.getContent().length;
String lengthMbs = format((zipFileLength * 1.0)/(1024*1024));
RuntimeException exception = new RuntimeException(
"Sorry, can't package projects larger than 10Mb."
+ " Yours is " + lengthMbs + "MB.");
CrashReport.createAndLogError(LOG, null,
buildErrorMsg("RuntimeException", buildServerUrl, userId, projectId),
exception);
return new RpcResult(false, "", exception.getMessage());
}
bufferedOutputStream.write(zipFile.getContent()); bufferedOutputStream.write(zipFile.getContent());
bufferedOutputStream.flush(); bufferedOutputStream.flush();
bufferedOutputStream.close(); bufferedOutputStream.close();
...@@ -715,6 +734,16 @@ public final class YoungAndroidProjectService extends CommonProjectService { ...@@ -715,6 +734,16 @@ public final class YoungAndroidProjectService extends CommonProjectService {
} }
return new RpcResult(responseCode, "", StringUtils.escape(error)); return new RpcResult(responseCode, "", StringUtils.escape(error));
} else {
// We get here if all went well and we sent the job to the
// buildserver. Below we read the response, but throw it away.
// We don't really care what was said. But we need to empty out
// the TCP Stream or App Engine will abort the connection by
// sending a RST packet instead of re-using it or closing it
// cleanly (by sending a FIN packet). Aborting connections can
// have a negative effect on some buildserver infrastructures,
// particularly those based on docker swarm (as of 2018).
readContent(connection.getInputStream());
} }
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
CrashReport.createAndLogError(LOG, null, CrashReport.createAndLogError(LOG, null,
......
...@@ -192,6 +192,10 @@ ...@@ -192,6 +192,10 @@
POSTs work with URLFetch around 09/20/2018 --> POSTs work with URLFetch around 09/20/2018 -->
<property name="appengine.api.urlfetch.defaultDeadline" value="40"/> <property name="appengine.api.urlfetch.defaultDeadline" value="40"/>
<!-- So the calls to the buildserver can re-use connections -->
<property name="http.keepAlive" value="true" />
<property name="http.maxConnections" value="5" />
</system-properties> </system-properties>
<!-- Enable concurrency in the app engine server --> <!-- Enable concurrency in the app engine server -->
......
...@@ -274,6 +274,9 @@ public class BuildServer { ...@@ -274,6 +274,9 @@ public class BuildServer {
variables.put("num-processors", osBean.getAvailableProcessors() + ""); variables.put("num-processors", osBean.getAvailableProcessors() + "");
variables.put("load-average-past-1-min", osBean.getSystemLoadAverage() + ""); variables.put("load-average-past-1-min", osBean.getSystemLoadAverage() + "");
// Threads
variables.put("num-java-threads", ManagementFactory.getThreadMXBean().getThreadCount() + "");
// Memory // Memory
Runtime runtime = Runtime.getRuntime(); Runtime runtime = Runtime.getRuntime();
MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment