rbbt-util 5.19.35 → 5.19.36

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 71c4c5187485430e7ea4977a2a46002f2a5caa81
4
- data.tar.gz: 60e13741b32e65b17e63621a0dcdd021b467b2ff
3
+ metadata.gz: 72a73b569032a1fce45e26a98b2e5e57c1abd83c
4
+ data.tar.gz: 1bb8e14d02dbc52654120389c6c1ff303ec25d05
5
5
  SHA512:
6
- metadata.gz: 70760328e15502ce16d06483def0e5d6c7ee75d20d33e7891666e2a10c8cebb275a5a277be0afd0810fdecfa99f3d27ee48ddf93335b52caa94f629102fac250
7
- data.tar.gz: 7310fddb61cc783289304aabd83b77bf47b2666d1f31ba90a7d15c91b701016b3272d2d2a7503b8b3697fd62a56278e420be3caf81efdfcf3f18c6bf629e138f
6
+ metadata.gz: 6126957c9cb71705cfa47105941752e32033b714e7972dac3b211179c0e23c3c7e7a7d693922f0c7bc141e9c4955b15936ebd1418daa80150fdab5ef950c07cb
7
+ data.tar.gz: 263a74be39a0ed6e0fee8d2e3c913f77767744fc54b4c0e7d5c469013ef1bd48cf134b5efbcb1c00aacd036a174a552ec2260a64f75156744f5bed1324a9089a
data/etc/app.d/base.rb CHANGED
@@ -1,9 +1,13 @@
1
1
  #{{{ MODULES AND HELPERS
2
+ register Sinatra::MultiRoute
2
3
 
3
4
  register Sinatra::RbbtRESTMain
4
5
  register Sinatra::RbbtRESTEntity
5
6
  register Sinatra::RbbtRESTFileServer # Remove to prevent serving files
6
7
  register Sinatra::RbbtRESTKnowledgeBase
8
+ register Sinatra::RbbtRESTWorkflow
9
+
10
+ helpers Sinatra::RbbtToolHelper
7
11
  helpers Sinatra::RbbtMiscHelpers
8
12
 
9
13
  #{{{ SESSIONS
data/etc/app.d/init.rb CHANGED
@@ -5,3 +5,4 @@ require 'rbbt/rest/entity'
5
5
  require 'rbbt/rest/workflow'
6
6
  require 'rbbt/rest/file_server'
7
7
  require 'rbbt/rest/helpers'
8
+ require 'rbbt/rest/web_tool'
@@ -230,6 +230,7 @@ module Annotation
230
230
  end
231
231
 
232
232
  def clean_and_setup_hash(object, hash)
233
+ object.instance_variable_set(:@annotation_values, nil) if object.instance_variable_get(:@annotation_values).nil?
233
234
  annotation_values = object.instance_variable_get(:@annotation_values)
234
235
  annotation_values = annotation_values.nil? ? {} : annotation_values.dup
235
236
  annotation_values.instance_variable_set(:@annotation_md5, nil)
@@ -83,13 +83,18 @@ class WorkflowRESTClient
83
83
  end
84
84
 
85
85
  def self.post_jobname(url, params = {})
86
+ Log.stack caller
86
87
  Log.debug{ "RestClient post_jobname: #{ url } - #{Misc.fingerprint params}" }
87
88
  params = params.merge({ :_format => 'jobname' })
88
89
  params = fix_params params
89
90
 
90
- capture_exception do
91
+ name = capture_exception do
91
92
  RestClient.post(URI.encode(url), params)
92
93
  end
94
+
95
+ Log.debug{ "RestClient post_jobname: #{ url } - #{Misc.fingerprint params}: #{name}" }
96
+
97
+ name
93
98
  end
94
99
 
95
100
  def self.post_json(url, params = {})
@@ -1,30 +1,36 @@
1
- require 'excon'
2
1
  class WorkflowRESTClient
3
2
  class RemoteStep < Step
4
3
 
5
4
  attr_accessor :url, :base_url, :task, :base_name, :inputs, :result_type, :result_description, :is_exec
6
5
 
7
6
  def self.get_streams(inputs)
7
+ new_inputs = {}
8
8
  inputs.each do |k,v|
9
- if Step === v
10
- stream = v.get_stream
11
- inputs[k] = stream || v.run
9
+ if Step === v or RemoteStep === v
10
+ v.run
11
+ new_inputs[k] = v.load
12
+ else
13
+ new_inputs[k] = v
12
14
  end
13
15
  end
16
+ new_inputs
14
17
  end
15
18
 
19
+
16
20
  def initialize(base_url, task = nil, base_name = nil, inputs = nil, result_type = nil, result_description = nil, is_exec = false)
17
21
  @base_url, @task, @base_name, @inputs, @result_type, @result_description, @is_exec = base_url, task, base_name, inputs, result_type, result_description, is_exec
18
22
  @mutex = Mutex.new
19
- RemoteStep.get_streams @inputs
23
+ @inputs = RemoteStep.get_streams @inputs
20
24
  end
21
25
 
22
26
  def name
23
27
  return nil if @is_exec
28
+ return @path if @url.nil?
24
29
  (Array === @url ? @url.first : @url).split("/").last
25
30
  end
26
31
 
27
32
  def task_name
33
+ return task unless @url
28
34
  init_job
29
35
  (Array === @url ? @url.first : @url).split("/")[-2]
30
36
  end
@@ -41,6 +47,7 @@ class WorkflowRESTClient
41
47
  end
42
48
 
43
49
  def status
50
+ return nil if @url.nil?
44
51
  begin
45
52
  info[:status]
46
53
  ensure
