taverna-player 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +8 -0
  3. data/CHANGES.rdoc +47 -0
  4. data/README.rdoc +43 -3
  5. data/Rakefile +1 -4
  6. data/app/assets/stylesheets/taverna_player/coderay.css +30 -20
  7. data/app/controllers/taverna_player/application_controller.rb +2 -2
  8. data/app/controllers/taverna_player/job_queue_controller.rb +18 -0
  9. data/app/models/taverna_player/run.rb +10 -3
  10. data/app/views/taverna_player/job_queue/index.html.erb +47 -0
  11. data/app/views/taverna_player/runs/_interaction.html.erb +7 -1
  12. data/app/views/taverna_player/runs/embedded/new.html.erb +1 -1
  13. data/config/locales/en.yml +36 -0
  14. data/config/routes.rb +4 -1
  15. data/db/migrate/20140226135723_change_taverna_player_runs_status_message_to_use_keys.rb +19 -0
  16. data/lib/generators/taverna_player/install_generator.rb +6 -1
  17. data/lib/generators/templates/ReadMe.txt +6 -0
  18. data/lib/generators/templates/controllers/job_queue_controller.rb +19 -0
  19. data/lib/generators/templates/player_initializer.rb +8 -0
  20. data/lib/tasks/delete-cancelled-runs.rake +1 -1
  21. data/lib/taverna-player.rb +9 -1
  22. data/lib/taverna_player/concerns/controllers/job_queue_controller.rb +38 -0
  23. data/lib/taverna_player/concerns/controllers/runs_controller.rb +2 -13
  24. data/lib/taverna_player/concerns/models/run.rb +22 -9
  25. data/lib/taverna_player/concerns/models/run_port.rb +5 -0
  26. data/lib/taverna_player/port_renderer.rb +1 -1
  27. data/lib/taverna_player/version.rb +1 -1
  28. data/lib/taverna_player/worker.rb +78 -51
  29. data/taverna_player.gemspec +7 -5
  30. data/test/dummy/app/views/home/index.html.erb +1 -1
  31. data/test/dummy/app/views/layouts/application.html.erb +2 -1
  32. data/test/dummy/config/application.rb +1 -0
  33. data/test/dummy/config/initializers/taverna_player.rb +8 -3
  34. data/test/dummy/config/locales/taverna_player.en.yml +36 -0
  35. data/test/dummy/db/migrate/20140226143013_change_taverna_player_runs_status_message_to_use_keys.taverna_player.rb +20 -0
  36. data/test/dummy/db/schema.rb +9 -9
  37. data/test/dummy/lib/callbacks.rb +1 -5
  38. data/test/fixtures/files/non-ascii.csv +30 -0
  39. data/test/fixtures/taverna_player/interactions.yml +4 -1
  40. data/test/fixtures/taverna_player/runs.yml +6 -1
  41. data/test/functional/taverna_player/job_queue_controller_test.rb +35 -0
  42. data/test/functional/taverna_player/runs_controller_test.rb +20 -0
  43. data/test/functional/taverna_player/service_credentials_controller_test.rb +3 -3
  44. data/test/test_helper.rb +4 -1
  45. data/test/unit/helpers/taverna_player/runs_helper_test.rb +20 -1
  46. data/test/unit/taverna_player/run_port_test.rb +41 -5
  47. data/test/unit/{utils_test.rb → taverna_player/utils_test.rb} +0 -0
  48. data/test/unit/taverna_player/worker_test.rb +201 -0
  49. metadata +67 -18
  50. data/test/fixtures/files/crassostrea_gigas.csv +0 -737
@@ -31,5 +31,8 @@ TavernaPlayer::Engine.routes.draw do
31
31
  end
32
32
  end
33
33
 
34
- resources :service_credentials
34
+ scope TavernaPlayer.admin_scope do
35
+ resources :service_credentials
36
+ get "job_queue", :controller => :job_queue, :action => "index"
37
+ end
35
38
  end
