Class: SequenceServer::Job

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Includes:
FileUtils
Defined in:
lib/sequenceserver/job.rb

Overview

Abstract job super class.

Provides a simple framework to store job data, execute shell commands asynchronously and capture stdout, stderr and exit status. Subclasses must provide a concrete implementation for ‘command` and may override any other methods as required.

Global ‘config` and `logger` object are available as instance methods.

Singleton methods provide the facility to create and queue a job, fetch a job or all jobs, and delete a job.

Direct Known Subclasses

BLAST::Job

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params = {}) ⇒ Job

Initialize the job: generates a job id, creates directory where all kind of job data will be held, yields (if block given) and saves the job.

Subclasses should extend ‘initialize` as per requirement.



87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/sequenceserver/job.rb', line 87

def initialize(params = {})
  @id = params.fetch(:id, SecureRandom.uuid)
  @submitted_at = Time.now
  mkdir_p dir
  yield if block_given?
  save
rescue Errno::ENOSPC
  raise SystemError, 'Not enough disk space to start a new job'
rescue Errno::EACCES
  raise SystemError, "Permission denied to write to #{DOTDIR}"
rescue StandardError => e
  rm_rf dir
  raise e
end

Instance Attribute Details

#completed_atObject (readonly)

Returns the value of attribute completed_at.



102
103
104
# File 'lib/sequenceserver/job.rb', line 102

def completed_at
  @completed_at
end

#exitstatusObject (readonly)

Returns the value of attribute exitstatus.



102
103
104
# File 'lib/sequenceserver/job.rb', line 102

def exitstatus
  @exitstatus
end

#idObject (readonly)

Returns the value of attribute id.



102
103
104
# File 'lib/sequenceserver/job.rb', line 102

def id
  @id
end

#submitted_atObject (readonly)

Returns the value of attribute submitted_at.



102
103
104
# File 'lib/sequenceserver/job.rb', line 102

def 
  @submitted_at
end

Class Method Details

.allObject

Returns an Array of all jobs.



58
59
60
61
# File 'lib/sequenceserver/job.rb', line 58

def all
  Dir["#{DOTDIR}/**/job.yaml"]
    .map { |f| fetch File.basename File.dirname f }
end

.create(params) ⇒ Object

Creates and queues a job. Returns created job object.



26
27
28
29
# File 'lib/sequenceserver/job.rb', line 26

def create(params)
  job = BLAST::Job.new(params) # TODO: Dynamic dispatch.
  enqueue(job)
end

.delete(id) ⇒ Object

Deletes job with the given id.



53
54
55
# File 'lib/sequenceserver/job.rb', line 53

def delete(id)
  FileUtils.rm_r File.join(DOTDIR, id)
end

.enqueue(job) ⇒ Object

Enqueues a job that is already created, returns the job object



64
65
66
67
# File 'lib/sequenceserver/job.rb', line 64

def enqueue(job)
  pool.queue { job.run }
  job
end

.fetch(id) ⇒ Object

Fetches job with the given id.



42
43
44
45
46
47
48
49
50
# File 'lib/sequenceserver/job.rb', line 42

def fetch(id)
  job_file = File.join(DOTDIR, id, 'job.yaml')
  return nil unless File.exist?(job_file)

  YAML.safe_load_file(
    job_file,
    permitted_classes: serializable_classes
  )
end

.serializable_classesObject



31
32
33
34
35
36
37
38
39
# File 'lib/sequenceserver/job.rb', line 31

def serializable_classes
  [
    Time,
    Symbol,
    SequenceServer::Job,
    SequenceServer::BLAST::Job,
    SequenceServer::Database
  ]
end

Instance Method Details

#commandObject

Returns shell command that will be executed. Subclass needs to provide a concrete implementation.



106
107
108
# File 'lib/sequenceserver/job.rb', line 106

def command
  fail 'Not implemented.'
end

#dirObject

Where to save all kind of data for this job.



143
144
145
# File 'lib/sequenceserver/job.rb', line 143

def dir
  File.join(DOTDIR, id)
end

#done?Boolean

Is exitstatus of the job available? If yes, it means the job is done.

Returns:

  • (Boolean)


121
122
123
# File 'lib/sequenceserver/job.rb', line 121

def done?
  !!@exitstatus
end

#raise!Object

Raise RuntimeError if job finished with non-zero exit status. This method should be called on a completed job before attempting to use the results. Subclasses should provide their own implementation.



128
129
130
# File 'lib/sequenceserver/job.rb', line 128

def raise!
  fail if done? && exitstatus != 0
end

#runObject

Shell out and execute the job.

NOTE: This method is called asynchronously by thread pool.



113
114
115
116
117
118
# File 'lib/sequenceserver/job.rb', line 113

def run
  sys(command, path: config[:bin], stdout: stdout, stderr: stderr)
  done!
rescue CommandFailed => e
  done! e.exitstatus
end

#stderrObject

Where will the stderr be written to during execution and read from later.



138
139
140
# File 'lib/sequenceserver/job.rb', line 138

def stderr
  File.join(dir, 'stderr')
end

#stdoutObject

Where will the stdout be written to during execution and read from later.



133
134
135
# File 'lib/sequenceserver/job.rb', line 133

def stdout
  File.join(dir, 'stdout')
end