bharatgraph / fix_stats_lock.py
abinazebinoy's picture
fix(ascii): replace all non-ASCII chars in Python source files
fa87992
Raw
History Blame Contribute Delete
3.39 kB
# fix_stats_lock.py -- fixes BACKEND-2: add threading lock for stats cache
import re
with open('api/main.py', 'r', encoding='utf-8') as f:
content = f.read()
# First: check what actually exists in the file around stats cache
idx = content.find('_stats_cache')
if idx == -1:
print('ERROR: _stats_cache not found in main.py at all')
exit()
# Show context
print('Current stats cache area:')
print(repr(content[idx-10:idx+200]))
print()
# Add threading import + lock after _stats_cache = None line
# Find the module-level _stats_cache declaration
import_added = False
if '_stats_lock' not in content:
# Add threading lock after _STATS_TTL line
old_ttl = '_STATS_TTL = 60.0'
if old_ttl in content:
content = content.replace(
old_ttl,
old_ttl + '\nimport threading as _th\n_stats_lock = _th.Lock()'
)
import_added = True
print('OK: _stats_lock added after _STATS_TTL')
else:
# Try alternate TTL variable name
for candidate in ['_STATS_TTL = 60.0', '_STATS_TTL=60.0']:
if candidate in content:
content = content.replace(
candidate,
candidate + '\nimport threading as _th\n_stats_lock = _th.Lock()'
)
import_added = True
print(f'OK: lock added after {candidate}')
break
if not import_added:
print('WARNING: could not find _STATS_TTL -- adding lock near _stats_cache')
content = content.replace(
'_stats_cache = None',
'_stats_cache = None\nimport threading as _th\n_stats_lock = _th.Lock()',
1
)
import_added = True
# Add double-check pattern inside get_stats
# Find the early return and add lock before the Neo4j call
old_early_return = ' if _stats_cache is not None and'
if old_early_return in content:
# Find the full early-return block
start = content.find(old_early_return)
# Find end of that if block (the return statement)
end = content.find('\n', content.find('return _stats_cache', start)) + 1
early_block = content[start:end]
print('Found early return block:')
print(repr(early_block))
# After the early return, add lock + double-check
old_driver_line = ' driver = get_driver()'
if old_driver_line in content:
content = content.replace(
old_driver_line,
' # BACKEND-2 FIX: lock prevents two concurrent requests both\n'
' # seeing _stats_cache is None and both running the full graph scan\n'
' with _stats_lock:\n'
' import time as _tc\n'
' if _stats_cache is not None and (_tc.monotonic() - _stats_cached_at) < _STATS_TTL:\n'
' return _stats_cache\n'
' driver = get_driver()',
1
)
print('OK: double-check lock added before get_driver()')
else:
print('WARNING: "driver = get_driver()" not found in get_stats')
else:
print('WARNING: early return not found')
with open('api/main.py', 'w', encoding='utf-8') as f:
f.write(content)
# Verify syntax
import ast
try:
ast.parse(content)
print('SYNTAX OK')
except SyntaxError as e:
print(f'SYNTAX ERROR at line {e.lineno}: {e.msg}')