@@ -0,0 +1,19 @@
1
+ class ChangeTavernaPlayerRunsStatusMessageToUseKeys < ActiveRecord::Migration
2
+ def up
3
+ rename_column :taverna_player_runs, :status_message, :status_message_key
4
+
5
+ TavernaPlayer::Run.all.each do |run|
6
+ run.status_message_key = run.saved_state
7
+ run.save
8
+ end
9
+ end
10
+
11
+ def down
12
+ rename_column :taverna_player_runs, :status_message_key, :status_message
13
+
14
+ TavernaPlayer::Run.all.each do |run|
15
+ run.status_message = run.saved_state.capitalize
16
+ run.save
17
+ end
18
+ end
19
+ end
@@ -1,5 +1,5 @@
1
1
  #------------------------------------------------------------------------------
2
- # Copyright (c) 2013 The University of Manchester, UK.
2
+ # Copyright (c) 2013, 2014 The University of Manchester, UK.
3
3
  #
4
4
  # BSD Licenced. See LICENCE.rdoc for details.
5
5
  #
@@ -25,6 +25,11 @@ module TavernaPlayer
25
25
  "config/initializers/taverna_server.rb.example"
26
26
  end
27
27
 
28
+ def copy_locale
29
+ copy_file "../../../config/locales/en.yml",
30
+ "config/locales/taverna_player.en.yml"
31
+ end
32
+
28
33
  def show_readme
29
34
  readme "ReadMe.txt" if behavior == :invoke
30
35
  end
@@ -23,6 +23,12 @@ Taverna Player configuration, leaving the sensitive parts out.
23
23
  In your application's install instructions remember to tell your users to copy
24
24
  the example initializer and configure their Taverna Server information.
25
25
 
26
+ A locale file has also been installed to:
27
+
28
+ config/locales/taverna_player.en.yml
29
+
30
+ Please edit this to suit your application if required.
31
+
26
32
  There is also some manual setup to do, if you haven't already done it:
27
33
 
28
34
  1. Mount the Taverna Player engine in your config/routes.rb. For example:
@@ -0,0 +1,19 @@
1
+ #------------------------------------------------------------------------------
2
+ # Copyright (c) 2014 The University of Manchester, UK.
3
+ #
4
+ # BSD Licenced. See LICENCE.rdoc for details.
5
+ #
6
+ # Taverna Player was developed in the BioVeL project, funded by the European
7
+ # Commission 7th Framework Programme (FP7), through grant agreement
8
+ # number 283359.
9
+ #
10
+ # Author: Robert Haines
11
+ #------------------------------------------------------------------------------
12
+
13
+ module TavernaPlayer
14
+ class JobQueueController < TavernaPlayer::ApplicationController
15
+ # Do not remove the next line.
16
+ include TavernaPlayer::Concerns::Controllers::JobQueueController
17
+ # Extend the JobQueueControllerController here.
18
+ end
19
+ end
@@ -42,6 +42,14 @@ TavernaPlayer.setup do |config|
42
42
  # or use :rails_root for the root directory of your application.
43
43
  #config.file_store = ":rails_root/public/system"
44
44
 
45
+ # If you would like to use a different namespace for admin type resources
46
+ # you can configure it here. Defaults to the empty string.
47
+ #config.admin_scope = "admin"
48
+
49
+ # The queue name for Taverna Player's delayed jobs to be run. Whatever you
50
+ # use here be sure to start delayed job workers listening to this queue.
51
+ #config.job_queue_name = "player"
52
+
45
53
  # Callbacks to be run at various points during a workflow run. These can be
46
54
  # defined as Proc objects or as methods and referenced by name.
47
55
  #
@@ -17,7 +17,7 @@ namespace :taverna_player do
17
17
  gone = 0
18
18
  TavernaPlayer::Run.all.each do |run|
19
19
  if run.cancelled?
