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