Module: Lifeline

Defined in:
lib/lifeline.rb

Defined Under Namespace

Classes: LifelineRakeTask

Instance Method Summary collapse

Instance Method Details

#define_lifeline_tasks(namespace, &block) ⇒ Object

A method that defines 3 rake tasks for doing lifelines:

  • namespace:run runs the specified block

  • namespace:lifeline a lifeline for executing only a single copy of namespace:run at a time

  • namespace:terminate a task for terminating the lifelines

Parameters:

  • namespace (String, Symbol)

    the namespace to define the 3 tasks in

  • &block

    a block which defines the body of the namespace:run method

Raises:

  • (ArgumentError)

    if you do not pass in a block argument



135
136
137
# File 'lib/lifeline.rb', line 135

def define_lifeline_tasks(namespace, &block)
  LifelineRakeTask.new(namespace, &block)
end

#get_process_listObject



13
14
15
16
17
18
19
20
21
22
23
# File 'lib/lifeline.rb', line 13

def get_process_list
  processes = get_processes_from_shell

  return nil if processes.nil?

  processes.split(/\n/).map do |p|
    if p =~ /^\s*(\d+)\s(.+)$/
      {:pid => $1.to_i, :command => $2.strip}
    end
  end.compact
end

#get_processes_from_shellObject



7
8
9
# File 'lib/lifeline.rb', line 7

def get_processes_from_shell
   %x{ps ax -o pid,command}
end

#lifelineObject

A method for executing a block of code only if there is no other process with the same command running. This is useful if you want to have a perpetually running daemon that only executes once at a time. It uses the process name returned by ps ax to see if there is a process with the same command name but a different PID already executing. If so, it terminates without running the block. NOTE: since it uses the command name returned from ps ax, it us up to to you to name the process containing this code with a distinctly unique name. If two separate Rails projects both have a rake lifeline task they WILL interfere with each other. I’d suggest prefixing with the project name (ie, doc_viewer:lifeline) to be sure

Parameters:

  • &block

    a block which is executed if there is not already a lifeline running.

Raises:

  • (ArgumentError)

    if you do not pass in a block argument



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/lifeline.rb', line 35

def lifeline
  if !block_given?
    raise ArgumentError, "You must pass in a block to be the body of the run rake task"
  end

  my_pid = $$
  processes = get_process_list

  if processes.nil? || processes.empty?
    raise "No processes being returned by get_process_list. Aborting!"
  end

  myself = processes.detect {|p| p[:pid] == my_pid}
  if myself.nil?
    raise "Unable to find self (PID=#{my_pid}) in process list. This is bizarre to say the least. Exiting.\n#{processes.map {|p| p.inspect}.join("\n")}"
  end

  # there isn't already another process running with the same command
  if !processes.any? {|p| p[:pid] != my_pid && p[:command] == myself[:command]}
    yield
  end
end