@@ -82,8 +89,11 @@ class WorkflowRESTClient
82
89
  end
83
90
 
84
91
  def path
85
- init_job
86
- @url + '?_format=raw'
92
+ if @url
93
+ @url + '?_format=raw'
94
+ else
95
+ [base_url, task, Misc.fingerprint(inputs)] * "/"
96
+ end
87
97
  end
88
98
 
89
99
  def run(noload = false)
@@ -99,6 +109,7 @@ class WorkflowRESTClient
99
109
  end
100
110
  end
101
111
  end
112
+
102
113
  return @result if noload == :stream
103
114
  noload ? path + '?_format=raw' : @result
104
115
  end
@@ -186,7 +197,18 @@ class WorkflowRESTClient
186
197
  RestClient::Request.execute(:method => :post, :url => url, :payload => task_params, :block_response => bl)
187
198
  end
188
199
 
189
- Zlib::GzipReader.new(sout)
200
+ reader = Zlib::GzipReader.new(sout)
201
+ Misc.open_pipe do |sin|
202
+ while c = reader.read(1015)
203
+ sin.write c
204
+ end
205
+ sin.close
206
+ @done = true
207
+ end
208
+ #nsout, nsin = Misc.pipe
209
+ #Misc.consume_stream(reader, true, nsin, true) do @done = true end
210
+ #iii :ret
211
+ #nsout
190
212
  end
191
213
  end
192
214
 
@@ -19,6 +19,7 @@ module TSV
19
19
  end
20
20
 
21
21
  def entity_options
22
+ @entity_options ||= nil
22
23
  if @entity_options.nil?
23
24
  @entity_options = namespace ? {:namespace => namespace, :organism => namespace} : {}
24
25
  @entity_templates = nil
@@ -122,7 +123,7 @@ module TSV
122
123
  end
123
124
 
124
125
  def write?
125
- @writable
126
+ @writable ||= false
126
127
  end
127
128
 
128
129
  def self._extended(data)
data/lib/rbbt/tsv/util.rb CHANGED
@@ -133,13 +133,17 @@ module TSV
133
133
  StringIO.new file
134
134
  end
135
135
  when (defined? Step and Step)
136
- file.grace
137
- stream = file.get_stream
138
- if stream
139
- stream
136
+ if file.respond_to?(:base_url) and file.result
137
+ file.result
140
138
  else
141
- file.join
142
- get_stream(file.path)
139
+ file.grace
140
+ stream = file.get_stream
141
+ if stream
142
+ stream
143
+ else
144
+ file.join
145
+ get_stream(file.path)
146
+ end
143
147
  end
144
148
  when Array
145
149
  Misc.open_pipe do |sin|
@@ -10,6 +10,14 @@ module R
10
10
  sources = [:plot, Rbbt.share.Rlib["svg.R"].find(:lib), options[:source]].flatten.compact
11
11
  options.delete :source
12
12
 
13
+ fast = options[:fast]
14
+
15
+ if fast
16
+ save_method = "rbbt.SVG.save.fast"
17
+ else
18
+ save_method = "rbbt.SVG.save"
19
+ end
20
+
13
21
  if data
14
22
  data.each do |k,v|
15
23
  v = Array === v ? v : [v]
@@ -48,7 +56,7 @@ module R
48
56
  data.R <<-EOF, sources, options
