-
Notifications
You must be signed in to change notification settings - Fork 41
β‘ Bolt: Optimize N+1 query in Grievance Escalation Engine #938
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f3c5265
eed4fea
31df218
71b93c6
5bed1f4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,12 +5,12 @@ | |
|
|
||
| import datetime | ||
| from typing import List, Dict, Any, Optional | ||
| from sqlalchemy.orm import Session | ||
| from sqlalchemy.orm import Session, joinedload | ||
| from sqlalchemy import and_, or_ | ||
| from backend.models import Grievance, Jurisdiction, EscalationAudit, GrievanceStatus, JurisdictionLevel, EscalationReason, SeverityLevel | ||
| from backend.database import SessionLocal | ||
| from backend.routing_service import RoutingService | ||
| from backend.sla_config_service import SLAConfigService | ||
| from models import Grievance, Jurisdiction, EscalationAudit, GrievanceStatus, JurisdictionLevel, EscalationReason, SeverityLevel | ||
| from database import SessionLocal | ||
| from routing_service import RoutingService | ||
| from sla_config_service import SLAConfigService | ||
|
|
||
| class EscalationEngine: | ||
| """ | ||
|
|
@@ -150,7 +150,13 @@ def _get_grievances_for_evaluation(self, db: Session) -> List[Grievance]: | |
| now = datetime.datetime.now(datetime.timezone.utc) | ||
|
|
||
| # Get grievances that are active and past SLA deadline | ||
| return db.query(Grievance).filter( | ||
| # β‘ Bolt Optimization: Use joinedload to eager-load the jurisdiction relationship. | ||
| # This prevents an N+1 query problem during the evaluation loop where each | ||
| # grievance would otherwise trigger a separate query to fetch its jurisdiction. | ||
| # Expected Impact: Reduces database queries from 1+N to 1 per evaluation cycle. | ||
| return db.query(Grievance).options( | ||
| joinedload(Grievance.jurisdiction) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The Consider setting Prompt for AI agents |
||
| ).filter( | ||
|
Comment on lines
+153
to
+159
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π Performance & Scalability | π‘ Minor | β‘ Quick win π§© Analysis chainπ Script executed: #!/bin/bash
rg -n -C3 'SessionLocal|expire_on_commit|\.commit\(\)' backendRepository: RohanExploit/VishwaGuru Length of output: 20207 π Script executed: #!/bin/bash
set -euo pipefail
echo "== backend/database.py =="
cat -n backend/database.py
echo
echo "== backend/escalation_engine.py outline =="
ast-grep outline backend/escalation_engine.py --view compact || true
echo
echo "== backend/escalation_engine.py relevant sections =="
sed -n '1,190p' backend/escalation_engine.py | cat -n
echo
sed -n '190,280p' backend/escalation_engine.py | cat -nRepository: RohanExploit/VishwaGuru Length of output: 13109 π Script executed: #!/bin/bash
set -euo pipefail
echo "== backend/routing_service.py relevant sections =="
sed -n '1,180p' backend/routing_service.py | cat -n
echo
sed -n '250,410p' backend/escalation_engine.py | cat -n
echo
echo "== SQLAlchemy availability and compile output =="
python3 - <<'PY'
import inspect
try:
import sqlalchemy
print("sqlalchemy", sqlalchemy.__version__)
import sqlalchemy.orm
import sqlalchemy.orm.session
print("expire_on_commit default from get_state_manager attr may be", getattr(sqlalchemy.orm.session, "_SESSION_DEFAULTS", {}).get("expire_on_commit", "<not exposed"))
print("SessionLocal defaults:" , hasattr(sqlalchemy.orm.sessionmaker, "Session"))
except Exception as e:
print("SQLAlchemy import failed:", repr(e))
PYRepository: RohanExploit/VishwaGuru Length of output: 9616 π Web query:
π‘ Result: In SQLAlchemy, the default value for the expire_on_commit parameter in sessionmaker is True [1][2][3]. When this setting is enabled (the default), all objects associated with a Session are expired after a transaction is committed [1][4]. This means that the internal contents of the objects are erased, and they will be automatically re-loaded from the database upon their next attribute access to ensure they contain the most recent state [1][5][4]. If you prefer to maintain the state of your objects after a commitβfor instance, to avoid additional SQL queries for refreshing data when working in web request layersβyou can disable this behavior by setting expire_on_commit=False when initializing your sessionmaker [5][4]. Citations:
Keep evaluation objects unexpired through the loop.
π€ Prompt for AI Agents |
||
| and_( | ||
| Grievance.status.in_([GrievanceStatus.OPEN, GrievanceStatus.IN_PROGRESS, GrievanceStatus.ESCALATED]), | ||
| Grievance.sla_deadline < now | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,5 @@ | ||||||||||||
| from sqlalchemy import text | ||||||||||||
| from backend.database import engine | ||||||||||||
| from database import engine | ||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Package-style imports of Prompt for AI agents
Suggested change
|
||||||||||||
| import logging | ||||||||||||
|
|
||||||||||||
| logger = logging.getLogger(__name__) | ||||||||||||
|
|
||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,8 +3,8 @@ | |
| Sets up sample jurisdictions, SLA configurations, and test data. | ||
| """ | ||
|
|
||
| from backend.database import SessionLocal, engine | ||
| from backend.models import Jurisdiction, JurisdictionLevel, SLAConfig, SeverityLevel | ||
| from database import SessionLocal, engine | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The documented package/module entry points now fail immediately because Prompt for AI agents |
||
| from models import Jurisdiction, JurisdictionLevel, SLAConfig, SeverityLevel | ||
| from backend.grievance_service import GrievanceService | ||
| import json | ||
|
|
||
|
|
@@ -13,7 +13,7 @@ def initialize_grievance_system(): | |
| Initialize the grievance system with sample data. | ||
| """ | ||
| # Create tables | ||
| from backend.models import Base | ||
| from models import Base | ||
| Base.metadata.create_all(bind=engine) | ||
|
|
||
| db = SessionLocal() | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P2: Package imports of
backend.escalation_enginenow fail unless the backend directory is separately injected intosys.path, because these bare imports no longer resolvebackend/models.pyand the other backend modules. Keeping thebackend.*imports (or consistently converting the backend to package-relative imports) preserves package-mode loading.Prompt for AI agents