20
- gone += 1 #if run.destroy
20
+ gone += 1 if run.destroy
21
21
  end
22
22
  end
23
23
 
@@ -1,5 +1,5 @@
1
1
  #------------------------------------------------------------------------------
2
- # Copyright (c) 2013 The University of Manchester, UK.
2
+ # Copyright (c) 2013, 2014 The University of Manchester, UK.
3
3
  #
4
4
  # BSD Licenced. See LICENCE.rdoc for details.
5
5
  #
@@ -99,6 +99,10 @@ module TavernaPlayer
99
99
  mattr_accessor :file_store
100
100
  @@file_store = ":rails_root/public/system"
101
101
 
102
+ # Admin scope for system configuration routes.
103
+ mattr_accessor :admin_scope
104
+ @@admin_scope = ""
105
+
102
106
  # Taverna server polling interval (in seconds)
103
107
  mattr_accessor :server_poll_interval
104
108
  @@server_poll_interval = 5
@@ -111,6 +115,10 @@ module TavernaPlayer
111
115
  mattr_accessor :server_connection
112
116
  @@server_connection = T2Server::DefaultConnectionParameters.new
113
117
 
118
+ # Queue on which to create workflow execution jobs
119
+ mattr_accessor :job_queue_name
120
+ @@job_queue_name = "player"
121
+
114
122
  # Pre run callback
115
123
  mattr_accessor :pre_run_callback
116
124
  @@pre_run_callback = nil
@@ -0,0 +1,38 @@
1
+ #------------------------------------------------------------------------------
2
+ # Copyright (c) 2014 The University of Manchester, UK.
3
+ #
4
+ # BSD Licenced. See LICENCE.rdoc for details.
5
+ #
6
+ # Taverna Player was developed in the BioVeL project, funded by the European
7
+ # Commission 7th Framework Programme (FP7), through grant agreement
8
+ # number 283359.
9
+ #
10
+ # Author: Robert Haines
11
+ #------------------------------------------------------------------------------
12
+
13
+ module TavernaPlayer
14
+ module Concerns
15
+ module Controllers
16
+ module JobQueueController
17
+
18
+ extend ActiveSupport::Concern
19
+
20
+ included do
21
+ respond_to :html
22
+
23
+ before_filter :find_jobs
24
+
25
+ def find_jobs
26
+ @jobs = Delayed::Job.find_all_by_queue(TavernaPlayer.job_queue_name)
27
+ end
28
+ end # included
29
+
30
+ # GET job_queue
31
+ def index
32
+
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -32,8 +32,6 @@ module TavernaPlayer
32
32
  before_filter :filter_update_parameters, :only => :update
33
33
  before_filter :find_interaction, :only => [ :read_interaction, :write_interaction ]
34
34
 
35
- layout :choose_layout
36
-
37
35
  private
38
36
 
39
37
  def find_runs
@@ -87,15 +85,6 @@ module TavernaPlayer
87
85
  send_data @port.value, :type => type, :filename => @port.filename
88
86
  end
89
87
 
90
- # Choose a layout for the page depending on action and embedded status.
91
- def choose_layout
92
- if (action_name == "new" || action_name == "show") && @run.embedded?
93
- "taverna_player/embedded"
94
- else
95
- ApplicationController.new.send(:_layout).virtual_path
96
- end
97
- end
98
-
99
88
  end # included
100
89
 
101
90
  # GET /runs
@@ -119,7 +108,7 @@ module TavernaPlayer
119
108
  respond_with(@run) do |format|
120
109
  # Render show.{html|js}.erb unless the run is embedded.
121
110
  format.any(:html, :js) do
122
- render "taverna_player/runs/embedded/show" if @run.embedded
111
+ render "taverna_player/runs/embedded/show", :layout => "taverna_player/embedded" if @run.embedded
123
112
  end
124
113
  end
125
114
  end
@@ -129,7 +118,7 @@ module TavernaPlayer
129
118
  respond_with(@run) do |format|