49
57
  plot = { #{script} }
50
58
 
51
- rbbt.SVG.save('#{tmpfile}', plot, width = #{R.ruby2R width}, height = #{R.ruby2R height})
59
+ #{save_method}('#{tmpfile}', plot, width = #{R.ruby2R width}, height = #{R.ruby2R height})
52
60
  data = NULL
53
61
  EOF
54
62
 
@@ -61,7 +69,7 @@ module R
61
69
  R.run <<-EOF, sources, options
62
70
  plot = { #{script} }
63
71
 
64
- rbbt.SVG.save('#{tmpfile}', plot, width = #{R.ruby2R width}, height = #{R.ruby2R height})
72
+ #{save_method}('#{tmpfile}', plot, width = #{R.ruby2R width}, height = #{R.ruby2R height})
65
73
  data = NULL
66
74
  EOF
67
75
  Open.read(tmpfile).gsub(/(glyph\d+-\d+)/, '\1-' + File.basename(tmpfile))
@@ -70,7 +70,7 @@ class RbbtProcessQueue
70
70
 
71
71
  initial = Misc.memory_use(Process.pid)
72
72
  memory_cap = multiplier * initial
73
- Log.medium "Worker #{Process.pid} started with #{@current} -- initial: #{initial} - multiplier: #{multiplier} - cap: #{memory_cap}"
73
+ Log.medium "Worker for #{Process.pid} started with pid #{@current} -- initial: #{initial} - multiplier: #{multiplier} - cap: #{memory_cap}"
74
74
 
75
75
  @monitor_thread = Thread.new do
76
76
  begin
data/lib/rbbt/util/log.rb CHANGED
@@ -90,7 +90,7 @@ module Log
90
90
 
91
91
  def self.logfile(file=nil)
92
92
  if file.nil?
93
- @logfile
93
+ @logfile ||= nil
94
94
  else
95
95
  case file
96
96
  when String
@@ -104,7 +104,7 @@ module Log
104
104
  end
105
105
 
106
106
  def save
107
- info = {:start => @start, :last_time => @last_time, :last_count => @last_count, :last_percent => @last_percent, :desc => @desc, :ticks => @ticks, :max => @max}
107
+ info = {:start => @start, :last_time => @last_time, :last_count => @last_count, :last_percent => @last_percent, :desc => @desc, :ticks => @ticks, :max => @max, :mean => @mean}
108
108
  Open.write(@file, info.to_yaml)
109
109
  end
110
110
 
@@ -8,6 +8,8 @@ class Aborted < Exception; end
8
8
 
9
9
  class RemoteServerError < Exception; end
10
10
 
11
+ class DependencyError < Exception; end
12
+
11
13
  class KeepLocked < Exception
12
14
  attr_accessor :payload
13
15
  def initialize(payload)
@@ -208,7 +208,7 @@ module Misc
208
208
  'false'
209
209
  when Hash
210
210
  "{"<< obj.collect{|k,v| obj2str(k) + '=>' << obj2str(v)}*"," << "}"
211
- when Symbol
211
+ when Symbol
212
212
  obj.to_s
213
213
  when String
214
214
  if obj.length > HASH2MD5_MAX_STRING_LENGTH
@@ -0,0 +1,138 @@
1
+ require 'net/http'
2
+ require 'rbbt-util'
3
+
4
+ class Net::HTTPGenericRequest
5
+ alias old_send_request_with_body_stream send_request_with_body_stream
6
+
7
+ def send_request_with_body_stream(*args)
8
+ if chunked?
9
+ Thread.new do
10
+ old_send_request_with_body_stream(*args)
11
+ end
12
+ else
13
+ old_send_request_with_body_stream(*args)
14
+ end
15
+ end
16
+ end
17
+
18
+ module RbbtMutiplartPayload
19
+ BOUNDARY = "Rbbt_Param_Stream"
20
+ EOL = "\r\n"
21
+
22
+ def self.input_header(name, filename = nil)
23
+
24
+ if filename
25
+ head_text = 'Content-Disposition: form-data; name="' + name + '"; filename="' + filename + '"'
26
+ else
27
+ head_text = 'Content-Disposition: form-data; name="' + name + '"'
28
+ end
29
+
30
+ content_transfer_text = "Content-Transfer-Encoding: binary"
31
+
32
+ content_type_text = 'Content-Type: text/plain'
33
+
34
+ head_text + EOL + content_transfer_text + EOL + content_type_text + EOL
35
+ end
36
+
37
+ def self.add_input(name, content, filename = nil)
38
+ header = input_header(name, filename)
39
+ "--" + BOUNDARY + EOL + header + EOL + content + EOL
40
+ end
41
+
42
+ def self.add_stream(io, name, content, filename = nil)
43
+ header = input_header(name, filename)
44
+ io.write "--" + BOUNDARY + EOL + header + EOL + EOL
45
+
46
+ while c = content.read(1024)
47
+ io.write c
48
+ end
49
+ content.close
50
+ end
51
+
52
+ def self.close_stream(io)
53
+ io.write "--" + BOUNDARY + "--" + EOL + EOL
54
+ io.write EOL
55
+ io.close
56
+ end
57
+
58
+ def self.post_data_stream(inputs = nil, stream_input = nil, stream_io = nil, stream_filename = nil)
59
+ sout, sin = Misc.pipe
60
+
61
+ Thread.new do
62
+ inputs.each do |input,content|
63
+ input = input.to_s
64
+ next if stream_input and input == stream_input.to_s
65
+ content_str = case content
66
+ when String
67
+ if Misc.is_filename?(content) and File.exists?(content)
68
+ File.read(content)
69
+ else
70
+ content
71
+ end
72
+ when File, IO
73
+ content.read
74
+ when nil
75
+ "nil"
76
+ else
77
+ content.to_s
78
+ end
79
+ str = RbbtMutiplartPayload.add_input(input, content_str)
80
+ sin.write str
81
+ end
82
+
83
+ RbbtMutiplartPayload.add_stream(sin, stream_input.to_s, stream_io, stream_filename) if stream_input
84
+ RbbtMutiplartPayload.close_stream(sin)
85
+ end
86
+
87
+ sout
88
+ end
89
+
90
+ def self.issue(url, inputs = nil, stream_input = nil, stream_io = nil, stream_filename = nil)
91
+
92
+ uri = URI(url)
93
+ req = Net::HTTP::Post.new(uri.path)
94
+
95
+ IndiferentHash.setup(inputs)
96
+
97
+ if stream_input
98
+ stream_io ||= TSV.get_stream inputs[stream_input]
99
+ stream_filename ||= case inputs[stream_input]
100
+ when String
101
+ inputs[stream_input]
102
+ when File
103
+ inputs[stream_input].filename
104
+ else
105
+ 'file'
106
+ end
107
+ end
108
+
109
+ sout = RbbtMutiplartPayload.post_data_stream inputs, stream_input, stream_io, stream_filename
110
+
111
+ if stream_input
112
+ req.content_type = "multipart/form-data; boundary=" + RbbtMutiplartPayload::BOUNDARY + '; stream=' + stream_input.to_s
113
+ req.body_stream = sout
114
+ req.add_field "Transfer-Encoding", "chunked"
115
+ else
116
+ req.content_type = "multipart/form-data; boundary=" + RbbtMutiplartPayload::BOUNDARY
117
+ req.body = sout.read
118
+ end
119
+
120
+ Misc.open_pipe do |sin|
121
+ Net::HTTP.start(uri.hostname, uri.port) do |http|
122
+ http.request(req) do |res|
123
+ if Net::HTTPRedirection === res
124
+ sin.write res["location"]
125
+ elsif stream_input
126
+ res.read_body do |c|
127
+ sin.write c
128
+ end
129
+ else
130
+ sin.write res.body
131
+ end
132
+ sin.close
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ end
@@ -159,7 +159,7 @@ module Misc
159
159
  str
160
160
  end
161
161
 
162
- def self.consume_stream(io, in_thread = false, into = nil, into_close = true)
162
+ def self.consume_stream(io, in_thread = false, into = nil, into_close = true, &block)
163
163
  return if Path === io
164
164
  return unless io.respond_to? :read
165
165
  if io.respond_to? :closed? and io.closed?
@@ -189,6 +189,7 @@ module Misc
189
189
  io.close unless io.closed?
190
190
  into.close if into and into_close and not into.closed?
191
191
  into.join if into and into_close and into.respond_to?(:joined?) and not into.joined?
192
+ block.call if block_given?
192
193
  rescue Aborted
193
194
  Log.medium "Consume stream aborted #{Misc.fingerprint io}"
194
195
  io.abort if io.respond_to? :abort
@@ -38,6 +38,10 @@ class Step
38
38
  path.nil? ? nil : path + '.info'
39
39
  end
40
40
 
41
+ def self.pid_file(path)
42
+ path.nil? ? nil : path + '.pid'
43
+ end
44
+
41
45
  def self.step_info(path)
42
46
  begin
43
47
  Open.open(info_file(path)) do |f|
@@ -61,6 +65,10 @@ class Step
61
65
  path.sub(/.*\/#{Regexp.quote task.name.to_s}\/(.*)/, '\1')
62
66
  end
63
67
 
68
+ def short_path
69
+ [task_name, name] * "/"
70
+ end
71
+
64
72
  def task_name
65
73
  @task_name ||= task.name
66
74
  end
@@ -71,6 +79,10 @@ class Step
71
79
  @info_file ||= Step.info_file(path)
72
80
  end
73
81
 
82
+ def pid_file
83
+ @pid_file ||= Step.pid_file(path)
84
+ end
85
+
74
86
  def info_lock
75
87
  @info_lock = begin
76
88
  path = Persist.persistence_path(info_file + '.lock', {:dir => Step.lock_dir})
@@ -118,6 +130,16 @@ class Step
118
130
  end
119
131
  end
120
132
 
133
+ def init_info
134
+ return nil if @exec or info_file.nil?
135
+ Open.lock(info_file, :lock => info_lock) do
136
+ i = {:status => :init}
137
+ @info_cache = i
138
+ Misc.sensiblewrite(info_file, INFO_SERIALIAZER.dump(i), :force => true, :lock => false)
139
+ @info_cache_time = Time.now
140
+ end
141
+ end
142
+
121
143
  def set_info(key, value)
122
144
  return nil if @exec or info_file.nil?
123
145
  value = Annotated.purge value if defined? Annotated
@@ -286,7 +308,7 @@ class Step
286
308
  end
287
309
 
288
310
  def started?
289
- Open.exists? info_file or Open.exists? path
311
+ Open.exists?(path) or Open.exists?(pid_file)
290
312
  end
291
313
 
292
314
  def dirty?
@@ -302,7 +324,7 @@ class Step
302
324
  end
303
325
 
304
326
  def running?
305
- return nil if not Open.exists? info_file
327
+ return nil if not Open.exists? pid_file
306
328
  return nil if info[:pid].nil?
307
329
 
308
330
  pid = @pid || info[:pid]
@@ -468,13 +490,22 @@ module Workflow
468
490
  deps.each do |dep|
469
491
  case dep
470
492
  when Array
471
- wf, t = dep
493
+ wf, t, o = dep
472
494
  wf.rec_dependencies(t).each do |d|
473
495
  if Array === d
474
- all_deps << d
496
+ new = d
475
497
  else
476
- all_deps << [dep.first, d]
498
+ new = [dep.first, d]
499
+ end
500
+ if Hash === o and not o.empty?
501
+ if Hash === new.last
502
+ hash = new.last
503
+ o.each{|k,v| hash[k] ||= v}
504
+ else
505
+ new.push o
506
+ end
477
507
  end
508
+ all_deps << new
478
509
  end
479
510
  when String, Symbol
480
511
  all_deps.concat rec_dependencies(dep.to_sym)
@@ -59,7 +59,7 @@ module Workflow
59
59
  (defined? WorkflowRESTClient and WorkflowRESTClient === dependency.first) or
60
60
  Hash === dependency.last
61
61
 
62
- dependency = ([self] + dependency) unless Module === dependency.first
62
+ dependency = ([self] + dependency) unless Module === dependency.first or (defined? WorkflowRESTClient and WorkflowRESTClient === dependency.first)
63
63
  @dependencies << dependency
64
64
  else
65
65
  @dependencies.concat dependency
@@ -201,8 +201,9 @@ class Step
201
201
 
202
202
  def self.clean(path)
203
203
  info_file = Step.info_file path
204
+ pid_file = Step.pid_file path
204
205
  files_dir = Step.files_dir path
205
- if Open.exists?(path) or Open.exists?(info_file)
206
+ if Open.exists?(path) or Open.exists?(pid_file)
206
207
  begin
207
208
  self.abort if self.running?
208
209
  rescue Exception
@@ -213,10 +214,11 @@ class Step
213
214
 
214
215
  Misc.insist do
215
216
  Open.rm info_file if Open.exists? info_file
216
- Open.rm info_file + '.lock' if Open.exists? info_file + '.lock'
217
+ #Open.rm info_file + '.lock' if Open.exists? info_file + '.lock'
217
218
  Open.rm path if Open.exists? path
218
- Open.rm path + '.lock' if Open.exists? path + '.lock'
219
+ #Open.rm path + '.lock' if Open.exists? path + '.lock'
219
220
  Open.rm_rf files_dir if Open.exists? files_dir
221
+ Open.rm pid_file if Open.exists? pid_file
220
222
  end
221
223
  end
222
224
  end
@@ -236,7 +238,8 @@ class Step
236
238
 
237
239
  new_dependencies = []
238
240
  dependencies.each{|step|
239
- new_dependencies.concat step.rec_dependencies
241
+ r = step.rec_dependencies
242
+ new_dependencies.concat r
240
243
  new_dependencies << step
241
244
  }
242
245
  new_dependencies.uniq
@@ -143,7 +143,11 @@ class Step
143
143
  next if (dependency.done? and not dependency.dirty?) or
144
144
  (dependency.streaming? and dependency.running?) or
145
145
  (defined? WorkflowRESTClient and WorkflowRESTClient::RemoteStep === dependency and not (dependency.error? or dependency.aborted?))
146
- dependency.clean if dependency.started? and dependency
146
+
147
+ dependency.clean if dependency.aborted? or (dependency.started? and not dependency.running? and not dependency.error?)
148
+
149
+ raise DependencyError, [dependency.short_path, dependency.messages.last] * ": " if dependency.error?
150
+
147
151
  dupping << dependency unless dependencies.include? dependency
148
152
  end
149
153
 
@@ -154,30 +158,83 @@ class Step
154
158
 
155
159
  begin
156
160
 
157
- if not dependency.done?
158
- if dependency.started?
159
- if dependency.streaming?
160
- Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} streaming -- #{Log.color :blue, dependency.path}"
161
- else
162
- Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} joining -- #{Log.color :blue, dependency.path}"
163
- dependency.join unless dependency.streaming?
164
- end
165
- else
166
- Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} starting -- #{Log.color :blue, dependency.path}"
167
- dependency.run(true).grace
168
- end
169
- else
170
- Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} done -- #{Log.color :blue, dependency.path}"
161
+ if dependency.done?
162
+ Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} done -- #{Log.color :blue, dependency.path} -- #{Log.color :yellow, self.short_path}"
163
+ next
164
+ end
165
+
166
+ if not dependency.started?
167
+ Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} starting -- #{Log.color :blue, dependency.path} -- #{Log.color :yellow, self.short_path}"
168
+ dependency.run(:stream)
169
+ raise TryAgain
170
+ end
171
+
172
+ dependency.grace
173
+
174
+ if dependency.aborted?
175
+ dependency.clean
176
+ raise TryAgain
177
+ end
178
+
179
+ if dependency.error?
180
+ raise DependencyError, [dependency.path, dependency.messages.last] * ": " if dependency.error?
181
+ end
182
+
183
+ if dependency.streaming?
184
+ Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} streaming -- #{Log.color :blue, dependency.path} -- #{Log.color :yellow, self.short_path}"
185
+ next
171
186
  end
