fix(readiness): allow measured native probe execution time
This commit is contained in:
1 parent
31938681dc
commit
e4308a2dd4
5 files changed
+18
-8
No files matched your search
@@ -21,7 +21,7 @@ Run `python3 adapter.py --config /private/adapter.json` inside the application f
|
||||
|
||||
Only GET at the exact canonical path, with one matching `X-APEX-Ready-Token` header, can execute the fixed command. Missing/wrong/duplicate credentials return403; other paths404; supported non-GET methods405. Ready returns204; probe failure, timeout or concurrency exhaustion returns503. These responses have empty bodies and `Cache-Control: no-store`. The adapter does not log requests, tokens or command output, cache success, or accept a client-supplied command. Each connection closes after its response.
|
||||
|
||||
Probe timeout is bounded to1.5seconds so an origin can answer within the Worker's two-second deadline. A timeout kills the probe's process group. Probe slots and request threads are bounded; slow socket operations time out after two seconds. Operators must account for proxy overhead and actual probe execution time. Probe programs must not detach into a new session or launch background jobs.
|
||||
Probe timeout defaults to1.5seconds and can be configured up to3seconds. With a3-second probe, allow4seconds at the readiness proxy and5seconds at the Worker. A timeout kills the probe's process group. Probe slots and request threads are bounded; slow socket operations time out after two seconds. Operators must account for proxy overhead and actual probe execution time. Probe programs must not detach into a new session or launch background jobs.
|
||||
|
||||
Optional `single_flight: true` lets overlapping authenticated requests share one running fixed-command probe. It accepts only a JSON boolean and defaults to false. Waiters use that probe's remaining monotonic deadline; they never queue another probe for the same request. The existing connection limit (`slots * 2 + 4`) also bounds waiting requests. Timeout or shutdown returns unavailable and terminates the probe group. Completed results are not cached: each subsequent request starts a fresh probe, with no success TTL or failure cache. Coalescing reduces concurrent work but does not make a slow individual probe meet its deadline.
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ class ReadinessServer(http.server.ThreadingHTTPServer):
|
||||
raise ValueError('A canonical absolute readiness path is required')
|
||||
if not isinstance(command, list) or not command or not all(isinstance(arg, str) and '\0' not in arg for arg in command) or not os.path.isabs(command[0]):
|
||||
raise ValueError('A fixed absolute executable and argv are required')
|
||||
if isinstance(timeout, bool) or not 0 < timeout <= 1.5 or isinstance(slots, bool) or not isinstance(slots, int) or not 1 <= slots <= 16:
|
||||
if isinstance(timeout, bool) or not 0 < timeout <= 3 or isinstance(slots, bool) or not isinstance(slots, int) or not 1 <= slots <= 16:
|
||||
raise ValueError('Invalid probe bounds')
|
||||
if not isinstance(single_flight, bool):
|
||||
raise ValueError('single_flight must be a boolean')
|
||||
|
||||
@@ -17,6 +17,13 @@ class AdapterTests(unittest.TestCase):
|
||||
c.endheaders();r=c.getresponse();out=(r.status,r.getheader('Cache-Control'),r.read());c.close();return out
|
||||
def test_authenticated_success_runs_fixed_probe(self):
|
||||
self.assertEqual(self.request(self.server()),(204,'no-store',b''));self.assertTrue(self.marker.exists())
|
||||
def test_configured_three_seconds_allows_a_probe_longer_than_default(self):
|
||||
code=f"import time;from pathlib import Path;time.sleep(1.6);Path({str(self.marker)!r}).write_text('completed')"
|
||||
s=self.server(code,timeout=3,single_flight=True)
|
||||
self.assertEqual(self.request(s),(204,'no-store',b''));self.assertEqual(self.marker.read_text(),'completed')
|
||||
def test_timeout_over_three_seconds_is_rejected_before_probe(self):
|
||||
with self.assertRaises(ValueError):self.server(timeout=3.01)
|
||||
self.assertFalse(self.marker.exists())
|
||||
def test_absent_wrong_and_duplicate_tokens_never_probe(self):
|
||||
s=self.server()
|
||||
for token,duplicate in [(None,False),('bad',False),('private-test-token',True)]:self.assertEqual(self.request(s,token=token,extra_token=duplicate)[0],403)
|
||||
|
||||
Reference in new issue
Block a user