lib/frontkick/command.rb in frontkick-0.1.0 vs lib/frontkick/command.rb in frontkick-0.2.0
- old
+ new
@@ -1,15 +1,21 @@
require 'benchmark'
require 'open3'
module Frontkick
+ class Locked < StandardError
+ end
+end
+
+module Frontkick
class Command
def self.exec(cmd, opts = {})
stdout, stderr, exit_code, duration = nil
stdin, out, err, wait_thr, pid = nil
cmd_array = cmd.kind_of?(Array) ? cmd : [cmd]
+ lock_fd = file_lock(opts[:exclusive]) if opts[:exclusive]
begin
timeout(opts[:timeout]) do # nil is for no timeout
duration = Benchmark.realtime do
stdin, out, err, wait_thr = Open3.popen3(*cmd_array)
stdin.close
@@ -30,10 +36,11 @@
ensure
stdin.close if stdin and !stdin.closed?
out.close if out and !out.closed?
err.close if err and !err.closed?
wait_thr.kill if wait_thr and !wait_thr.stop?
+ lock_fd.flock(File::LOCK_UN)
end
CommandResult.new(stdout, stderr, exit_code, duration)
end
@@ -41,8 +48,23 @@
begin
pid, status = Process.waitpid2(pid) # wait child processes finish
rescue Errno::ECHILD => e
# no child process
end
+ end
+
+ # Use file lock to perfome exclusive operation
+ #
+ # @param lock_file file path used to lock
+ # @return file descriptor
+ # @raise Fontkick::Locked if locked
+ def self.file_lock(lock_file)
+ lock_fd = File.open(lock_file, File::RDWR|File::CREAT, 0644)
+ success = lock_fd.flock(File::LOCK_EX|File::LOCK_NB)
+ unless success
+ lock_fd.flock(File::LOCK_UN)
+ raise Frontkick::Locked
+ end
+ lock_fd
end
end
end