Merge branch 'master' into 3583-provenance-graph-issue
[arvados.git] / services / api / app / models / job.rb
index ea9990d9e7a3e766c709d194f62aa84255a0d6e0..4b86be79699e6cf678975934e40f35c3e35d62c7 100644 (file)
@@ -14,6 +14,7 @@ class Job < ArvadosModel
   validate :ensure_script_version_is_commit
   validate :find_docker_image_locator
   validate :validate_status
+  validate :validate_state_change
 
   has_many :commit_ancestors, :foreign_key => :descendant, :primary_key => :script_version
   has_many(:nodes, foreign_key: :job_uuid, primary_key: :uuid)
@@ -70,9 +71,7 @@ class Job < ArvadosModel
   end
 
   def self.queue
-    self.where('started_at is ? and is_locked_by_uuid is ? and cancelled_at is ? and success is ?',
-               nil, nil, nil, nil).
-      order('priority desc, created_at')
+    self.where('state = ?', Queued).order('priority desc, created_at')
   end
 
   def queue_position
@@ -94,7 +93,7 @@ class Job < ArvadosModel
     transaction do
       self.reload
       unless self.state == Queued and self.is_locked_by_uuid.nil?
-        raise ConflictError.new
+        raise AlreadyLockedError
       end
       self.state = Running
       self.is_locked_by_uuid = locked_by_uuid
@@ -330,4 +329,30 @@ class Job < ArvadosModel
     end
   end
 
+  def validate_state_change
+    ok = true
+    if self.state_changed?
+      ok = case self.state_was
+           when nil
+             # state isn't set yet
+             true
+           when Queued
+             # Permit going from queued to any state
+             true
+           when Running
+             # From running, may only transition to a finished state
+             [Complete, Failed, Cancelled].include? self.state
+           when Complete, Failed, Cancelled
+             # Once in a finished state, don't permit any more state changes
+             false
+           else
+             # Any other state transition is also invalid
+             false
+           end
+      if not ok
+        errors.add :state, "invalid change from #{self.state_was} to #{self.state}"
+      end
+    end
+    ok
+  end
 end