172
187
 
188
+ Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} joining -- #{Log.color :blue, dependency.path} -- #{Log.color :yellow, self.short_path}"
189
+ begin
190
+ dependency.join
191
+ raise TryAgain unless dependency.done?
192
+ rescue Aborted
193
+ raise TryAgain
194
+ end
195
+ Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} joined -- #{Log.color :blue, dependency.path} -- #{Log.color :yellow, self.short_path}"
196
+
197
+ #if not dependency.done?
198
+ # if dependency.started?
199
+ # dependency.grace
200
+ # if dependency.error?
201
+ # raise DependencyError, [dependency.path, dependency.messages.last] * ": " if dependency.error?
202
+ # elsif dependency.streaming?
203
+ # Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} streaming -- #{Log.color :blue, dependency.path} -- #{Log.color :blue, self.short_path}"
204
+ # else
205
+ # Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} joining -- #{Log.color :blue, dependency.path} -- #{Log.color :blue, self.short_path}"
206
+ # begin
207
+ # dependency.join unless dependency.streaming?
208
+ # rescue Aborted
209
+ # Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} #{Log.color :red, "aborted"} -- #{Log.color :blue, dependency.path} -- #{Log.color :blue, self.short_path}"
210
+ # if dependency.aborted?
211
+ # Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} #{Log.color :red, "aborted cleaning"} -- #{Log.color :blue, dependency.path} -- #{Log.color :blue, self.short_path}"
212
+ # dependency.clean
213
+ # raise TryAgain
214
+ # end
215
+ # end
216
+ # Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} joined -- #{Log.color :blue, dependency.path} -- #{Log.color :blue, self.short_path}"
217
+ # end
218
+ # else
219
+ # Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} starting -- #{Log.color :blue, dependency.path} -- #{Log.color :blue, self.short_path}"
220
+ # dependency.run(:stream)
221
+ # dependency.grace
222
+ # dependency.join unless dependency.streaming?
223
+ # end
224
+ #else
225
+ # Log.info "#{Log.color :cyan, "dependency"} #{Log.color :yellow, task.name.to_s || ""} => #{Log.color :yellow, dependency.task_name.to_s || ""} done -- #{Log.color :blue, dependency.short_path}"
226
+ #end
227
+
228
+ rescue TryAgain
229
+ retry
173
230
  rescue Aborted
