Class: MiGA::Lair

Inherits:
MiGA
  • Object
show all
Extended by:
Common::WithDaemonClass
Includes:
Common::WithDaemon
Defined in:
lib/miga/lair.rb

Overview

Lair of MiGA Daemons handling job submissions

Constant Summary

Constants included from MiGA

CITATION, VERSION, VERSION_DATE, VERSION_NAME

Instance Attribute Summary collapse

Attributes included from Common::WithDaemon

#declare_alive_pid, #loop_i

Attributes included from Common::Net

#remote_connection_uri

Instance Method Summary collapse

Methods included from Common::WithDaemonClass

alive_file, last_alive, terminated_file

Methods included from Common::WithDaemon

#active?, #alive_file, #daemon, #declare_alive, #declare_alive_loop, #default_options, #in_loop, #last_alive, #launch_daemon_proc, #output_file, #pid_file, #process_alive?, #run, #start, #status, #stop, #terminate, #terminate_file, #terminated_file, #termination_file?, #write_alive_file

Methods inherited from MiGA

CITATION, CITATION_ARRAY, DEBUG, DEBUG_OFF, DEBUG_ON, DEBUG_TRACE_OFF, DEBUG_TRACE_ON, FULL_VERSION, LONG_VERSION, VERSION, VERSION_DATE, #advance, debug?, debug_trace?, initialized?, #like_io?, #num_suffix, rc_path, #result_files_exist?, #say

Methods included from Common::Path

#root_path, #script_path

Methods included from Common::Format

#clean_fasta_file, #seqs_length, #tabulate

Methods included from Common::Net

#download_file_ftp, #http_request, #known_hosts, #main_server, #net_method, #normalize_encoding, #remote_connection

Methods included from Common::SystemCall

#run_cmd, #run_cmd_opts

Constructor Details

#initialize(path, opts = {}) ⇒ Lair

Initialize an inactive daemon for the directory at path. See #daemon to wake the chief daemon. Supported options include:

  • json: json definition for all children daemons, by default: nil

  • latency: time to wait between iterations in seconds, by default: 120

  • wait_for: time to wait for a daemon to report being alive in seconds, by default: 30

  • keep_inactive: boolean indicating if daemons should stay alive even when inactive (when all tasks are complete), by default: false

  • name: A name for the chief daemon process, by default: basename of path

  • trust_timestamp: boolean indicating if the modified timestamp of the project is to be trusted to determine changes in the project, by default: true

  • dry: Only report when daemons would be launched, but don’t actually launch them

  • exclude: Array of project names to be excluded from the lair

  • exclude_releases: Exclude projects with release metadata from the lair

  • max_running: Run a maximum of this many projects at time

  • ignore_complete: Ignore projects that are complete based on their datasets reported metadata status



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/miga/lair.rb', line 39

def initialize(path, opts = {})
  @path = File.expand_path(path)
  @options = opts
  {
    json: nil,
    latency: 30,
    wait_for: 30,
    keep_inactive: false,
    trust_timestamp: true,
    name: File.basename(@path),
    dry: false,
    exclude: [],
    exclude_releases: false,
    max_running: nil,
    ignore_complete: false
  }.each { |k, v| @options[k] = v if @options[k].nil? }
end

Instance Attribute Details

#optionsObject

Options used to setup the chief daemon



17
18
19
# File 'lib/miga/lair.rb', line 17

def options
  @options
end

#pathObject (readonly) Also known as: daemon_home

Absolute path to the directory where the projects are located



14
15
16
# File 'lib/miga/lair.rb', line 14

def path
  @path
end

Instance Method Details

#check_directoriesObject

Traverse directories checking MiGA projects



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/miga/lair.rb', line 146

def check_directories
  active = 0
  each_project do |project|
    break if options[:max_running] && active >= options[:max_running]

    d = project_daemon(project)
    d.active? and active += 1 and next

    l_alive = d.last_alive
    unless l_alive.nil?
      next if options[:trust_timestamp] && project..updated < l_alive
      next if l_alive > Time.now - options[:wait_for]
    end
    launch_daemon(project) && active += 1
  end
end

#daemon_first_loopObject

First loop of the lair’s chief daemon



75
76
77
78
79
80
81
# File 'lib/miga/lair.rb', line 75

def daemon_first_loop
  say '-----------------------------------'
  say '%s launched' % daemon_name
  say '-----------------------------------'
  say 'Configuration options:'
  say options.to_s
end

#daemon_loopObject

Run one loop step. Returns a Boolean indicating if the loop should continue.



85
86
87
88
89
90
91
# File 'lib/miga/lair.rb', line 85

def daemon_loop
  check_directories
  return false if options[:dry]

  sleep(options[:latency])
  true
end

#daemon_nameObject

Name of the lair’s chief daemon



63
64
65
# File 'lib/miga/lair.rb', line 63

def daemon_name
  "MiGA:#{options[:name]}"
end

#each_daemon(include_self = true) {|_self| ... } ⇒ Object

Perform block for each daemon, including the chief daemon if include_self.

Yields:

  • (_self)

Yield Parameters:

  • _self (MiGA::Lair)

    the object that the method was called on



139
140
141
142
# File 'lib/miga/lair.rb', line 139

def each_daemon(include_self = true)
  yield(self) if include_self
  each_project { |project| yield(project_daemon(project)) }
end

#each_project(dir = path) ⇒ Object

Perform block for each project in the dir directory, passing the absolute path of the project to the block. Searches for MiGA projects recursively in all subdirectories that are not MiGA projects.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/miga/lair.rb', line 118

def each_project(dir = path)
  Dir.entries(dir).each do |f|
    next if %w[. ..].include?(f) # Ruby <= 2.3 doesn't have Dir.children

    f = File.join(dir, f)
    if MiGA::Project.exist? f
      project = MiGA::Project.load(f)
      raise "Cannot load project: #{f}" if project.nil?
      next if options[:exclude].include?(project.name)
      next if options[:exclude_releases] && project.[:release]

      yield(project)
    elsif Dir.exist? f
      each_project(f) { |p| yield(p) }
    end
  end
end

#launch_daemon(project) ⇒ Object

Launch daemon for the MiGA::Project project and returns the corresponding MiGA::Daemon object



166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/miga/lair.rb', line 166

def launch_daemon(project)
  return if options[:ignore_complete] && project.complete?

  say "Launching daemon: #{project.path}"
  daemon = project_daemon(project)
  daemon.runopts(:shutdown_when_done, true) unless options[:keep_inactive]
  unless options[:dry]
    daemon.start
    sleep(1) # <- to make sure the daemon started up (it takes about 0.1 secs)
  end
  daemon
end

#project_daemon(project) ⇒ Object

Return the daemon of project, a MiGA::Project object



69
70
71
# File 'lib/miga/lair.rb', line 69

def project_daemon(project)
  MiGA::Daemon.new(project, options[:json])
end

#terminate_daemon(daemon) ⇒ Object

Send termination message to daemon, an object implementing MiGA::Common::WithDaemon



105
106
107
108
109
110
111
# File 'lib/miga/lair.rb', line 105

def terminate_daemon(daemon)
  say "Probing #{daemon.class} #{daemon.daemon_home}"
  if daemon.active?
    say 'Sending termination message'
    FileUtils.touch(daemon.terminate_file)
  end
end

#terminate_daemonsObject

Terminate all daemons in the lair (including the chief daemon)



95
96
97
98
99
100
# File 'lib/miga/lair.rb', line 95

def terminate_daemons
  terminate_daemon(self)
  each_project do |project|
    terminate_daemon(MiGA::Daemon.new(project))
  end
end