3 # Author: Martin Langhoff <martin.langhoff@remote-learner.net>
7 from __future__
import with_statement
20 " flock_multi [-h] [-v] [-E 200] [-T 201] [-s 20] [-w 60m ] heavy 4 heavyscript \n" \
22 " -w accepts m and h suffixes\n"
25 if isinstance(a
, (int, long)) or re
.match('\d+$', a
):
27 m
= re
.match('(\d+)m$', a
)
29 return (int(m
.group(1)) * 60)
30 m
= re
.match('(\d+)h$', a
)
32 return (int(m
.group(1)) * 60 * 60)
33 sys
.stderr
.write("ERROR: timeout parameter not an integer!\n")
36 def maybe_timeout(timeout
, exitcode
):
38 if timeout
< time
.time():
39 sys
.stderr
.write("ERROR: flock_multi timeout\n")
43 # vars overriden from env
44 lockdir
= '/mnt/cluster/lock'
45 confdir
= '/mnt/cluster/conf/lock'
46 if 'FLOCK_MULTI_DIR' in os
.environ
:
47 lockdir
= os
.environ
['FLOCK_MULTI_DIR']
48 if 'FLOCK_MULTI_CONF_DIR' in os
.environ
:
49 confdir
= os
.environ
['FLOCK_MULTI_CONF_DIR']
52 long_opts
= ["help", "verbose", "conflict-exit-code=",
53 "timeout-exit-code=", "sleeptime=", "wait=", "timeout="]
54 opts
, args
= getopt
.getopt(sys
.argv
[1:], "hvE:T:s:w:", long_opts
)
55 except getopt
.GetoptError
, e
:
56 sys
.stderr
.write("ERROR: Invalid parameter: %s\n" % e
[0])
57 sys
.stderr
.write(help())
61 sys
.stderr
.write("ERROR: At least 3 parameters needed.\n")
62 sys
.stderr
.write(help())
72 if o
in ("-v", "--verbose") :
74 elif o
in ("-h", "--help"):
77 elif o
in ("-E", "--conflict-exit-code"):
79 elif o
in ("-T", "--timeout-exit-code"):
81 elif o
in ("-s", "--sleeptime"):
83 elif o
in ("-w", "--wait", "--timeout"):
84 timeout
= float(arg_to_secs(a
)) + time
.time()
86 assert False, "unhandled option %s" % o
88 lockname
= args
.pop(0)
89 maxlocks
= int(args
.pop(0))
92 conffile
= os
.path
.join(confdir
, lockname
)
94 if os
.path
.exists(conffile
):
95 tmpval
= int(open(conffile
).read())
98 sys
.stderr
.write("WARNING: Ignoring invalid value in %s\n" % conffile
)
101 print "Using %s maxlocks" % maxlocks
104 hostname
= os
.uname()[1]
108 # cast to have better splay
109 sleeptime
= float(sleeptime
)
112 locks
= range(1, maxlocks
+1)
114 random
.shuffle(locks
)
115 for trylock
in locks
:
116 # print "trying %s" %trylock
117 trylockfn
= os
.path
.join(lockdir
, lockname
+ '.%s' % trylock
)
118 # we open for "append", and only move to truncate the
119 # file if we succeed in getting the flock
120 with
open(trylockfn
, 'a') as fh
:
122 fcntl
.flock(fh
, fcntl
.LOCK_EX|fcntl
.LOCK_NB
)
128 print "Got %s" % trylockfn
130 fh
.write("%s PID: %s epoch: %s %s\n" %
131 (hostname
, mypid
, time
.time(), time
.strftime("%a, %d %b %Y %H:%M:%S +0000", t
)))
132 fh
.write(' '.join(cmd
))
135 # execute the command requested
136 cmdexit
= subprocess
.call(cmd
)
137 except IOError: # failed to get lock, nonfatal
141 sys
.stderr
.write("ERROR: No such file or directory: %s\n" % cmd
[0])
146 # runs on _all_ exceptions - IOError, OSError and KeyboardInterrupt
147 # truncate flock'd file on completion
157 maybe_timeout(timeout
, timeouterr
)
159 splay
= sleeptime
/ 10
160 actual_sleep
= sleeptime
+ random
.uniform(0 - splay
, splay
)
162 print "Tried all locks - sleeping %s" % actual_sleep
163 time
.sleep(actual_sleep
)
164 maybe_timeout(timeout
, timeouterr
)
166 if __name__
== '__main__':
169 except KeyboardInterrupt: # user hit control-C
171 except Exception: # all "interesting" exceptions, but not SystemExit
172 traceback
.print_exc(file=sys
.stdout
)