-
Notifications
You must be signed in to change notification settings - Fork 988
/
Copy pathkill_idle_backend_conns.py
executable file
·133 lines (107 loc) · 4.61 KB
/
kill_idle_backend_conns.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python
"""
Kills all ProxySQL idle backend connections from a particular instance.
- Optional params (with default values): '{ "admin_host": "127.0.0.1", "admin_port": 6032, "admin_user": "radmin", "admin_pass": "radmin" }'
- Mandatory params: '{ "timeout": N }'
"""
import json
import jsonschema
import sys
import time
import pymysql.cursors
schema = {
"type": "object",
"properties": {
"admin_host": {"type": "string"},
"admin_port": {"type": "number"},
"admin_user": {"type": "string"},
"admin_pass": {"type": "string"},
"timeout": {"type": "number"}
},
"required": ["timeout"]
}
def validate_params():
"""Validates the JSON encoded received parameters."""
res = {}
if len(sys.argv) != 2:
res = {"err_code": 1, "res": "Invalid number of parameters"}
else:
try:
j_arg = json.loads(sys.argv[1])
jsonschema.validate(instance=j_arg, schema=schema)
res = {"err_code": 0, "res": ""}
except jsonschema.exceptions.ValidationError as err:
res = {"err_code": 1, "res": "Params validation failed: `" + str(err) + "`"}
except json.decoder.JSONDecodeError as err:
res = {"err_code": 1, "res": "Invalid supplied JSON: `" + str(err) + "`"}
return res
if __name__ == "__main__":
p_res = validate_params()
if p_res["err_code"] != 0:
print(json.dumps(p_res))
exit(0)
params = json.loads(sys.argv[1])
if params.get('admin_host') is None:
params['admin_host'] = "127.0.0.1"
if params.get('admin_port') is None:
params['admin_port'] = 6032
if params.get('admin_user') is None:
params['admin_user'] = "radmin"
if params.get('admin_pass') is None:
params['admin_pass'] = "radmin"
try:
proxy_admin_conn = pymysql.connect(
host=params['admin_host'],
user=params['admin_user'],
password=params['admin_pass'],
port=int(params['admin_port']),
cursorclass=pymysql.cursors.DictCursor,
defer_connect=True
)
proxy_admin_conn.client_flag |= pymysql.constants.CLIENT.MULTI_STATEMENTS
proxy_admin_conn.connect()
proxy_admin_conn.autocommit(True)
except Exception as err:
print(json.dumps({"err_code": 1, "res": "Connection attempt failed: `" + str(err) + "`"}))
exit(0)
with proxy_admin_conn:
with proxy_admin_conn.cursor() as cursor:
# Backup the current 'free_connections_pct'
prev_free_conns_pct = ""
s_var_query = "SELECT variable_value FROM global_variables WHERE variable_name='mysql-free_connections_pct'"
cursor.execute(s_var_query)
my_varval = cursor.fetchall()
if len(my_varval) != 1:
print(json.dumps({"err_code": 1, "res": "Invalid resulset received for query `" + s_var_query + "`"}))
exit(0)
else:
prev_free_conns_pct = my_varval[0]['variable_value']
# Set the 'free_connections_pct' to '0', to performa purge of the idle backend connections
update_query = "UPDATE global_variables SET variable_value=%s WHERE variable_name='mysql-free_connections_pct'"
cursor.execute(update_query, "0")
cursor.execute("LOAD MYSQL VARIABLES TO RUNTIME")
# Loop with a timeout until ProxySQL has cleaned all the backend connections
free_conns = -1
waited = 0
timeout = int(params['timeout'])
while free_conns != 0 and waited < timeout:
s_free_query = "SELECT SUM(ConnFree) FROM stats.stats_mysql_connection_pool"
cursor.execute(s_free_query)
my_rows = cursor.fetchall()
if len(my_rows) != 1:
print(json.dumps({"err_code": 1, "res": "Invalid resulset received for query `" + s_free_query + "`"}))
exit(0)
else:
conn_free_field = my_rows[0]['SUM(ConnFree)']
if conn_free_field is not None:
free_conns = int(conn_free_field)
else:
free_conns = 0
time.sleep(1)
# Recover previous 'mysql-free_connections_pct'
cursor.execute(update_query, prev_free_conns_pct)
cursor.execute("LOAD MYSQL VARIABLES TO RUNTIME")
if waited >= timeout:
print(json.dumps({"err_code": 1, "res": "Operation timedout"}))
else:
print(json.dumps({"err_code": 0, "res": "Success!"}))