Changes between Version 1 and Version 2 of AdvancedApplicationDevelopment
- Timestamp:
- 08/23/26 20:42:56 (4 days ago)
Legend:
- Unmodified
- Added
- Removed
- Modified
-
AdvancedApplicationDevelopment
v1 v2 9 9 === Прием на податоци од агент (`/receive`) === 10 10 11 Најкритичната трансакција во системот се извршува при прием на податоци од агентите преку POST `/receive`. Во рамките на една конекција се извршуваат следните операции:11 Најкритичната трансакција во системот се извршува при прием на податоци од агентите преку POST `/receive`. Во рамките на една конекција (v04) се извршуваат следните операции: 12 12 13 13 * Пронаоѓање или креирање на компјутер во `computers` 14 14 * Ажурирање на `last_seen`, `ip`, `os`, `user`, `sysmon_available` 15 * Внесување на системски метрики во `computer_history` 15 * Внесување на системски метрики во `computer_history` (историја) и освежување на тековниот snapshot во `computer_history_current` 16 16 * Бришење и повторно внесување на тековните процеси во `computer_processes_current` 17 * Условно внесување на историски процеси во `computer_processes_history` ( доколкуе овозможено во `env_settings`)17 * Условно внесување на историски процеси во `computer_processes_history` (ако `save_process_history` е овозможено во `env_settings`) 18 18 * Внесување на Sysmon настани во `sysmon_events` 19 * Внесување на мрежни конекции во `network_connections`19 * Освежување на тековните мрежни конекции во `network_connections_current` и условно во `network_connections_history` (ако `save_network_history` е овозможено) 20 20 21 21 Сите операции се завршуваат со `conn.commit()`. Доколку се случи грешка во кој било чекор, се извршува `conn.rollback()` и ниедна промена не е трајно зачувана: … … 58 58 computer_id = c.lastrowid 59 59 60 # Чекор 2: Системски метрики 60 # Чекор 2: Системски метрики — историја + тековен snapshot [v04] 61 61 c.execute(""" 62 62 INSERT INTO computer_history( 63 computer_id, cpu_usage, ram_usage, disk_usage, 64 network_sent_mb, network_recv_mb, timestamp) 65 VALUES(?, ?, ?, ?, ?, ?, ?) 66 """, (computer_id, float(info.get("cpu_usage") or 0), 67 float(info.get("ram_usage") or 0), float(info.get("disk_usage") or 0), 68 float(info.get("network_sent_mb") or 0), 69 float(info.get("network_recv_mb") or 0), 70 info.get("timestamp") or now_iso)) 71 72 c.execute("DELETE FROM computer_history_current WHERE computer_id=?", (computer_id,)) 73 c.execute(""" 74 INSERT INTO computer_history_current( 63 75 computer_id, cpu_usage, ram_usage, disk_usage, 64 76 network_sent_mb, network_recv_mb, timestamp) … … 109 121 json.dumps(ev, ensure_ascii=False))) 110 122 111 # Чекор 6: Мрежни конекции 123 # Чекор 6: Мрежни конекции — тековен snapshot + условна историја [v04] 124 c.execute("DELETE FROM network_connections_current WHERE computer_id=?", (computer_id,)) 125 net_hist = is_network_history_enabled(tenant_id, env_name) 112 126 for nc in (security_data.get("network_connections") or []): 127 vals = (computer_id, nc.get("pid"), nc.get("local_address"), 128 nc.get("remote_address"), nc.get("status"), 129 nc.get("process_name"), info.get("timestamp") or now_iso) 113 130 c.execute(""" 114 INSERT INTO network_connections (115 computer_id, pid, local_address, 116 remote_address,status, process_name, timestamp)131 INSERT INTO network_connections_current( 132 computer_id, pid, local_address, remote_address, 133 status, process_name, timestamp) 117 134 VALUES(?, ?, ?, ?, ?, ?, ?) 118 """, (computer_id, nc.get("pid"), nc.get("local_address"), 119 nc.get("remote_address"), nc.get("status"), 120 nc.get("process_name"), info.get("timestamp") or now_iso)) 135 """, vals) 136 if net_hist: 137 c.execute(""" 138 INSERT INTO network_connections_history( 139 computer_id, pid, local_address, remote_address, 140 status, process_name, timestamp) 141 VALUES(?, ?, ?, ?, ?, ?, ?) 142 """, vals) 121 143 122 144 # Сите операции успешни — зачувај 123 145 conn.commit() 124 return jsonify({"ok": True, "computer_id": computer_id , ...})146 return jsonify({"ok": True, "computer_id": computer_id}) 125 147 126 148 except Exception as e: … … 137 159 * `conn.rollback()` се повикува во `except` блокот — ниедна табела нема делумни податоци 138 160 * `conn.close()` е во `finally` блокот — конекцијата секогаш се затвора 139 * Условното снимање на процесна историја (`is_process_history_enabled`) е дел од истата трансакција161 * Условното снимање историја (процеси/мрежа) е дел од истата трансакција и се контролира по околина преку знамињата во `env_settings` 140 162 141 163 ---- … … 268 290 === Ажурирање на поставки за околина (`/api/admin/env-settings/<env_name>`) === 269 291 270 Поставките за околина се запишуваат атомарно преку `INSERT OR ... ON CONFLICT DO UPDATE` (upsert), со цел да се избегне race condition при истовремено читање и пишување:292 Поставките за околина се запишуваат атомарно преку upsert (`ON CONFLICT DO UPDATE`), со цел да се избегне race condition. Во v04 се поддржани трите знамиња (`save_process_history`, `save_metrics_history`, `save_network_history`); незададените во барањето ги задржуваат тековните вредности: 271 293 272 294 {{{ … … 275 297 def admin_set_env_settings(env_name): 276 298 tenant_id = request.user["tenant_id"] 277 enabled = 1 if bool(data.get("save_process_history")) else 0299 data = request.get_json(force=True, silent=True) or {} 278 300 279 301 conn = db() 280 302 c = conn.cursor() 303 304 # прочитај ги тековните вредности за да ги задржиш незададените знамиња 281 305 c.execute(""" 282 INSERT INTO env_settings(tenant_id, env_name, save_process_history, created_at, updated_at) 283 VALUES(?, ?, ?, datetime('now'), datetime('now')) 306 SELECT save_process_history, save_metrics_history, save_network_history 307 FROM env_settings WHERE tenant_id=? AND env_name=? LIMIT 1 308 """, (tenant_id, env_name)) 309 cur = c.fetchone() 310 311 def pick(key): 312 if data.get(key) is not None: 313 return 1 if bool(data.get(key)) else 0 314 return int(cur[key]) if cur else 0 315 316 p = pick("save_process_history") 317 m = pick("save_metrics_history") 318 n = pick("save_network_history") 319 320 c.execute(""" 321 INSERT INTO env_settings(tenant_id, env_name, save_process_history, 322 save_metrics_history, save_network_history, 323 created_at, updated_at) 324 VALUES(?, ?, ?, ?, ?, datetime('now'), datetime('now')) 284 325 ON CONFLICT(tenant_id, env_name) DO UPDATE SET 285 326 save_process_history=excluded.save_process_history, 327 save_metrics_history=excluded.save_metrics_history, 328 save_network_history=excluded.save_network_history, 286 329 updated_at=datetime('now') 287 """, (tenant_id, env_name, enabled))330 """, (tenant_id, env_name, p, m, n)) 288 331 conn.commit() 289 332 conn.close() 290 333 291 return jsonify({"ok": True, "env": env_name, "save_process_history": bool(enabled)}) 334 return jsonify({"ok": True, "env": env_name, 335 "save_process_history": bool(p), 336 "save_metrics_history": bool(m), 337 "save_network_history": bool(n)}) 292 338 }}} 293 339 … … 296 342 == Database Connection Pooling == 297 343 298 Во моменталната имплементација системот користи SQLite база на податоци преку `sqlite3` библиотеката. Конекцијата кон базата се воспоставува преку помошната функција `db()`:344 Во моменталната имплементација (прототип) системот користи SQLite база преку `sqlite3` библиотеката. Конекцијата се воспоставува преку помошната функција `db()`: 299 345 300 346 {{{ … … 307 353 }}} 308 354 309 `conn.row_factory = sqlite3.Row` овозможува пристап до колоните по име (на пр. `row["email"]`) наместо по индекс. При секое барање се отвора нова конекција која се затвора по завршување на операцијата— секогаш во `finally` блокот:355 `conn.row_factory = sqlite3.Row` овозможува пристап до колоните по име (на пр. `row["email"]`). При секое барање се отвора нова конекција која се затвора по завршување — секогаш во `finally` блокот: 310 356 311 357 {{{ … … 320 366 }}} 321 367 322 Поради природата на SQLite (file-based база со writer lock), Connection Pooling не е применливо во тековната верзија. 368 Поради природата на SQLite (file-based база со writer lock), Connection Pooling не е применливо во тековната прототип верзија. 369 370 Забелешка: официјалната проектна база (од претходната фаза) е PostgreSQL. Прототипот користи SQLite со истата структура, а миграцијата кон PostgreSQL со pool е опишана подолу. 323 371 324 372 ---- … … 326 374 === Позадинска задача за автоматско чистење (`cleanup_old_data`) === 327 375 328 Системот стартува посебна daemon нишка која на секои 3600 секунди (1 час) автоматски ги брише записите постари од 30 дена . Нишката ја користи истата `db()` функција иработи со своја независна конекција:376 Системот стартува посебна daemon нишка која на секои 3600 секунди (1 час) автоматски ги брише записите постари од 30 дена од историските табели. Нишката работи со своја независна конекција: 329 377 330 378 {{{ … … 342 390 c.execute("DELETE FROM network_connections WHERE timestamp < ?", (cutoff,)) 343 391 c.execute("DELETE FROM computer_processes_history WHERE timestamp < ?", (cutoff,)) 392 # [v04] нова history табела 393 c.execute("DELETE FROM network_connections_history WHERE timestamp < ?", (cutoff,)) 344 394 345 395 conn.commit() … … 355 405 356 406 Нишката е `daemon=True` — автоматски се гасне кога се гасне главниот Flask процес. 357 358 ---- 359 360 === Планирана миграција кон PostgreSQL со Connection Pooling === 361 362 По миграција кон PostgreSQL, `db()` функцијата би се заменила со SQLAlchemy engine со connection pool: 407 (Тековните snapshot табели `*_current` не се чистат бидејќи се препишуваат при секое известување.) 408 409 ---- 410 411 === Миграција кон PostgreSQL со Connection Pooling === 412 413 Официјалната проектна база е веќе PostgreSQL. При поврзување на апликацискиот слој кон неа, `db()` функцијата би се заменила со SQLAlchemy engine со connection pool: 363 414 364 415 {{{ … … 408 459 Предности на оваа миграција: 409 460 * Повторно користење на активни конекции наместо отворање нова при секое барање 410 * Намалување на латенцијата — воспоставувањето н а нова PostgreSQL конекција трае ~50-100ms461 * Намалување на латенцијата — воспоставувањето нова PostgreSQL конекција трае ~50-100ms 411 462 * `pool_pre_ping=True` автоматски ги отстранува прекинатите конекции од pool-от 412 463 * Подобри перформанси при голем број истовремени агенти кои праќаат податоци паралелно