174
- Log.error "Aborted dep. #{Log.color :red, dependency.task.name.to_s}"
231
+ Log.error "Aborted dep. #{Log.color :red, dependency.task_name.to_s}"
175
232
  raise $!
176
233
  rescue Interrupt
177
- Log.error "Interrupted while in dep. #{Log.color :red, dependency.task.name.to_s}"
234
+ Log.error "Interrupted while in dep. #{Log.color :red, dependency.task_name.to_s}"
178
235
  raise $!
179
236
  rescue Exception
180
- Log.error "Exception in dep. #{ Log.color :red, dependency.task.name.to_s }"
237
+ Log.error "Exception in dep. #{ Log.color :red, dependency.task_name.to_s }"
181
238
  raise $!
182
239
  end
183
240
  end
@@ -189,13 +246,14 @@ class Step
189
246
  begin
190
247
  @mutex.synchronize do
191
248
  no_load = no_load ? :stream : false
192
- result = Persist.persist "Job", @task.result_type, :file => path, :check => checks, :no_load => no_load do |lockfile|
249
+ result = Persist.persist "Job", @task.result_type, :file => path, :check => checks, :no_load => no_load do
193
250
  if Step === Step.log_relay_step and not self == Step.log_relay_step
194
251
  relay_log(Step.log_relay_step) unless self.respond_to? :relay_step and self.relay_step
