10637.3.1
by Guilherme Salgado
Use the default python version instead of a hard-coded version |
1 |
#!/usr/bin/python
|
8687.15.4
by Karl Fogel
Add the copyright header block to more files; tweak format in a few files. |
2 |
#
|
3 |
# Copyright 2009 Canonical Ltd. This software is licensed under the
|
|
4 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
|
7771.5.3
by Stuart Bishop
Script to kill transactions that have been active for too long |
5 |
|
7771.5.4
by Stuart Bishop
Fix docstring |
6 |
"""Kill transaction that have hung around for too long.
|
7771.5.3
by Stuart Bishop
Script to kill transactions that have been active for too long |
7 |
"""
|
8 |
||
9 |
__metaclass__ = type |
|
10 |
__all__ = [] |
|
11 |
||
12 |
||
13 |
from optparse import OptionParser |
|
14 |
import os |
|
15 |
import psycopg2 |
|
16 |
import signal |
|
17 |
import sys |
|
18 |
import time |
|
19 |
||
20 |
||
21 |
def main(): |
|
22 |
parser = OptionParser() |
|
23 |
parser.add_option( |
|
24 |
'-c', '--connection', type='string', dest='connect_string', |
|
25 |
default='', help="Psycopg connection string", |
|
26 |
)
|
|
27 |
parser.add_option( |
|
28 |
'-s', '--max-seconds', type='int', |
|
29 |
dest='max_seconds', default=60*60, |
|
30 |
help='Maximum seconds time connections are allowed to remain active.', |
|
31 |
)
|
|
32 |
parser.add_option( |
|
33 |
'-q', '--quiet', action='store_true', dest="quiet", |
|
34 |
default=False, help='Silence output', |
|
35 |
)
|
|
36 |
parser.add_option( |
|
37 |
'-n', '--dry-run', action='store_true', default=False, |
|
38 |
dest='dry_run', help="Dry run - don't kill anything", |
|
39 |
)
|
|
40 |
parser.add_option( |
|
41 |
'-u', '--user', action='append', dest='users', |
|
42 |
help='Kill connection of users matching REGEXP', metavar='REGEXP') |
|
43 |
options, args = parser.parse_args() |
|
44 |
if len(args) > 0: |
|
45 |
parser.error('Too many arguments') |
|
46 |
if not options.users: |
|
47 |
parser.error('--user is required') |
|
48 |
||
49 |
user_match_sql = 'AND (%s)' % ' OR '.join( |
|
50 |
['usename ~* %s'] * len(options.users)) |
|
51 |
||
52 |
con = psycopg2.connect(options.connect_string) |
|
53 |
cur = con.cursor() |
|
54 |
cur.execute(""" |
|
55 |
SELECT usename, procpid, backend_start, xact_start
|
|
56 |
FROM pg_stat_activity
|
|
57 |
WHERE xact_start < CURRENT_TIMESTAMP - '%d seconds'::interval %s |
|
58 |
ORDER BY procpid
|
|
59 |
""" % (options.max_seconds, user_match_sql), options.users) |
|
60 |
||
61 |
rows = list(cur.fetchall()) |
|
62 |
||
63 |
if len(rows) == 0: |
|
64 |
if not options.quiet: |
|
65 |
print 'No transactions to kill' |
|
66 |
return 0 |
|
67 |
||
68 |
for usename, procpid, backend_start, transaction_start in rows: |
|
69 |
print 'Killing %s (%d), %s, %s' % ( |
|
70 |
usename, procpid, backend_start, transaction_start, |
|
71 |
)
|
|
72 |
if not options.dry_run: |
|
73 |
os.kill(procpid, signal.SIGTERM) |
|
74 |
return 0 |
|
75 |
||
76 |
||
77 |
if __name__ == '__main__': |
|
78 |
sys.exit(main()) |