Skip to content

Commit 1406c8f

Browse files
fix(jobs): fix: garbage collector error
1 parent 00fb6d9 commit 1406c8f

File tree

2 files changed

+21
-25
lines changed

2 files changed

+21
-25
lines changed

app/jobs/record_usages.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
import asyncio
22
import random
33
from collections import defaultdict
4-
from datetime import datetime as dt, timezone as tz, timedelta as td
4+
from datetime import datetime as dt, timedelta as td, timezone as tz
55
from operator import attrgetter
66

7-
from PasarGuardNodeBridge import PasarGuardNode, NodeAPIError
7+
from PasarGuardNodeBridge import NodeAPIError, PasarGuardNode
88
from PasarGuardNodeBridge.common.service_pb2 import StatType
99
from sqlalchemy import and_, bindparam, insert, select, update
10+
from sqlalchemy.dialects.mysql import insert as mysql_insert
11+
from sqlalchemy.dialects.postgresql import insert as pg_insert
1012
from sqlalchemy.exc import DatabaseError, OperationalError
1113
from sqlalchemy.sql.expression import Insert
12-
from sqlalchemy.dialects.postgresql import insert as pg_insert
13-
from sqlalchemy.dialects.mysql import insert as mysql_insert
1414

1515
from app import scheduler
1616
from app.db import GetDB
17+
from app.db.base import engine
1718
from app.db.models import Admin, Node, NodeUsage, NodeUserUsage, System, User
1819
from app.node import node_manager as node_manager
1920
from app.utils.logger import get_logger
@@ -195,22 +196,20 @@ async def safe_execute(stmt, params=None, max_retries: int = 5):
195196
params (list[dict], optional): Parameters for the statement
196197
max_retries (int, optional): Maximum number of retry attempts (default: 5)
197198
"""
199+
statement = stmt
200+
201+
if await get_dialect() == "mysql" and isinstance(stmt, Insert):
202+
# MySQL-specific IGNORE prefix - but skip if using ON DUPLICATE KEY UPDATE
203+
if not hasattr(stmt, "_post_values_clause") or stmt._post_values_clause is None:
204+
statement = stmt.prefix_with("IGNORE")
198205
for attempt in range(max_retries):
199206
try:
200-
# Create fresh session for each attempt to release any locks from previous attempts
201-
async with GetDB() as db:
202-
dialect = db.bind.dialect.name
203-
204-
# MySQL-specific IGNORE prefix - but skip if using ON DUPLICATE KEY UPDATE
205-
if dialect == "mysql" and isinstance(stmt, Insert):
206-
# Check if statement already has ON DUPLICATE KEY UPDATE
207-
if not hasattr(stmt, "_post_values_clause") or stmt._post_values_clause is None:
208-
stmt = stmt.prefix_with("IGNORE")
209-
210-
# Use raw connection to avoid ORM bulk update requirements
211-
await (await db.connection()).execute(stmt, params)
212-
await db.commit()
213-
return # Success - exit function
207+
# engine.begin() ensures commit/rollback + connection return on exit
208+
async with engine.begin() as conn:
209+
if params is None:
210+
await conn.execute(statement)
211+
else:
212+
await conn.execute(statement, params)
214213

215214
except (OperationalError, DatabaseError) as err:
216215
# Session auto-closed by context manager, locks released

tests/test_record_usages.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,10 @@ async def fake_get_users_stats(node: DummyNode):
5454

5555
assert safe_execute_mock.await_count == 2
5656
user_call = safe_execute_mock.await_args_list[0]
57-
assert user_call.args[1] == [
58-
{"pk_uid": 1, "value": 275},
59-
{"pk_uid": 2, "value": 100},
60-
]
57+
assert user_call.args[1] == expected_users_usage
6158

6259
admin_call = safe_execute_mock.await_args_list[1]
63-
assert admin_call.args[1] == [{"pk_admin_id": 99, "value": 555}]
60+
assert admin_call.args[1] == [{"admin_id": 99, "value": 555}]
6461

6562
assert record_user_stats_mock.await_count == 2
6663
expected_record_calls = [
@@ -123,8 +120,8 @@ async def fake_get_outbounds_stats(node: DummyNode):
123120
assert safe_execute_mock.await_count == 2
124121
node_call = safe_execute_mock.await_args_list[0]
125122
assert node_call.args[1] == [
126-
{"pk_id": 1, "up": 10, "down": 7},
127-
{"pk_id": 2, "up": 1, "down": 1},
123+
{"node_id": 1, "up": 10, "down": 7},
124+
{"node_id": 2, "up": 1, "down": 1},
128125
]
129126

130127
system_call = safe_execute_mock.await_args_list[1]

0 commit comments

Comments
 (0)