195
252
  end
196
- @exec = false
197
253
 
198
- Open.rm info_file if Open.exists? info_file
254
+ @exec = false
255
+ Open.write(pid_file, Process.pid.to_s)
256
+ init_info
199
257
 
200
258
  log :setup, "#{Log.color :green, "Setup"} step #{Log.color :yellow, task.name.to_s || ""}"
201
259
 
@@ -204,16 +262,17 @@ class Step
204
262
  :issued => (issue_time = Time.now),
205
263
  :name => name,
206
264
  :clean_name => clean_name,
207
- :dependencies => dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]},
208
265
  })
209
266
 
210
267
  dup_inputs
211
268
  begin
212
269
  run_dependencies
213
270
  rescue Exception
271
+ FileUtils.rm pid_file if File.exists?(pid_file)
214
272
  stop_dependencies
215
273
  raise $!
216
274
  end
275
+ set_info :dependencies, dependencies.collect{|dep| [dep.task_name, dep.name, dep.path]}
217
276
 
218
277
  set_info :inputs, Misc.remove_long_items(Misc.zip2hash(task.inputs, @inputs)) unless task.inputs.nil?
219
278
 
@@ -223,7 +282,6 @@ class Step
223
282
  begin
224
283
  result = _exec
225
284
  rescue Aborted
226
- stop_dependencies
227
285
  log(:aborted, "Aborted")
228
286
  raise $!
229
287
  rescue Exception
@@ -231,9 +289,9 @@ class Step
231
289
 
232
290
  # HACK: This fixes an strange behaviour in 1.9.3 where some
233
291
  # backtrace strings are coded in ASCII-8BIT
292
+ backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
234
293
  set_info :backtrace, backtrace
235
294
  log(:error, "#{$!.class}: #{$!.message}")
236
- backtrace.each{|l| l.force_encoding("UTF-8")} if String.instance_methods.include? :force_encoding
237
295
  stop_dependencies
238
296
  raise $!
239
297
  end
@@ -266,6 +324,7 @@ class Step
266
324
  Log.exception $!
267
325
  ensure
268
326
  join
327
+ FileUtils.rm pid_file if File.exists?(pid_file)
269
328
  end
270
329
  end
271
330
  stream.abort_callback = Proc.new do
@@ -273,6 +332,8 @@ class Step
273
332
  log :aborted, "#{Log.color :red, "Aborted"} step #{Log.color :yellow, task.name.to_s || ""}" if status == :streaming
274
333
  rescue
275
334
  Log.exception $!
335
+ stop_dependencies
336
+ FileUtils.rm pid_file if File.exists?(pid_file)
276
337
  end
277
338
  end
278
339
  else
@@ -280,6 +341,7 @@ class Step
280
341
  set_info :total_time_elapsed, (total_time_elapsed = done_time - issue_time)
281
342
  set_info :time_elapsed, (time_elapsed = done_time - start_time)
282
343
  log :done, "#{Log.color :magenta, "Completed"} step #{Log.color :yellow, task.name.to_s || ""} in #{time_elapsed.to_i}+#{(total_time_elapsed - time_elapsed).to_i} sec."
344
+ FileUtils.rm pid_file if File.exists?(pid_file)
283
345
  end
284
346
 
285
347
  result
@@ -294,6 +356,7 @@ class Step
294
356
  end
295
357
  rescue Exception
296
358
  exception $!
359
+ stop_dependencies
297
360
  raise $!
298
361
  end
299
362
  end
@@ -302,10 +365,10 @@ class Step
302
365
  return self if done? and not dirty?
303
366
 
304
367
  if error? or aborted?
305
- if force
368
+ if force or aborted?
306
369
  clean
307
370
  else
308
- raise "Error in job: #{status}"
371
+ raise "Error in job: #{status} - #{self.path}"
309
372
  end
310
373
  end
311
374
 
@@ -326,6 +389,7 @@ class Step
326
389
  RbbtSemaphore.wait_semaphore(semaphore) if semaphore
327
390
  FileUtils.mkdir_p File.dirname(path) unless File.exists? File.dirname(path)
328
391
  begin
392
+ @forked = true
329
393
  res = run true
330
394
  set_info :forked, true
331
395
  rescue Aborted
@@ -386,13 +450,14 @@ class Step
386
450
  Log.medium "Could not abort #{path}: same process"
387
451
  false
388
452
  else
389
- Log.medium "Aborting #{path}: #{ @pid }"
453
+ Log.medium "Aborting pid #{path}: #{ @pid }"
390
454
  begin
391
- Process.kill("KILL", @pid)
455
+ Process.kill("INT", @pid)
392
456
  Process.waitpid @pid
393
457
  rescue Exception
394
458
  Log.debug("Aborted job #{@pid} was not killed: #{$!.message}")
395
459
  end
460
+ Log.medium "Aborted pid #{path}: #{ @pid }"
396
461
  true
397
462
  end
398
463
  end
