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