From: wmorgan Date: Mon, 4 Jun 2007 01:56:26 +0000 (+0000) Subject: multiple concurrent process detection and resolution X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=b466aede237fc954ce5c64dd4ed383c04be046ba;p=sup multiple concurrent process detection and resolution git-svn-id: svn://rubyforge.org/var/svn/sup/trunk@430 5c8cc53c-5e98-4d25-b20a-d8db53a31250 --- diff --git a/Manifest.txt b/Manifest.txt index 971f0ca..8d90c39 100644 --- 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 index 176031d..cc4a12a 100644 --- 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 index 273ef01..ab835e7 100644 --- 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 < 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 < "#{ 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 new file mode 100644 index 0000000..6c3141e --- /dev/null +++ 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