@@ -422,7 +487,7 @@ class Step
422
487
  begin
423
488
  stop_dependencies
424
489
  abort_stream
425
- abort_pid
490
+ abort_pid if defined? @forked and @forked
426
491
  rescue Aborted
427
492
  Log.medium{"#{Log.color :red, "Aborting ABORTED RETRY"} #{Log.color :blue, path}"}
428
493
  retry
@@ -463,7 +528,7 @@ class Step
463
528
  end
464
529
 
465
530
  def soft_grace
466
- until Open.exists? info_file
531
+ until done? or File.exists?(info_file)
467
532
  sleep 1
468
533
  end
469
534
  self
@@ -506,7 +571,7 @@ class Step
506
571
  pid = nil
507
572
  dependencies.each{|dep| dep.join }
508
573
  end
509
- sleep 1 until path.exists?
574
+ sleep 1 until path.exists? or error? or aborted?
510
575
  self
511
576
  ensure
512
577
  set_info :joined, true
@@ -20,6 +20,8 @@ $ rbbt app start [options] <app_name>
20
20
  -R--Rserve_session* Rserve session to use, otherwise start new one
21
21
  -wd--workdir* Change the working directory of the workflow
22
22
  --views* Directory with view templates
23
+ --stream Activate streaming of workflow tasks
24
+ --options* Additional options for server (e.g. option1=value1;option2=value2)
23
25
  EOF
24
26
 
25
27
  if options[:help]
@@ -55,19 +57,32 @@ Misc.in_dir(app_dir) do
55
57
  ENV["RACK_ENV"] = options[:environment] if options.include?(:environment)
56
58
  ENV["RBBT_VIEWS_DIR"] = options[:views] if options.include?(:views)
57
59
 
60
+ if options[:stream]
61
+ raise "No streaming available for any server other than puma" unless options[:server] =~ /^puma|unico/
62
+ ENV["RBBT_WORKFLOW_TASK_STREAM"] = 'true'
63
+ end
64
+
58
65
  config_ru_file = File.exists?('./config.ru') ? './config.ru' : Rbbt.share['config.ru'].find
59
66
 
60
- if server == 'unicorn'
61
- `unicorn -c #{ Rbbt.share['unicorn.rb'].find } '#{config_ru_file}' -p #{options[:port] || "2887"}`
67
+ if options[:options]
68
+ options[:options].split(";").each do |pair|
69
+ name, _sep, value = pair.partition("=")
70
+ name = name[1..-1].to_sym if name[0] == ':'
71
+ options[name] = value
72
+ end
73
+ end
74
+
75
+ case server
76
+ when 'unicorn'
77
+ system ENV, "unicorn -c #{ Rbbt.share['unicorn.rb'].find } '#{config_ru_file}' -p #{options[:port] || "2887"}"
78
+ when 'puma_alt'
79
+ system ENV, "puma '#{config_ru_file}' -p #{options[:Port] || "2887"} -w 3 -t 8:32 --preload"
62
80
  else
63
81
  options[:config] = config_ru_file
64
82
  Rack::Server.start(options)
65
83
  end
66
84
  end
67
85
 
68
-
69
-
70
-
71
86
  #!/usr/bin/env ruby
72
87
 
73
88
  require 'rbbt-util'
@@ -1,33 +1,28 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
+ require 'rbbt-util'
3
4
  require 'rbbt/util/simpleopt'
4
- require 'rbbt/workflow'
5
5
 
6
- #require 'zurb-foundation'
7
- #require 'modular-scale'
8
-
9
- require 'rbbt/rest/main'
10
- require 'rbbt/rest/entity'
11
- require 'rbbt/rest/workflow'
12
- require 'rbbt/rest/file_server'
13
- require 'rbbt/rest/knowledge_base'
14
- require 'rbbt/rest/helpers'
15
- require 'rbbt/rest/web_tool'
6
+ $0 = "rbbt #{$previous_commands*""} #{ File.basename(__FILE__) }" if $previous_commands
16
7
 
17
8
  options = SOPT.setup <<EOF
18
9
  Start an rbbt app
19
10
 
20
- $ rbbt app start [options] <app_name>
11
+ $ rbbt workflow server [options] <Workflow>
21
12
 
22
13
  -h--help Print this help
23
14
  -e--environment* Execution environment: production or development
24
- -b--bind* Bind to a particular IP (net interface)
15
+ -Ho--Host* Host name
16
+ -B--Bind* Bind IP
25
17
  -p--port* TCP port
26
18
  -s--server* Server type: thin, webrick, unicorn, etc
27
19
  -f--finder Start server with finder functionality
28
20
  -R--Rserve_session* Rserve session to use, otherwise start new one
21
+ -wd--workdir* Change the working directory of the workflow
29
22
  -w--workflows* List of additional workflows to load
30
23
  --views* Directory with view templates
24
+ --stream Activate streaming of workflow tasks
25
+ --options* Additional options for server (e.g. option1=value1;option2=value2)
31
26
  EOF
32
27
 
33
28
  if options[:help]
@@ -39,57 +34,59 @@ if options[:help]
39
34
  exit 0
40
35
  end
41
36
 
