Skip to content

Commit fbd29f2

Browse files
committed
fix(node): force reconnect for invalid nodes
1 parent e4a57a6 commit fbd29f2

File tree

7 files changed

+38
-29
lines changed

7 files changed

+38
-29
lines changed

app/jobs/node_checker.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,6 @@ async def process_node_health_check(db_node: Node, node: PasarGuardNode):
8585
if node is None:
8686
return
8787

88-
if node.requires_hard_reset():
89-
async with GetDB() as db:
90-
await node_operator.connect_single_node(db, db_node.id)
91-
return
92-
9388
try:
9489
health = await asyncio.wait_for(verify_node_backend_health(node, db_node.name), timeout=15)
9590
except asyncio.TimeoutError:
@@ -101,6 +96,11 @@ async def process_node_health_check(db_node: Node, node: PasarGuardNode):
10196
async with GetDB() as db:
10297
await NodeOperation._update_single_node_status(db, db_node.id, NodeStatus.error, message=e.detail)
10398

99+
if node.requires_hard_reset() or health is None or health in (Health.NOT_CONNECTED, Health.INVALID):
100+
async with GetDB() as db:
101+
await node_operator.connect_single_node(db, db_node.id)
102+
return
103+
104104
# Skip nodes that are already healthy and connected
105105
if health == Health.HEALTHY and db_node.status == NodeStatus.connected:
106106
return

app/operation/node.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,6 @@ async def connect_node(db_node: Node, users: list) -> dict | None:
157157
users=users,
158158
keep_alive=db_node.keep_alive,
159159
exclude_inbounds=core.exclude_inbound_tags,
160-
timeout=10,
161160
)
162161
logger.info(f'Connected to "{db_node.name}" node v{info.node_version}, xray run on v{info.core_version}')
163162

