Stage A of review fixes: single read snapshot, redacted /health, batched diff
/addresses reads the cursor and data in one session and one snapshot, /health exposes only time and backup file name of the last restore, get_changes checks presence in batches instead of per value (6.8 s -> 88 ms on a 12k-entry journal). Adds the plan for review fixes 5-10. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
0155fd3f38
commit
d6b69d0842
6 files changed
+103
-33
No files matched your search
+13
-23
@@ -6,7 +6,7 @@ import os
|
||||
import re
|
||||
import secrets
|
||||
import sqlite3
|
||||
from typing import List, Literal, Optional
|
||||
from typing import Literal, Optional
|
||||
|
||||
from apscheduler.triggers.cron import CronTrigger
|
||||
from fastapi import Depends, FastAPI, Header, HTTPException, Path, Query, Response
|
||||
@@ -121,16 +121,6 @@ def ensure_data_ready(conn, kinds):
|
||||
detail="The database was recreated after corruption; data is being collected again.")
|
||||
|
||||
|
||||
def get_cidrs() -> List[str]:
|
||||
with db.session() as conn:
|
||||
return db.get_values(conn, "asn")
|
||||
|
||||
|
||||
def get_fqdn_ips() -> List[str]:
|
||||
with db.session() as conn:
|
||||
return db.get_values(conn, "fqdn")
|
||||
|
||||
|
||||
@app.get("/addresses", response_model=None, responses={
|
||||
200: {"description": "JSON list for format=json, text/plain configuration script for other formats",
|
||||
"content": {"application/json": {"schema": {"type": "array", "items": {"type": "string"}}},
|
||||
@@ -144,17 +134,14 @@ def get_addresses(
|
||||
description="List/set name used in generated configuration"),
|
||||
response: Response = None,
|
||||
):
|
||||
# Курсор читаем до данных: изменения между чтением курсора и данных повторятся в diff, что безвредно
|
||||
with db.session() as conn:
|
||||
ensure_data_ready(conn, kinds_of(type))
|
||||
headers = {"X-Changes-Cursor": str(db.journal_head(conn))}
|
||||
# Одна сессия и один снимок: курсор в заголовке точно соответствует выданным данным
|
||||
kinds = kinds_of(type)
|
||||
results = set()
|
||||
|
||||
if type in [AddressType.cidr, AddressType.all_types]:
|
||||
results.update(get_cidrs())
|
||||
|
||||
if type in [AddressType.fqdn, AddressType.all_types]:
|
||||
results.update(get_fqdn_ips())
|
||||
with db.session() as conn, db.read_transaction(conn):
|
||||
ensure_data_ready(conn, kinds)
|
||||
headers = {"X-Changes-Cursor": str(db.journal_head(conn))}
|
||||
for kind in kinds:
|
||||
results.update(db.get_values(conn, kind))
|
||||
|
||||
output = formatters.build_output(results, format.value, ip_version.value, aggregate, name)
|
||||
if format == OutputFormat.json:
|
||||
@@ -233,9 +220,12 @@ def health():
|
||||
pending = db.recreated_pending(conn, ("asn", "fqdn"))
|
||||
|
||||
try:
|
||||
last_restore = load_json(cc.RESTORE_FILE, None) # след автовосстановления базы из копии
|
||||
restore = load_json(cc.RESTORE_FILE, None) # след автовосстановления базы из копии
|
||||
except StorageError:
|
||||
last_restore = None
|
||||
restore = None
|
||||
# Наружу - только время и имя файла копии; каталоги и текст ошибки остаются в last_restore.json
|
||||
last_restore = ({"at": restore.get("at"), "backup": os.path.basename(str(restore.get("backup") or ""))}
|
||||
if isinstance(restore, dict) else None)
|
||||
|
||||
try:
|
||||
recreated = load_json(cc.RECREATED_FILE, None) # база пересоздана после порчи без копий
|
||||
|
||||
Reference in new issue
Block a user