class Bookie::Database::Job

A reported job

The various filter methods can be chained to produce more complex queries.

Examples

Bookie::Database::Job.by_user_name('root').by_system_name('localhost').find_each do |job|
  puts job.inspect
end

Public Class Methods

by_command_name(c_name) click to toggle source

Filters by command name

# File lib/bookie/database/job.rb, line 76
def self.by_command_name(c_name)
  where('jobs.command_name = ?', c_name)
end
by_group_name(group_name) click to toggle source

Filters by group name

# File lib/bookie/database/job.rb, line 59
def self.by_group_name(group_name)
  group = Group.find_by(name: group_name)
  if group then
    joins(:user).where('users.group_id = ?', group.id)
  else
    self.none
  end
end
by_system(system) click to toggle source
# File lib/bookie/database/job.rb, line 47
def self.by_system(system)
  where('jobs.system_id = ?', system.id)
end
by_system_name(system_name) click to toggle source

Filters by system name

# File lib/bookie/database/job.rb, line 53
def self.by_system_name(system_name)
  joins(:system).where('systems.name = ?', system_name)
end
by_system_type(system_type) click to toggle source

Filters by system type

# File lib/bookie/database/job.rb, line 70
def self.by_system_type(system_type)
  joins(:system).where('systems.system_type_id = ?', system_type.id)
end
by_time_range(time_range) click to toggle source

Finds all jobs that were running at some point in a given time range

# File lib/bookie/database/job.rb, line 82
def self.by_time_range(time_range)
  if time_range.empty?
    self.none
  else
    time_range = time_range.exclusive
    where('jobs.end_time > ? AND jobs.start_time < ?', time_range.begin, time_range.end)
  end
end
by_user(user) click to toggle source

To consider: disable end_time= ?

# File lib/bookie/database/job.rb, line 37
def self.by_user(user)
  where('jobs.user_id = ?', user.id)
end
by_user_name(user_name) click to toggle source

Filters by user name

# File lib/bookie/database/job.rb, line 43
def self.by_user_name(user_name)
  joins(:user).where('users.name = ?', user_name)
end
overlapping_edges(time_range) click to toggle source

Finds all jobs that overlap the edges of the given time range

# File lib/bookie/database/job.rb, line 109
def self.overlapping_edges(time_range)
  if time_range.empty?
    self.none
  else
    time_range = time_range.exclusive
    query_str = ['begin', 'end'].map{ |edge| "(jobs.start_time < :#{edge} AND jobs.end_time > :#{edge})" }.join(" OR ")
    where(query_str, {:begin => time_range.begin, :end => time_range.end})
  end
end
summary(time_range = nil) click to toggle source

Produces a summary of the jobs in the given time interval

Returns a hash with the following fields:

  • :num_jobs: the number of jobs in the interval

  • :successful: the number of jobs that have completed successfully

  • :cpu_time: the total CPU time used

  • :memory_time: the sum of memory * wall_time for all jobs in the interval

This method should probably not be chained with other queries that filter by start/end time. It also doesn’t work with the limit() method.

The time_range parameter is always treated as if time_range.exclude_end? is true.

# File lib/bookie/database/job.rb, line 132
def self.summary(time_range = nil)
  jobs = self

  num_jobs = 0
  successful = 0
  cpu_time = 0.0
  memory_time = 0

  if time_range
    unless time_range.empty?
      time_range = time_range.exclusive

      #Any jobs that are completely within the time range can
      #be summarized as-is.
      jobs_within = jobs.within_time_range(time_range)
      #TODO: optimize into one query?
      num_jobs += jobs_within.count
      successful += jobs_within.where(:exit_code => 0).count
      cpu_time += jobs_within.sum(:cpu_time)
      memory_time += jobs_within.sum('jobs.memory * jobs.wall_time')

      #Any jobs that overlap an edge of the time range
      #must be clipped.
      jobs_overlapped = jobs.overlapping_edges(time_range)
      jobs_overlapped.find_each do |job|
        start_time = [job.start_time, time_range.begin].max
        end_time = [job.end_time, time_range.end].min
        clipped_wall_time = end_time.to_i - start_time.to_i
        if job.wall_time != 0
          cpu_time += Float(job.cpu_time * clipped_wall_time) / job.wall_time
          memory_time += job.memory * clipped_wall_time
        end
        num_jobs += 1
        successful += 1 if job.exit_code == 0
      end
    end
  else
    #There's no time_range constraint; just summarize everything.
    num_jobs = jobs.count
    successful = jobs.where(:exit_code => 0).count
    cpu_time = jobs.sum(:cpu_time)
    memory_time = jobs.sum('jobs.memory * jobs.wall_time')
  end

  return {
    :num_jobs => num_jobs,
    :successful => successful,
    :cpu_time => cpu_time.round,
    :memory_time => memory_time,
  }
end
within_time_range(time_range) click to toggle source

Similar to by_time_range, but only includes jobs that are completely contained within the time range

# File lib/bookie/database/job.rb, line 94
def self.within_time_range(time_range)
  if time_range.empty?
    self.none
  else
    time_range = time_range.exclusive
    #The second "<=" operator _is_ intentional.
    #If the job's end_time is one second past the last value in the range, it
    #is still considered to be contained within time_range because it did not
    #run outside time_range; it only _stopped_ outside it.
    where('? <= jobs.start_time AND jobs.end_time <= ?', time_range.begin, time_range.end)
  end
end

Public Instance Methods

end_time() click to toggle source

The time at which the job ended

# File lib/bookie/database/job.rb, line 27
def end_time
  return start_time + wall_time
end
end_time=(time) click to toggle source
# File lib/bookie/database/job.rb, line 31
def end_time=(time)
  self.wall_time = (time - start_time)
end