commit b466aede237fc954ce5c64dd4ed383c04be046ba
parent 8f527cafa779dddff1c82ece0c44569598604040
Author: wmorgan <wmorgan@5c8cc53c-5e98-4d25-b20a-d8db53a31250>
Date: Mon, 4 Jun 2007 01:56:26 +0000
multiple concurrent process detection and resolution
git-svn-id: svn://rubyforge.org/var/svn/sup/trunk@430 5c8cc53c-5e98-4d25-b20a-d8db53a31250
Diffstat:
5 files changed, 127 insertions(+), 9 deletions(-)
diff --git a/Manifest.txt b/Manifest.txt
@@ -57,6 +57,7 @@ lib/sup/person.rb
lib/sup/poll.rb
lib/sup/sent.rb
lib/sup/source.rb
+lib/sup/suicide.rb
lib/sup/tagger.rb
lib/sup/textfield.rb
lib/sup/thread.rb
diff --git a/Rakefile b/Rakefile
@@ -16,7 +16,7 @@ Hoe.new('sup', Redwood::VERSION) do |p|
p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[2].gsub(/^\s+/, "")
p.changes = p.paragraphs_of('History.txt', 0..0).join("\n\n")
p.email = "wmorgan-sup@masanjin.net"
- p.extra_deps = [['ferret', '>= 0.10.13'], ['ncurses', '>= 0.9.1'], ['rmail', '>= 0.17'], 'highline', 'net-ssh', ['trollop', '>= 1.5']]
+ p.extra_deps = [['ferret', '>= 0.10.13'], ['ncurses', '>= 0.9.1'], ['rmail', '>= 0.17'], 'highline', 'net-ssh', ['trollop', '>= 1.5'], 'lockfile']
end
rule 'ss?.png' => 'ss?-small.png' do |t|
diff --git a/bin/sup b/bin/sup
@@ -2,6 +2,7 @@
require 'rubygems'
require 'ncurses'
+require 'fileutils'
require 'trollop'
require "sup"
@@ -54,6 +55,30 @@ def stop_cursing
end
module_function :start_cursing, :stop_cursing
+begin
+ Redwood::lock
+rescue LockError => e
+ require 'highline'
+ h = HighLine.new
+ h.say <<EOS
+Error: sup is already running! User #{e.user} on host #{e.host} was running sup
+with pid #{e.pid} as of #{e.time}.
+EOS
+
+ case h.ask("Should I try and kill that process? ")
+ when /^\s*y\s*$/i
+ h.say "Ok, suggesting sepuku..."
+ FileUtils.touch Redwood::SUICIDE_FN
+ sleep SuicideManager::DELAY * 2
+ FileUtils.rm_f Redwood::SUICIDE_FN
+ h.say "Let's try that again."
+ retry
+ else
+ h.say "Ok, see you later."
+ exit
+ end
+end
+
Redwood::start
Index.new.load
@@ -140,7 +165,10 @@ begin
imode.load_threads :num => ibuf.content_height, :when_done => lambda { reporting_thread { sleep 1; PollManager.poll } }
- PollManager.start_thread unless $opts[:no_threads]
+ unless $opts[:no_threads]
+ PollManager.start_thread
+ SuicideManager.start_thread
+ end
until $exception
bm.draw_screen
@@ -223,14 +251,20 @@ rescue Exception => e
ensure
Redwood::finish
stop_cursing
- if $exception
- Redwood::log "oh crap, an exception"
- else
+
+ case $exception
+ when SuicideException
+ Redwood::log "I've been asked to commit sepuku. I obey!"
+ exit
+ when nil
Redwood::log "good night, sweet prince!"
+ Index.save
+ else
+ Redwood::log "oh crap, an exception"
end
-end
-Index.save unless $exception # TODO: think about this
+ Redwood::unlock
+end
if $exception
$stderr.puts <<EOS
diff --git a/lib/sup.rb b/lib/sup.rb
@@ -3,6 +3,29 @@ require 'yaml'
require 'zlib'
require 'thread'
require 'fileutils'
+require 'lockfile'
+
+## time for some monkeypatching!
+class Lockfile
+ def gen_lock_id
+ Hash[
+ 'host' => "#{ Socket.gethostname }",
+ 'pid' => "#{ Process.pid }",
+ 'ppid' => "#{ Process.ppid }",
+ 'time' => timestamp,
+ 'user' => ENV["USER"]
+ ]
+ end
+
+ def dump_lock_id lock_id = @lock_id
+ "host: %s\npid: %s\nppid: %s\ntime: %s\nuser: %s\n" %
+ lock_id.values_at('host','pid','ppid','time','user')
+ end
+
+ def lockinfo_on_disk
+ load_lock_id IO.read(path)
+ end
+end
class Object
## this is for debugging purposes because i keep calling #id on the
@@ -12,6 +35,15 @@ class Object
end
end
+class LockError < StandardError
+ def initialize h
+ super ""
+ @h = h
+ end
+
+ def method_missing m; @h[m.to_s] end
+end
+
class Module
def yaml_properties *props
props = props.map { |p| p.to_s }
@@ -41,6 +73,8 @@ module Redwood
CONTACT_FN = File.join(BASE_DIR, "contacts.txt")
DRAFT_DIR = File.join(BASE_DIR, "drafts")
SENT_FN = File.join(BASE_DIR, "sent.mbox")
+ LOCK_FN = File.join(BASE_DIR, "lock")
+ SUICIDE_FN = File.join(BASE_DIR, "please-kill-yourself")
YAML_DOMAIN = "masanjin.net"
YAML_DATE = "2006-10-01"
@@ -58,7 +92,7 @@ module Redwood
File.open("sup-exception-log.txt", "w") do |f|
f.puts "--- #{e.class.name} at #{Time.now}"
f.puts e.message, e.backtrace
- end
+ end unless e.is_a? SuicideException
$exception ||= e
raise
end
@@ -95,6 +129,7 @@ module Redwood
Redwood::DraftManager.new Redwood::DRAFT_DIR
Redwood::UpdateManager.new
Redwood::PollManager.new
+ Redwood::SuicideManager.new Redwood::SUICIDE_FN
end
def finish
@@ -104,6 +139,23 @@ module Redwood
Redwood::BufferManager.deinstantiate!
end
+ def lock
+ FileUtils.rm_f SUICIDE_FN
+
+ Redwood::log "locking #{LOCK_FN}..."
+ $lock = Lockfile.new LOCK_FN, :retries => 0
+ begin
+ $lock.lock
+ rescue Lockfile::MaxTriesLockError
+ raise LockError, $lock.lockinfo_on_disk
+ end
+ end
+
+ def unlock
+ Redwood::log "unlocking #{LOCK_FN}..."
+ $lock.unlock if $lock
+ end
+
## not really a good place for this, so I'll just dump it here.
def report_broken_sources opts={}
return unless BufferManager.instantiated?
@@ -146,7 +198,8 @@ EOM
end
end
- module_function :save_yaml_obj, :load_yaml_obj, :start, :finish, :report_broken_sources
+ module_function :save_yaml_obj, :load_yaml_obj, :start, :finish,
+ :lock, :unlock, :report_broken_sources
end
## set up default configuration file
@@ -186,6 +239,7 @@ end
require "sup/util"
require "sup/update"
+require "sup/suicide"
require "sup/message"
require "sup/source"
require "sup/mbox"
diff --git a/lib/sup/suicide.rb b/lib/sup/suicide.rb
@@ -0,0 +1,29 @@
+require 'fileutils'
+module Redwood
+
+class SuicideException < StandardError; end
+
+class SuicideManager
+ include Singleton
+
+ DELAY = 5
+
+ def initialize fn
+ @fn = fn
+ self.class.i_am_the_instance self
+ end
+
+ def start_thread
+ Redwood::reporting_thread do
+ while true
+ sleep DELAY
+ if File.exists? @fn
+ FileUtils.rm_rf @fn
+ raise SuicideException
+ end
+ end
+ end
+ end
+end
+
+end