|
|
@@ -77,18 +77,19 @@ def http(method, url, data=None, headers=None, timeout=30):
|
|
|
request.add_header("Content-Type", "application/x-www-form-urlencoded")
|
|
|
for key, value in (headers or {}).items():
|
|
|
request.add_header(key, value)
|
|
|
- # One retry on a dropped connection: the freshly started app can
|
|
|
- # close a very early keep-alive connection once while warming up.
|
|
|
- for attempt in range(2):
|
|
|
+ # Retry dropped/refused connections: the freshly started app can
|
|
|
+ # close a very early keep-alive connection once while warming up,
|
|
|
+ # and its first seconds can wobble under load.
|
|
|
+ for attempt in range(3):
|
|
|
try:
|
|
|
with urllib.request.urlopen(request, timeout=timeout) as response:
|
|
|
return response.status, response.read().decode()
|
|
|
except urllib.error.HTTPError as error:
|
|
|
return error.code, error.read().decode()
|
|
|
except (urllib.error.URLError, OSError):
|
|
|
- if attempt > 0:
|
|
|
+ if attempt >= 2:
|
|
|
raise
|
|
|
- time.sleep(0.5)
|
|
|
+ time.sleep(0.75)
|
|
|
|
|
|
|
|
|
def directives(uri, auth=None):
|
|
|
@@ -333,8 +334,14 @@ def start_app():
|
|
|
log = open(os.path.join(WORK, "app.log"), "w")
|
|
|
process = subprocess.Popen([APP, str(APP_PORT)], cwd=WORK, env=env,
|
|
|
stdout=log, stderr=subprocess.STDOUT)
|
|
|
- if wait_for(lambda: app_ready() or False, timeout=30, what="app ready") is None:
|
|
|
+ outcome = wait_for(lambda: (app_ready() and "ready")
|
|
|
+ or (process.poll() is not None and "app-exited-%d" % process.poll())
|
|
|
+ or False, timeout=30, what="app ready")
|
|
|
+ if outcome is None:
|
|
|
raise SystemExit("app did not come up; see %s/app.log" % WORK)
|
|
|
+ if str(outcome).startswith("app-exited-"):
|
|
|
+ raise SystemExit("app exited during startup (%s); see %s/app.log"
|
|
|
+ % outcome, WORK)
|
|
|
return process
|
|
|
|
|
|
|