130
119
  # Render new.html.erb unless the run is embedded.
131
120
  format.html do
132
- render "taverna_player/runs/embedded/new" if @run.embedded
121
+ render "taverna_player/runs/embedded/new", :layout => "taverna_player/embedded" if @run.embedded
133
122
  end
134
123
  end
135
124
  end
@@ -1,5 +1,5 @@
1
1
  #------------------------------------------------------------------------------
2
- # Copyright (c) 2013 The University of Manchester, UK.
2
+ # Copyright (c) 2013, 2014 The University of Manchester, UK.
3
3
  #
4
4
  # BSD Licenced. See LICENCE.rdoc for details.
5
5
  #
@@ -20,7 +20,7 @@ module TavernaPlayer
20
20
  included do
21
21
  attr_accessible :create_time, :delayed_job, :embedded, :finish_time,
22
22
  :inputs_attributes, :log, :name, :parent_id, :results, :run_id,
23
- :start_time, :status_message, :user_id, :workflow_id
23
+ :start_time, :status_message_key, :user_id, :workflow_id
24
24
 
25
25
  # Each run is spawned from a workflow. This provides the link to the
26
26
  # workflow model in the parent app, whatever it calls its model.
@@ -48,7 +48,8 @@ module TavernaPlayer
48
48
 
49
49
  accepts_nested_attributes_for :inputs
50
50
 
51
- STATES = ["pending", "initialized", "running", "finished", "cancelled", "failed"]
51
+ STATES = ["pending", "initialized", "running", "finished",
52
+ "cancelled", "timeout", "failed"]
52
53
 
53
54
  validates :workflow_id, :presence => true
54
55
  validates :name, :presence => true
@@ -65,18 +66,20 @@ module TavernaPlayer
65
66
  # needs to be checked on update because on create we don't have an
66
67
  # id for ourself.
67
68
  validates :parent_id, :numericality => { :less_than => :id,
68
- :message => "Parents must have lower ids than children" },
69
+ :message => I18n.t("taverna_player.errors.invalid-parent") },
69
70
  :allow_nil => true, :on => :update
70
71
 
71
72
  has_attached_file :log,
72
73
  :path => File.join(TavernaPlayer.file_store, ":class/:attachment/:id/:filename"),
73
74
  :url => "/runs/:id/download/log",
74
75
  :default_url => ""
76
+ do_not_validate_attachment_file_type :log
75
77
 
76
78
  has_attached_file :results,
77
79
  :path => File.join(TavernaPlayer.file_store, ":class/:attachment/:id/:filename"),
78
80
  :url => "/runs/:id/download/results",
79
81
  :default_url => ""
82
+ do_not_validate_attachment_file_type :results
80
83
 
81
84
  after_initialize :initialize_child_run, :if => "new_record? && has_parent?"
82
85
  after_create :populate_child_inputs, :if => :has_parent?
@@ -106,8 +109,8 @@ module TavernaPlayer
106
109
 
107
110
  def enqueue
108
111
  worker = TavernaPlayer::Worker.new(self)
109
- job = Delayed::Job.enqueue worker, :queue => "player"
110
- update_attributes(:delayed_job => job, :status_message => "Queued")
112
+ job = Delayed::Job.enqueue worker, :queue => TavernaPlayer.job_queue_name
113
+ update_attributes(:delayed_job => job, :status_message_key => "pending")
111
114
  end
112
115
 
113
116
  end # included
@@ -144,7 +147,7 @@ module TavernaPlayer
144
147
  if delayed_job.locked_by.nil?
145
148
  delayed_job.destroy
146
149
  update_attribute(:saved_state, "cancelled")
147
- update_attribute(:status_message, "Cancelled")
150
+ update_attribute(:status_message_key, "cancelled")
148
151
  end
149
152
  end
150
153
  end
@@ -173,6 +176,11 @@ module TavernaPlayer
173
176
  self[:saved_state] = s
174
177
  end