@@ -296,6 +295,9 @@ async def connect_nodes_bulk(
296295
users = await core_users(db=db)
297296

298297
async def connect_single(node: Node) -> dict | None:
298+
if node is None or node.status in (NodeStatus.disabled, NodeStatus.limited):
299+
return
300+
299301
try:
300302
await node_manager.update_node(node)
301303
except NodeAPIError as e:
@@ -362,7 +364,7 @@ async def connect_single_node(self, db: AsyncSession, node_id: int) -> None:
362364
node_id (int): ID of the node to connect.
363365
"""
364366
db_node = await get_node_by_id(db, node_id)
365-
if db_node is None:
367+
if db_node is None or db_node.status in (NodeStatus.disabled, NodeStatus.limited):
366368
return
367369

368370
# Get core users once

tests/api/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def create_core(
5959

6060
def delete_core(access_token: str, core_id: int) -> None:
6161
response = client.delete(f"/api/core/{core_id}", headers=auth_headers(access_token))
62-
62+
6363
assert response.status_code in (status.HTTP_204_NO_CONTENT, status.HTTP_403_FORBIDDEN)
6464

6565

tests/api/test_bulk.py

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,7 @@ def test_add_groups_to_users(access_token):
3131
"""Test bulk adding groups to users."""
3232

3333
core, groups = setup_groups(access_token, 2)
34-
users = [
35-
create_user(access_token, payload={"username": unique_name("bulk_user")})
36-
for _ in range(2)
37-
]
34+
users = [create_user(access_token, payload={"username": unique_name("bulk_user")}) for _ in range(2)]
3835
group_ids = [group["id"] for group in groups]
3936
try:
4037
response = client.post(
@@ -54,10 +51,7 @@ def test_add_groups_to_users(access_token):
5451
def test_remove_groups_from_users(access_token):
5552
"""Test bulk removing groups from users."""
5653
core, groups = setup_groups(access_token, 2)
57-
users = [
58-
create_user(access_token, payload={"username": unique_name("bulk_user_remove")})
59-
for _ in range(2)
60-
]
54+
users = [create_user(access_token, payload={"username": unique_name("bulk_user_remove")}) for _ in range(2)]
6155
group_ids = [group["id"] for group in groups]
6256
try:
6357
client.post(
@@ -83,8 +77,12 @@ def test_update_users_datalimit(access_token):
8377
"""Test bulk updating user data limits."""
8478
core, groups = setup_groups(access_token, 1)
8579
users = [
86-
create_user(access_token, group_ids=[groups[0]["id"]], payload={"username": unique_name("user7"), "data_limit": 100}),
87-
create_user(access_token, group_ids=[groups[0]["id"]], payload={"username": unique_name("user8"), "data_limit": 200}),
80+
create_user(
81+
access_token, group_ids=[groups[0]["id"]], payload={"username": unique_name("user7"), "data_limit": 100}
82+
),
83+
create_user(
84+
access_token, group_ids=[groups[0]["id"]], payload={"username": unique_name("user8"), "data_limit": 200}
85+
),
8886
]
8987
user_ids = [user["id"] for user in users]
9088
try:
@@ -133,9 +131,19 @@ def test_update_users_expire(access_token):
133131

134132
assert response.status_code == status.HTTP_200_OK
135133
response = client.get("/api/users", headers={"Authorization": f"Bearer {access_token}"})
136-
listed = {u["username"]: u for u in response.json()["users"] if u["username"] in {users[0]["username"], users[1]["username"]}}
137-
assert dt.fromisoformat(listed[users[0]["username"]]["expire"]).replace(tzinfo=None).strftime("%Y-%m-%dT%H:%M:%S") == "2025-01-01T01:00:00"
138-
assert dt.fromisoformat(listed[users[1]["username"]]["expire"]).replace(tzinfo=None).strftime("%Y-%m-%dT%H:%M:%S") == "2026-01-01T01:00:00"
134+
listed = {
135+
u["username"]: u
136+
for u in response.json()["users"]
137+
if u["username"] in {users[0]["username"], users[1]["username"]}
138+
}
139+
assert (
140+
dt.fromisoformat(listed[users[0]["username"]]["expire"]).replace(tzinfo=None).strftime("%Y-%m-%dT%H:%M:%S")
141+
== "2025-01-01T01:00:00"
142+
)
143+
assert (
144+
dt.fromisoformat(listed[users[1]["username"]]["expire"]).replace(tzinfo=None).strftime("%Y-%m-%dT%H:%M:%S")
145+
== "2026-01-01T01:00:00"
146+
)
139147
finally:
140148
cleanup(access_token, core, groups, users)
141149

@@ -156,7 +164,11 @@ def test_update_users_proxy_settings(access_token):
156164

157165
assert response.status_code == status.HTTP_200_OK
158166
response = client.get("/api/users", headers={"Authorization": f"Bearer {access_token}"})
159-
listed = {u["username"]: u for u in response.json()["users"] if u["username"] in {users[0]["username"], users[1]["username"]}}
167+
listed = {
168+
u["username"]: u
169+
for u in response.json()["users"]
170+
if u["username"] in {users[0]["username"], users[1]["username"]}
171+
}
160172
assert listed[users[0]["username"]]["proxy_settings"]["vless"]["flow"] == "xtls-rprx-vision"
161173
assert listed[users[1]["username"]]["proxy_settings"]["vless"]["flow"] == "xtls-rprx-vision"
162174
finally:

tests/api/test_core.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
from tests.api.sample_data import XRAY_CONFIG as xray_config
66

77

8-
98
def test_core_create(access_token):
109
"""Test that the core create route is accessible."""
1110

tests/api/test_group.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,7 @@ def test_group_create(access_token):
1717
for _ in range(3):
1818
k = min(3, len(inbounds))
1919
selected_inbounds = random.sample(inbounds, k=k) if k else inbounds
20-
response = create_group(
21-
access_token, name=unique_name("testgroup"), inbound_tags=selected_inbounds
22-
)
20+
response = create_group(access_token, name=unique_name("testgroup"), inbound_tags=selected_inbounds)
2321
created_groups.append(response["id"])
2422
assert response["name"].startswith("testgroup")
2523
assert set(response["inbound_tags"]) == set(selected_inbounds)

tests/test_record_usages.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -269,9 +269,7 @@ async def fake_get_outbounds_stats(node: DummyNode):
269269
assert node_totals[node_one_id][0] > node_totals[node_two_id][0]
270270
assert node_totals[node_two_id][1] > 0
271271

272-
node_usage_rows = await session.execute(
273-
select(NodeUsage.node_id, NodeUsage.uplink, NodeUsage.downlink)
274-
)
272+
node_usage_rows = await session.execute(select(NodeUsage.node_id, NodeUsage.uplink, NodeUsage.downlink))
275273
node_usage_totals = {row.node_id: (row.uplink, row.downlink) for row in node_usage_rows.all()}
276274
assert set(node_usage_totals.keys()) == {node_one_id, node_two_id}
277275

0 commit comments

Comments
 (0)