Exercise 3: Reproducing the Stale-Cache Finding Live — Possible Solution ==================================================================== THE SETUP ------------------------------ # templates/greeting.html on disk, before the server starts: #
Hello, {{ name }}! (v1)
templates = TemplateEngine('templates') def app(environ, start_response): body = templates.render('greeting.html', name='Ada').encode('utf-8') start_response('200 OK', [('Content-type', 'text/html'), ('Content-Length', str(len(body)))]) return [body] server = make_server('127.0.0.1', 8851, app) # ... served via serve_forever() on a background thread ... VERIFIED, REAL RESULT ------------------------------ first_response = get('/') #Hello, Ada! (v1)
# the real file on disk is edited WHILE the server keeps running: # templates/greeting.html now reads # "Hi there, {{ name }}! (v2, updated on disk)
" second_response = get('/') #Hello, Ada! (v1)
-- unchanged Both real HTTP responses, taken from the same live server process before and after the on-disk edit, are byte-for-byte identical. WHY get_template()'S OWN CACHING CAUSES THIS ------------------------------ get_template('greeting.html') only calls _resolve_source() (which reads the real file) the first time that name is ever requested; every call after that returns self._cache['greeting.html'] directly, a plain Python list of already-built node objects sitting in memory. Nothing about the second real HTTP request ever triggers a fresh disk read - the cache dict has no expiry, no timestamp check, and no way to know the file underneath its own key has changed at all. compile_template() itself is not the problem: if it were called again on the real, updated file content, it would compile the new (v2) source correctly. It's simply never called again, because get_template() short-circuits on the cache hit before _resolve_source() (and therefore compile_template()) ever runs a second time. WHY THIS WORKS AS AN ANSWER ------------------------------ It reproduces the exact real behavior against a genuinely running server rather than describing it, and correctly locates the cause in get_template()'s own "if template_name not in self._cache" check - the one line standing between every later request and a fresh read of the real file.