175
178
 
179
+ def status_message
180
+ key = status_message_key.nil? ? saved_state : status_message_key
181
+ I18n.t("taverna_player.status.#{key}")
182
+ end
183
+
176
184
  def running?
177
185
  state == :running
178
186
  end
@@ -189,13 +197,18 @@ module TavernaPlayer
189
197
  state == :cancelling
190
198
  end
191
199
 
200
+ def timeout?
201
+ state == :timeout
202
+ end
203
+
192
204
  def failed?
193
205
  state == :failed
194
206
  end
195
207
 
196
- # This is used as a catch-all for finished, cancelled and failed
208
+ # This is used as a catch-all for finished, cancelled, failed and
209
+ # timeout
197
210
  def complete?
198
- finished? || cancelled? || failed?
211
+ finished? || cancelled? || failed? || timeout?
199
212
  end
200
213
 
201
214
  def has_parent?
@@ -37,6 +37,7 @@ module TavernaPlayer
37
37
  :path => File.join(TavernaPlayer.file_store, ":class/:attachment/:id/:filename"),
38
38
  :url => :file_url_via_run,
39
39
  :default_url => ""
40
+ do_not_validate_attachment_file_type :file
40
41
 
41
42
  default_scope order("lower(name) ASC")
42
43
 
@@ -159,6 +160,10 @@ module TavernaPlayer
159
160
  end
160
161
  end
161
162
 
163
+ def value=(v)
164
+ self[:value] = v.force_encoding("BINARY")
165
+ end
166
+
162
167
  def path(*indices)
163
168
  index = [*indices].flatten
164
169
  path = index.empty? ? "" : "/" + index.join("/")
@@ -53,7 +53,7 @@ module TavernaPlayer
53
53
 
54
54
  @hash[type.media_type] ||= {}
55
55
  @hash[type.media_type][type.sub_type] = method
56
- @hash[type.media_type][:default] = method if default
56
+ type_default(type.media_type, method) if default
57
57
  end
58
58
 
59
59
  # :call-seq:
@@ -11,5 +11,5 @@
11
11
  #------------------------------------------------------------------------------
12
12
 
13
13
  module TavernaPlayer
14
- VERSION = "0.5.0"
14
+ VERSION = "0.6.0"
15
15
  end
@@ -15,12 +15,16 @@ module TavernaPlayer
15
15
  include TavernaPlayer::Concerns::Callback
16
16
  include TavernaPlayer::Concerns::Zip
17
17
 
18
+ attr_reader :run
19
+
18
20
  # How to get the interaction presentation frame out of the interaction page.