42
- workflow = ARGV.first
43
-
44
- ENV["RBBT_FINDER"] = "true" if options.include?(:finder)
45
- ENV["RServe-session"] = options[:RServe_session] || workflow
46
-
47
- raise rbbt_usage unless workflow
48
-
49
- wf = Workflow.require_workflow workflow
50
-
51
- $title = wf.to_s
52
-
53
- load Rbbt.etc['app.d/init.rb'].find
54
-
55
- app = class WorkflowRest < Sinatra::Base; self end
56
-
57
- app.register Sinatra::RbbtRESTWorkflow
58
- app.register Sinatra::MultiRoute
59
- app.register Sinatra::RbbtRESTKnowledgeBase
60
- app.helpers Sinatra::RbbtToolHelper
61
-
62
- app.get '/' do
63
- redirect to(File.join('/', wf.to_s))
64
- end
65
- app.instance_eval Rbbt.etc['app.d/base.rb'].read
66
- app.use Rack::Deflater
67
-
68
- load Rbbt.etc['app.d/resources.rb'].find
69
-
70
- app.class_eval do
71
- eval Rbbt.etc['app.d/finder.rb'].read
37
+ if options[:workdir]
38
+ require 'rbbt/workflow'
39
+ Workflow.workdir = options[:workdir]
72
40
  end
73
41
 
74
- WorkflowRest.add_workflow wf, :priority
75
- if options[:workflows]
76
- options[:workflows].split(/[\s,]+/).each do |name|
77
- _wf = Workflow.require_workflow name
78
- WorkflowRest.add_workflow _wf, true
79
- end
80
- end
42
+ options[:Port] ||= options[:port]
43
+ options[:Host] ||= "0.0.0.0"
44
+ options[:Bind] ||= "0.0.0.0"
81
45
 
82
- load Rbbt.etc['app.d/requires.rb'].find
46
+ workflow = ARGV.shift
47
+ workflows = options[:workflows] || ""
83
48
 
84
- load Rbbt.etc['app.d/entities.rb'].find
49
+ workflow = File.expand_path(workflow) if File.exists?(workflow)
85
50
 
51
+ ENV["RServe-session"] = options[:RServe_session] || workflow
86
52
 
87
- if options[:views] and not options[:views].empty?
88
- Sinatra::RbbtRESTMain.add_resource_path(Path.setup(options[:views]), true)
53
+ server = options[:server] || 'puma'
54
+
55
+ TmpFile.with_file do |app_dir|
56
+ Misc.in_dir(app_dir) do
57
+ app_dir = Path.setup(app_dir.dup)
58
+ Open.write(app_dir.etc.target_workflow.find, workflow)
59
+ Open.write(app_dir.etc.workflows.find, workflows.split(/,\s/)*"\n") if workflows
60
+
61
+ require 'rack'
62
+ ENV["RBBT_FINDER"] = "true" if options.include?(:finder)
63
+ ENV["RACK_ENV"] = options[:environment] if options.include?(:environment)
64
+ ENV["RBBT_VIEWS_DIR"] = options[:views] if options.include?(:views)
65
+
66
+ if options[:stream]
67
+ raise "No streaming available for any server other than puma" unless options[:server] == 'puma'
68
+ ENV["RBBT_WORKFLOW_TASK_STREAM"] = 'true'
69
+ end
70
+
71
+ config_ru_file = File.exists?('./workflow_config.ru') ? './config.ru' : Rbbt.share['workflow_config.ru'].find
72
+
73
+
74
+ if options[:options]
75
+ options[:options].split(";").each do |pair|
76
+ name, _sep, value = pair.partition("=")
77
+ name = name[1..-1].to_sym if name[0] == ':'
78
+ options[name] = value
79
+ end
80
+ end
81
+
82
+ case server
83
+ when 'unicorn'
84
+ `unicorn -c #{ Rbbt.share['unicorn.rb'].find } '#{config_ru_file}' -p #{options[:port] || "2887"}`
85
+ when 'puma_alt'
86
+ `puma '#{config_ru_file}' -p #{options[:Port] || "2887"} -w 3 -t 8:32 --preload`
87
+ else
88
+ options[:config] = config_ru_file
89
+ Rack::Server.start(options)
90
+ end
91
+ end
89
92
  end
90
-
91
- WorkflowRest.port = options[:port] || 4567
92
- WorkflowRest.bind = options[:bind] || "0.0.0.0"
93
- WorkflowRest.environment = options[:environment] || "development"
94
- WorkflowRest.server = options[:server] if options[:server]
95
- WorkflowRest.run!
@@ -441,8 +441,8 @@ when (defined?(WorkflowRESTClient) and WorkflowRESTClient::RemoteStep)
441
441
  puts res.to_s
442
442
  end
443
443
  when Step
444
- if step.streaming?
445
- io = res.get_stream
444
+ if res.streaming?
445
+ io = TSV.get_stream res
446
446
  while block = io.read(2048) do
447
447
  out.write block
448
448
  end #unless io.closed?
@@ -493,6 +493,10 @@ eum fugiat quo voluptas nulla pariatur?"
493
493
  end
494
494
  end
495
495
 
496
+ def test_obj2md5_str_float
497
+ assert_equal Misc.obj2md5([1,2]), Misc.obj2md5(["1","2"])
498
+ end
499
+
496
500
  def test_sample_large_string
497
501
  str = "string" * 1000000
498
502
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbbt-util
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.19.35
4
+ version: 5.19.36
5
5
  platform: ruby
6
6
  authors:
7
7
  - Miguel Vazquez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-27 00:00:00.000000000 Z
11
+ date: 2016-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -261,6 +261,7 @@ files:
261
261
  - lib/rbbt/util/misc/lock.rb
262
262
  - lib/rbbt/util/misc/manipulation.rb
263
263
  - lib/rbbt/util/misc/math.rb
264
+ - lib/rbbt/util/misc/multipart_payload.rb
264
265
  - lib/rbbt/util/misc/objects.rb
265
266
  - lib/rbbt/util/misc/omics.rb
266
267
  - lib/rbbt/util/misc/options.rb