{"id":633,"date":"2012-05-18T21:05:43","date_gmt":"2012-05-18T21:05:43","guid":{"rendered":"http:\/\/tech.avant.net\/q\/?p=633"},"modified":"2019-06-01T04:37:37","modified_gmt":"2019-06-01T04:37:37","slug":"timeout-command-in-python","status":"publish","type":"post","link":"https:\/\/tech.avant.net\/q\/timeout-command-in-python\/","title":{"rendered":"timeout command in python"},"content":{"rendered":"<p>I would like to add a timeout to any shell command such that if it does not complete within a specified number of seconds the command will exit. This would be useful for a any long-running command where I&#8217;d like it to die on its own rather than manually killing the long-running process.<\/p>\n<p>There are several solutions to this, GNU coreutils provides a timeout command that does exactly like this, you could also use ulimit, or shell hacks such as<\/p>\n<pre>bash -c '(sleep 10; kill -9 $) &amp; exec command'\n<\/pre>\n<p>However, I&#8217;d like to give the program a chance to exit gracefully before forcibly killing it. In other words, in a UNIX environment I would like to first send a SIGTERM signal to the long-running process before issuing a SIGKILL. This way the command has a chance to properly close any network or I\/O before exiting.<\/p>\n<p>You could use the following python recipe, also available <a href=\"https:\/\/github.com\/timwarnock\/timeout.py\">here<\/a><\/p>\n<pre class=\"sh_python\">#!\/usr\/bin\/env python\n\"\"\"Usage: timeout.py [timeout] [command]\n    timeout in seconds before killing [command]\n    command is any command (and arguments) that you wish to timeout\"\"\"\nimport datetime, os, signal, subprocess, sys, time\n\n# how long (in seconds) between sigterm and sigkill\nSIGTERM_TO_SIGKILL = 1 \n\ndef timeout_command(cmd, timeout):\n    start = datetime.datetime.now()\n    process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n    while process.poll() is None:\n        now = datetime.datetime.now()\n        if (now - start).seconds &gt;= timeout:\n            os.kill(process.pid, signal.SIGTERM)\n            sys.stderr.write('TIMEOUT %s second%s, sent sigterm to %s %s\\n' %(str(timeout), '' if timeout==1 else 's', process.pid, ' '.join(cmd)))\n            time.sleep(SIGTERM_TO_SIGKILL)\n            if process.poll() is None:\n                os.kill(process.pid, signal.SIGKILL)\n                sys.stderr.write('process still running, sent sigkill to %s %s\\n' %(process.pid, ' '.join(cmd)))\n                os.waitpid(-1, os.WNOHANG)\n            return 2\n        time.sleep(0.1)\n    sys.stdout.write(process.stdout.read())\n    sys.stderr.write(process.stderr.read())\n    return 0\n\ndef main(argv=None):\n    try:\n        if \"-h\" in argv or \"--help\" in argv:\n            print __doc__\n            return 0\n        return timeout_command(sys.argv[2:], int(argv[1]))\n    except:\n        print &gt;&gt;sys.stderr, __doc__\n        return 2\n\nif __name__ == '__main__':\n    sys.exit(main(sys.argv))\n<\/pre>\n<p>This could be run as follows,<\/p>\n<pre>tim@laptop:~\/bin :) timeout.py 2 sleep 3\nTIMEOUT 2 seconds, sent sigterm to 9036 sleep 3\n<\/pre>\n<p>Or for the case where a SIGTERM was caught and ignored,<\/p>\n<pre>tim@laptop:~\/bin :) timeout.py 2 sleeper_ignore_sigterm.py \nTIMEOUT 2 seconds, sent sigterm to 9060 sleeper_ignore_sigterm.py\nprocess still running, sent sigkill to 9060 sleeper_ignore_sigterm.py\n<\/pre>\n<hr>\n<div id=\"amzn-assoc-ad-aefa7676-1e81-45ee-9f86-a6899fe69243\"><\/div>\n<p><script async=\"\" src=\"\/\/z-na.amazon-adsystem.com\/widgets\/onejs?MarketPlace=US&amp;adInstanceId=aefa7676-1e81-45ee-9f86-a6899fe69243\"><\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I would like to add a timeout to any shell command such that if it does not complete within a specified number of seconds the command will exit. This would be useful for a any long-running command where I&#8217;d like it to die on its own rather than manually killing the long-running process. There are [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[6,14],"tags":[],"_links":{"self":[{"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/posts\/633"}],"collection":[{"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/comments?post=633"}],"version-history":[{"count":6,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/posts\/633\/revisions"}],"predecessor-version":[{"id":993,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/posts\/633\/revisions\/993"}],"wp:attachment":[{"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/media?parent=633"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/categories?post=633"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tech.avant.net\/q\/wp-json\/wp\/v2\/tags?post=633"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}