19
21
  INTERACTION_REGEX = /document\.getElementById\(\'presentationFrame\'\)\.src = \"(.+)\";/
20
22
 
21
- def initialize(run)
23
+ # The workflow file to be run can be specified explicitly or it will be
24
+ # taken from the workflow model.
25
+ def initialize(run, workflow_file = nil)
22
26
  @run = run
23
- @workflow = TavernaPlayer.workflow_proxy.class_name.find(@run.workflow_id)
27
+ @workflow = workflow_file || TavernaPlayer.workflow_proxy.file(@run.workflow)
24
28
  end
25
29
 
26
30
  # This tells delayed_job to only try and complete each run once.
@@ -29,12 +33,9 @@ module TavernaPlayer
29
33
  end
30
34
 
31
35
  def perform
32
- unless TavernaPlayer.pre_run_callback.nil?
33
- status_message "Running pre-run tasks"
34
- callback(TavernaPlayer.pre_run_callback, @run)
35
- end
36
+ return unless run_callback(TavernaPlayer.pre_run_callback, "pre-callback")
36
37
 
37
- status_message "Connecting to Taverna Server"
38
+ status_message("connect")
38
39
 
39
40
  server_uri = URI.parse(TavernaPlayer.server_address)
40
41
  credentials = T2Server::HttpBasic.new(TavernaPlayer.server_username,
@@ -43,14 +44,14 @@ module TavernaPlayer
43
44
 
44
45
  begin
45
46
  server = T2Server::Server.new(server_uri, conn_params)
46
- wkf = File.read(TavernaPlayer.workflow_proxy.file(@workflow))
47
+ wkf = File.read(@workflow)
47
48
 
48
49
  # Try and create the run bearing in mind that the server might be at
49
50
  # the limit of runs that it can hold at once.
50
51
  begin
51
52
  run = server.create_run(wkf, credentials)
52
53
  rescue T2Server::ServerAtCapacityError
53
- status_message "Server full - please wait; run will start soon"
54
+ status_message("full")
54
55
 
55
56
  if cancelled?
56
57
  cancel
@@ -61,7 +62,7 @@ module TavernaPlayer
61
62
  retry
62
63
  end
63
64
 
64
- status_message "Initializing new workflow run"
65
+ status_message("initialized")
65
66
 
66
67
  @run.run_id = run.id
67
68
  @run.state = run.status
@@ -69,7 +70,7 @@ module TavernaPlayer
69
70
  @run.save
70
71
 
71
72
  unless @run.inputs.size == 0
72
- status_message "Uploading run inputs"
73
+ status_message("inputs")
73
74
  @run.inputs.each do |input|
74
75
  unless input.file.blank?
75
76
  run.input_port(input.name).file = input.file.path
@@ -84,13 +85,13 @@ module TavernaPlayer
84
85
  run.add_password_credential(cred.uri, cred.login, cred.password)
85
86
  end
86
87
 
87
- status_message "Starting run"
88
+ status_message("start")
88
89
  run.name = @run.name
89
90
 
90
91
  # Try and start the run bearing in mind that the server might be at
91
92
  # the limit of runs that it can run at once.
92
93
  while !run.start
93
- status_message "Server busy - please wait; run will start soon"
94
+ status_message("busy")
94
95
 
95
96
  if cancelled?
96
97
  cancel(run)
@@ -104,7 +105,7 @@ module TavernaPlayer
104
105
  @run.start_time = run.start_time
105
106
  @run.save
106
107
 
107
- status_message "Running"
108
+ status_message("running")
108
109
  until run.finished?
109
110
  sleep(TavernaPlayer.server_poll_interval)
110
111
  waiting = false
@@ -116,7 +117,7 @@ module TavernaPlayer
116
117
 
117
118
  run.notifications(:requests).each do |note|
118
119
  if @run.has_parent?
119
- next if note.has_reply?
120
+ next if note.has_reply? || note.is_notification?
120
121
  int = Interaction.find_by_run_id_and_serial(@run.parent_id, note.serial)
121
122
  new_int = Interaction.find_or_initialize_by_run_id_and_serial(@run.id, note.serial)
122
123
  if new_int.new_record?
@@ -154,6 +155,10 @@ module TavernaPlayer
154
155
  end
155
156
  end
156
157
 
158
+ if note.is_notification? && !int.new_record?
159
+ int.replied = true
160
+ end
161
+
157
162
  if int.data.blank?
158
163
  int.data = note.input_data.force_encoding("UTF-8")
159
164
  end
@@ -169,10 +174,10 @@ module TavernaPlayer
169
174
  end
170
175
  end
171
176
 
172
- status_message(waiting ? "Waiting for user input" : "Running")
177
+ status_message(waiting ? "interact" : "running")
173
178
  end
174
179
 
175
- status_message "Gathering run outputs and log"
180
+ status_message("outputs")
176
181
  download_outputs(run)
177
182
  download_log(run)
178
183
 
@@ -182,41 +187,35 @@ module TavernaPlayer
182
187
 
183
188
  run.delete
184
189
  rescue => exception
185
- begin
186
- unless run.nil?
187
- download_log(run)
188
- run.delete
189
- end
190
- rescue
191
- # Try and grab the log then delete the run from Taverna Server here,
192
- # but at this point we don't care if we fail...
193
- end
194
-
195
- unless TavernaPlayer.run_failed_callback.nil?
196
- status_message "Running post-failure tasks"
197
- callback(TavernaPlayer.run_failed_callback, @run)
198
- end
199
-
200
- backtrace = exception.backtrace.join("\n")
201
- @run.failure_message = "#{exception.message}\n#{backtrace}"
202
-
203
- @run.state = :failed
204
- @run.finish_time = Time.now
205
- status_message "Failed"
190
+ failed(exception, run)
206
191
  return
207
192
  end
208
193
 
209
- unless TavernaPlayer.post_run_callback.nil?
210
- status_message "Running post-run tasks"
211
- callback(TavernaPlayer.post_run_callback, @run)
212
- end
194
+ return unless run_callback(TavernaPlayer.post_run_callback, "post-callback")
213
195
 
214
196
  @run.state = :finished
215
- status_message "Finished"
197
+ status_message("finished")
216
198
  end
217
199
 
218
200
  private
219
201
 
202
+ # Run the specified callback and return false on error so that we know to
203
+ # return out of the worker code completely.
204
+ def run_callback(cb, message)
205
+ unless cb.nil?
206
+ status_message(message)
207
+ begin
208
+ callback(cb, @run)
209
+ rescue => exception
210
+ failed(exception)
211
+ return false
212
+ end
213
+ end
214
+
215
+ # no errors
216
+ true
217
+ end
218
+
220
219
  def download_log(run)
221
220
  Dir.mktmpdir(run.id, Rails.root.join("tmp")) do |tmp_dir|
222
221
  tmp_file_name = File.join(tmp_dir, "log.txt")
@@ -282,8 +281,8 @@ module TavernaPlayer
282
281
  File.new(tmp_file)
283
282
  end
284
283
 
285
- def status_message(message)
286
- @run.status_message = message
284
+ def status_message(key)
285
+ @run.status_message_key = key
287
286
  @run.save!
288
287
  end
289
288
 
@@ -295,21 +294,49 @@ module TavernaPlayer
295
294
  end
296
295
 
297
296
  def cancel(run = nil)
298
- status_message "Cancelling"
297
+ status_message("cancel")
299
298
 
300
299
  unless run.nil?
301
300
  download_log(run)
302
301
  run.delete
303
302
  end
304
303
 
305
- unless TavernaPlayer.run_cancelled_callback.nil?
306
- status_message "Running post-cancel tasks"
307
- callback(TavernaPlayer.run_cancelled_callback, @run)
308
- end
304
+ return unless run_callback(TavernaPlayer.run_cancelled_callback, "cancel-callback")
309
305
 
310
306
  @run.state = :cancelled
311
307
  @run.finish_time = Time.now
312
- status_message "Cancelled"
308
+ status_message("cancelled")
309
+ end
310
+
311
+ def failed(exception, run = nil)
312
+ begin
313
+ unless run.nil?
314
+ download_log(run)
315
+ run.delete
316
+ end
317
+ rescue
318
+ # Try and grab the log then delete the run from Taverna Server here,
319
+ # but at this point we don't care if we fail...
320
+ end
321
+
322
+ unless TavernaPlayer.run_failed_callback.nil?
323
+ status_message("fail-callback")
324
+
325
+ begin
326
+ callback(TavernaPlayer.run_failed_callback, @run)
327
+ rescue
328
+ # Again, nothing we can really do here, so...
329
+ end
330
+ end
331
+
332
+ backtrace = exception.backtrace.join("\n")
333
+ @run.failure_message = "#{exception.message}\n#{backtrace}"
334
+
335
+ @run.finish_time = Time.now
336
+
337
+ state = exception.instance_of?(Delayed::WorkerTimeout) ? :timeout : :failed
338
+ @run.state = state
339
+ status_message(state.to_s)
313
340
  end
314
341
 
315
342
  end