~launchpad-pqm/launchpad/devel

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())