mobilize-base 1.0.9 → 1.0.51

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -11,5 +11,4 @@ config
11
11
  log
12
12
  tmp
13
13
  .DS_Store
14
- REVISION
15
14
  test/dump.rdb
data/README.md CHANGED
@@ -120,7 +120,7 @@ same one that contains your Rakefile)
120
120
  Inside the Rakefile in your project's root folder, make sure you have:
121
121
 
122
122
  ``` ruby
123
- require 'mobilize-base/tasks'
123
+ require 'mobilize-base/rakes'
124
124
  ```
125
125
 
126
126
  This defines rake tasks essential to run the environment.
@@ -390,7 +390,7 @@ Mobilize takes the environment from your Rails.env if you're running
390
390
  Rails, or assumes "development." You can specify "development", "test",
391
391
  or "production," as per the yml files.
392
392
 
393
- Otherwise, it takes it from MOBILIZE_ENV parameter, as in:
393
+ Otherwise, it takes it from MOBILIZE_ENV parameter, set from irb, as in:
394
394
 
395
395
  ``` ruby
396
396
  > ENV['MOBILIZE_ENV'] = 'production'
@@ -489,28 +489,26 @@ name>))` and enter values under each header:
489
489
 
490
490
  * status Mobilize writes this field with the last status returned by the job
491
491
 
492
- * stage1..stage5 List of stages to be performed by the job.
493
- * Stages have this syntax: <handler>.<call> <params>.
494
- * handler specifies the file that should receive the stage
492
+ * task1..task5 List of tasks to be performed by the job.
493
+ * Tasks have this syntax: <handler>.<call> <params>.
494
+ * handler specifies the file that should receive the task
495
495
  * the call specifies the method within the file. The method should
496
- be called `"<handler>.<call>_by_stage_path"`
496
+ be called `"<Handler>.<call>_by_task_path"`
497
497
  * the params the method accepts, which are custom to each
498
- stage. These should be of the for `<key1>: <value1>, <key2>: <value2>`, where
499
- `<key>` is an unquoted string and `<value>` is a quoted string, an
500
- integer, an array (delimited by square braces), or a hash (delimited by
501
- curly braces).
502
- * For mobilize-base, the following stages are available:
503
- * gsheet.read `source: <input_gsheet_full_path>`, which reads the sheet.
504
- * The gsheet_full_path should be of the form `<gbook_name>/<gsheet_name>`. The test uses
505
- "Requestor_mobilize(test)/base1_stage1.in".
506
- * gsheet.write `source: <stage_relative_path>`,`target: <target_gsheet_path>`,
507
- which writes the specified stage output to the target_gsheet.
508
- * The stage_relative_path should be of the form `<stage_column>` or
509
- `<job_name/stage_column>`. The test uses "base1/stage1" for the first test
510
- and simply "stage1" for the second test. Both of these take the output
511
- from the first stage.
498
+ task. These should be a comma-delimited list, with each param in
499
+ quotes.
500
+ * For mobilize-base, the following tasks are available:
501
+ * gsheet.read `<input_gsheet_full_path>`, which reads the sheet.
502
+ * The gsheet_path should be of the form `<gbook_name>/<gsheet_name>`. The test uses
503
+ "Requestor_mobilize(test)/base1_task1.in".
504
+ * gsheet.write `<task_relative_path>`,`<output_gsheet_path>`,
505
+ which writes the specified task output to the output_gsheet.
506
+ * The task_path should be of the form `<task_column>` or
507
+ `<job_name/task_column>`. The test uses "base1/task1" for the first test
508
+ and simply "task1" for the second test. Both of these take the output
509
+ from the first task.
512
510
  * The test uses "Requestor_mobilize(test)/base1.out" and
513
- "Requestor_mobilize(test)/base2.out" for target sheets.
511
+ "Requestor_mobilize(test)/base2.out" for output sheets.
514
512
 
515
513
  <a name='section_Start_Run_Test'></a>
516
514
  ### Run Test
data/Rakefile CHANGED
@@ -17,7 +17,7 @@ require "bundler/gem_tasks"
17
17
  # Setup
18
18
  #
19
19
  $LOAD_PATH.unshift 'lib'
20
- require 'mobilize-base/tasks'
20
+ require 'mobilize-base/rakes'
21
21
 
22
22
  #
23
23
  # Tests
@@ -1,7 +1,6 @@
1
1
  module GoogleDrive
2
2
  class ClientLoginFetcher
3
3
  def request_raw(method, url, data, extra_header, auth)
4
- clf = self
5
4
  #this is patched to handle server errors due to http chaos
6
5
  uri = URI.parse(url)
7
6
  response = nil
@@ -15,32 +14,22 @@ module GoogleDrive
15
14
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
16
15
  #set 600 to allow for large downloads
17
16
  http.read_timeout = 600
18
- response = begin
19
- clf.http_call(http, method, uri, data, extra_header, auth)
20
- rescue
21
- #timeouts etc.
22
- nil
23
- end
24
- if response.nil?
25
- attempts +=1
26
- else
27
- if response.code.ie{|rcode| rcode.starts_with?("4") or rcode.starts_with?("5")}
28
- if response.body.downcase.index("rate limit") or response.body.downcase.index("captcha")
29
- if sleep_time
30
- sleep_time = sleep_time * attempts
31
- else
32
- sleep_time = (rand*100).to_i
33
- end
17
+ response = self.http_call(http, method, uri, data, extra_header, auth)
18
+ if response.code.ie{|rcode| rcode.starts_with?("4") or rcode.starts_with?("5")}
19
+ if response.body.downcase.index("rate limit") or response.body.downcase.index("captcha")
20
+ if sleep_time
21
+ sleep_time = sleep_time * attempts
34
22
  else
35
- sleep_time = 10
23
+ sleep_time = (rand*100).to_i
36
24
  end
37
- attempts += 1
38
- puts "Sleeping for #{sleep_time.to_s} due to #{response.body}"
39
- sleep sleep_time
25
+ else
26
+ sleep_time = 10
40
27
  end
28
+ attempts += 1
29
+ puts "Sleeping for #{sleep_time.to_s} due to #{response.body}"
30
+ sleep sleep_time
41
31
  end
42
32
  end
43
- raise "No response after 5 attempts" if response.nil?
44
33
  raise response.body if response.code.ie{|rcode| rcode.starts_with?("4") or rcode.starts_with?("5")}
45
34
  return response
46
35
  end
@@ -54,11 +54,7 @@ module GoogleDrive
54
54
  raise "Invalid role #{role}"
55
55
  end
56
56
  else
57
- begin
58
- f.acl.push({:scope_type=>"user",:scope=>email,:role=>role})
59
- rescue => exc
60
- raise exc unless exc.to_s.index("user already has access")
61
- end
57
+ f.acl.push({:scope_type=>"user",:scope=>email,:role=>role})
62
58
  end
63
59
  return true
64
60
  end
@@ -137,9 +137,8 @@ module GoogleDrive
137
137
  if loc_v != rem_v
138
138
  if ['true','false'].include?(loc_v.downcase)
139
139
  #google sheet upcases true and false. ignore
140
- elsif loc_v.to_s.downcase.gsub("-","").gsub(" ","")==rem_v.to_s.downcase.gsub("-","").gsub(" ","")
141
- #supported currency, silently converted whether it's an actual currency or not
142
- #put a backtick on it.
140
+ elsif loc_v.starts_with?('rp') and rem_v.starts_with?('Rp')
141
+ # some other math bs
143
142
  sheet[row_i+1,col_i+1] = %{'#{loc_v}}
144
143
  re_col_vs << {'row_i'=>row_i+1,'col_i'=>col_i+1,'col_v'=>%{'#{loc_v}}}
145
144
  elsif (loc_v.to_s.count('e')==1 or loc_v.to_s.count('e')==0) and
@@ -8,10 +8,10 @@ module Mobilize
8
8
  dst = Dataset.find_or_create_by_handler_and_path('gbook',path)
9
9
  #there should only be one book with each path, otherwise we have fail
10
10
  book = nil
11
- if books.length>1 and dst.http_url.to_s.length>0
11
+ if books.length>1 and dst.url.to_s.length>0
12
12
  #some idiot process created a duplicate book.
13
13
  #Fix by renaming all but one with dst entry's key
14
- dkey = dst.http_url.split("key=").last
14
+ dkey = dst.url.split("key=").last
15
15
  books.each do |b|
16
16
  bkey = b.resource_id.split(":").last
17
17
  if bkey == dkey
@@ -30,9 +30,9 @@ module Mobilize
30
30
  book = Gdrive.root(Gdrive.owner_email).create_spreadsheet(path)
31
31
  ("Created book #{path} at #{Time.now.utc.to_s}; Access at #{book.human_url}").oputs
32
32
  end
33
- #always make sure book dataset http URL is up to date
33
+ #always make sure book dataset URL is up to date
34
34
  #and that book has admin acl
35
- dst.update_attributes(:http_url=>book.human_url)
35
+ dst.update_attributes(:url=>book.human_url)
36
36
  book.add_admin_acl
37
37
  return book
38
38
  end
@@ -54,15 +54,6 @@ module Mobilize
54
54
  return false
55
55
  end
56
56
 
57
- def Gdrive.unslot_worker_by_path(path)
58
- begin
59
- Mobilize::Resque.set_worker_args_by_path(path,{'gdrive_slot'=>nil})
60
- return true
61
- rescue
62
- return false
63
- end
64
- end
65
-
66
57
  def Gdrive.root(gdrive_slot=nil)
67
58
  pw = Gdrive.password(gdrive_slot)
68
59
  GoogleDrive.login(gdrive_slot,pw)
@@ -22,16 +22,13 @@ module Mobilize
22
22
  Gdrive.files(gdrive_slot,{"title"=>path,"title-exact"=>"true"}).first
23
23
  end
24
24
 
25
- def Gfile.read_by_stage_path(stage_path)
25
+ def Gfile.read_by_task_path(task_path)
26
26
  #reserve gdrive_slot account for read
27
- gdrive_slot = Gdrive.slot_worker_by_path(s.path)
27
+ gdrive_slot = Gdrive.slot_worker_by_path(t.path)
28
28
  return false unless gdrive_slot
29
- s = Stage.where(:path=>stage_path)
30
- gfile_path = s.params['file']
31
- out_tsv = Gfile.find_by_path(gfile_path,gdrive_slot).read
32
- #use Gridfs to cache result
33
- out_url = "gridfs://#{s.path}/out"
34
- Dataset.write_to_url(out_url,out_tsv)
29
+ t = Task.where(:path=>task_path)
30
+ gfile_path = t.params.first
31
+ Gfile.find_by_path(gfile_path,gdrive_slot).read
35
32
  end
36
33
  end
37
34
  end
@@ -11,29 +11,29 @@ module Mobilize
11
11
  return ::Mongo::GridFileSystem.new(::Mongo::Connection.new(host,port).db(database_name))
12
12
  end
13
13
 
14
- def Gridfs.read_by_dataset_path(dst_path)
14
+ def Gridfs.read(path)
15
15
  begin
16
- zs=Gridfs.grid.open(dst_path,'r').read
16
+ zs=Gridfs.grid.open(path.gridsafe,'r').read
17
17
  return ::Zlib::Inflate.inflate(zs)
18
18
  rescue
19
19
  return nil
20
20
  end
21
21
  end
22
22
 
23
- def Gridfs.write_by_dataset_path(dst_path,string)
23
+ def Gridfs.write(path,string)
24
24
  zs = ::Zlib::Deflate.deflate(string)
25
25
  raise "compressed string too large for Gridfs write" if zs.length > Gridfs.config['max_compressed_write_size']
26
- curr_zs = Gridfs.read_by_dataset_path(dst_path).to_s
26
+ curr_zs = Gridfs.read(path.gridsafe).to_s
27
27
  #write a new version when there is a change
28
28
  if curr_zs != zs
29
- Gridfs.grid.open(dst_path,'w',:versions => Gridfs.config['max_versions']){|f| f.write(zs)}
29
+ Gridfs.grid.open(path.gridsafe,'w',:versions => Gridfs.config['max_versions']){|f| f.write(zs)}
30
30
  end
31
31
  return true
32
32
  end
33
33
 
34
- def Gridfs.delete(dst_path)
34
+ def Gridfs.delete(path)
35
35
  begin
36
- Gridfs.grid.delete(dst_path)
36
+ Gridfs.grid.delete(path.gridsafe)
37
37
  return true
38
38
  rescue
39
39
  return nil
@@ -32,35 +32,32 @@ module Mobilize
32
32
  return sheet
33
33
  end
34
34
 
35
- def Gsheet.read_by_stage_path(stage_path)
35
+ def Gsheet.read_by_task_path(task_path)
36
36
  #reserve gdrive_slot account for read
37
- gdrive_slot = Gdrive.slot_worker_by_path(stage_path)
37
+ gdrive_slot = Gdrive.slot_worker_by_path(task_path)
38
38
  return false unless gdrive_slot
39
- s = Stage.where(:path=>stage_path).first
40
- gsheet_path = s.params['source']
41
- out_tsv = Gsheet.find_by_path(gsheet_path,gdrive_slot).to_tsv
42
- #use Gridfs to cache result
43
- out_url = "gridfs://#{s.path}/out"
44
- Dataset.write_to_url(out_url,out_tsv)
39
+ t = Task.where(:path=>task_path).first
40
+ gsheet_path = t.params.first
41
+ Gsheet.find_by_path(gsheet_path,gdrive_slot).to_tsv
45
42
  end
46
43
 
47
- def Gsheet.write_by_stage_path(stage_path)
48
- gdrive_slot = Gdrive.slot_worker_by_path(stage_path)
49
- #return blank response if there are no slots available
50
- return nil unless gdrive_slot
51
- s = Stage.where(:path=>stage_path).first
52
- source = s.params['source']
53
- target_path = s.params['target']
54
- source_job_name, source_stage_name = if source.index("/")
44
+ def Gsheet.write_by_task_path(task_path)
45
+ gdrive_slot = Gdrive.slot_worker_by_path(task_path)
46
+ #return false if there are no emails available
47
+ return false unless gdrive_slot
48
+ t = Task.where(:path=>task_path).first
49
+ source = t.params.first
50
+ target_path = t.params.second
51
+ source_job_name, source_task_name = if source.index("/")
55
52
  source.split("/")
56
53
  else
57
54
  [nil, source]
58
55
  end
59
- source_stage_path = "#{s.job.runner.path}/#{source_job_name || s.job.name}/#{source_stage_name}"
60
- source_stage = Stage.where(:path=>source_stage_path).first
61
- tsv = source_stage.out_dst.read
56
+ source_task_path = "#{t.job.runner.path}/#{source_job_name || t.job.name}/#{source_task_name}"
57
+ source_task = Task.where(:path=>source_task_path).first
58
+ tsv = source_task.stdout_dataset.read_cache
62
59
  sheet_name = target_path.split("/").last
63
- temp_path = [stage_path.gridsafe,sheet_name].join("/")
60
+ temp_path = [task_path.gridsafe,sheet_name].join("/")
64
61
  temp_sheet = Gsheet.find_or_create_by_path(temp_path,gdrive_slot)
65
62
  temp_sheet.write(tsv)
66
63
  temp_sheet.check_and_fix(tsv)
@@ -68,11 +65,8 @@ module Mobilize
68
65
  target_sheet.merge(temp_sheet)
69
66
  #delete the temp sheet's book
70
67
  temp_sheet.spreadsheet.delete
71
- status = "Write successful for #{target_path}"
72
- s.update_status(status)
73
- #use Gridfs to cache result
74
- out_url = "gridfs://#{s.path}/out"
75
- Dataset.write_to_url(out_url,status)
68
+ "Write successful for #{target_path}".oputs
69
+ return true
76
70
  end
77
71
  end
78
72
  end
@@ -17,6 +17,7 @@ module Mobilize
17
17
  end
18
18
 
19
19
  def Resque.workers(state="all")
20
+ raise "invalid state #{state}" unless ['all','idle','working','timeout'].include?(state)
20
21
  workers = ::Resque.workers.select{|w| w.queues.first == Resque.queue_name}
21
22
  return workers if state == 'all'
22
23
  working_workers = workers.select{|w| w.job['queue']== Resque.queue_name}
@@ -27,7 +28,6 @@ module Mobilize
27
28
  return stale_workers if state == 'stale'
28
29
  timeout_workers = workers.select{|w| w.job['payload'] and w.job['payload']['class']!='Jobtracker' and w.job['runat'] < (Time.now.utc - Jobtracker.max_run_time)}
29
30
  return timeout_workers if state == 'timeout'
30
- raise "invalid state #{state}"
31
31
  end
32
32
 
33
33
  def Resque.failures
@@ -36,6 +36,7 @@ module Mobilize
36
36
 
37
37
  #active state refers to jobs that are either queued or working
38
38
  def Resque.jobs(state="active")
39
+ raise "invalid state #{state}" unless ['all','queued','working','active','timeout','failed'].include?(state)
39
40
  working_jobs = Resque.workers('working').map{|w| w.job['payload']}
40
41
  return working_jobs if state == 'working'
41
42
  queued_jobs = ::Resque.peek(Resque.queue_name,0,0).to_a
@@ -46,17 +47,16 @@ module Mobilize
46
47
  timeout_jobs = Resque.workers("timeout").map{|w| w.job['payload']}
47
48
  return timeout_jobs if state == 'timeout'
48
49
  return working_jobs + queued_jobs + failed_jobs if state == 'all'
49
- raise "invalid state #{state}"
50
50
  end
51
51
 
52
52
  def Resque.active_paths
53
- #first argument of the payload is the runner / stage path unless the worker is Jobtracker
54
- Resque.jobs('active').compact.map{|j| j['args'].first unless j['class']=='Jobtracker'}.compact
53
+ #first argument of the payload is the runner / task path unless the worker is Jobtracker
54
+ Resque.jobs('active').map{|j| j['args'].first unless j['class']=='Jobtracker'}.compact
55
55
  end
56
56
 
57
57
  #Resque workers and methods to find
58
58
  def Resque.find_worker_by_path(path)
59
- Resque.workers('working').select{|w| w.job and w.job['payload'] and w.job['payload']['args'].first == path}.first
59
+ Resque.workers('working').select{|w| w.job['payload'] and w.job['payload']['args'].first == path}.first
60
60
  end
61
61
 
62
62
  def Resque.set_worker_args_by_path(path,args)
@@ -141,7 +141,7 @@ module Mobilize
141
141
  return true
142
142
  end
143
143
 
144
- def Resque.kill_idle_and_stale_workers
144
+ def Resque.kill_idle_stale_workers
145
145
  idle_pids = Resque.workers('idle').select{|w| w.job=={}}.map{|w| w.to_s.split(":").second}
146
146
  stale_pids = Resque.workers('stale').select{|w| w.job=={}}.map{|w| w.to_s.split(":").second}
147
147
  idle_stale_pids = (idle_pids & stale_pids)
@@ -89,7 +89,7 @@ module Mobilize
89
89
 
90
90
  def Jobtracker.start
91
91
  if Jobtracker.status!='stopped'
92
- Jobtracker.update_status("Jobtracker still #{Jobtracker.status}")
92
+ raise "Jobtracker still #{Jobtracker.status}"
93
93
  else
94
94
  #make sure that workers are running and at the right number
95
95
  #Resque.prep_workers
@@ -190,9 +190,7 @@ module Mobilize
190
190
  while Jobtracker.status != 'stopping'
191
191
  users = User.all
192
192
  Jobtracker.run_notifications
193
- #run throush all users randomly
194
- #so none are privileged on JT restarts
195
- users.sort_by{rand}.each do |u|
193
+ users.each do |u|
196
194
  r = u.runner
197
195
  Jobtracker.update_status("Checking #{r.path}")
198
196
  if r.is_due?
@@ -208,25 +206,15 @@ module Mobilize
208
206
 
209
207
  def Jobtracker.deployed_at
210
208
  #assumes deploy is as of last commit, or as of last deploy time
211
- #as given by the REVISION file in the root folder
209
+ #as given by the least recently updated file in the root folder
212
210
  deploy_time = begin
213
- %{git log -1 --format="%cd"}.bash
214
- rescue
215
- revision_path = "#{ENV['PWD']}/REVISION"
216
- "touch #{revision_path}".bash unless File.exists?(revision_path)
217
- revision_string = "ls -l #{revision_path}".bash
218
- revision_rows = revision_string.split("\n").map{|lss| lss.strip.split(" ")}
219
- mod_time = revision_rows.map do |lsr|
220
- if lsr.length == 8
221
- #ubuntu
222
- lsr[5..6].join(" ")
223
- elsif lsr.length == 9
224
- #osx
225
- lsr[5..7].join(" ")
226
- end
227
- end.first
228
- mod_time
229
- end.to_s.strip
211
+ %{git log -1 --format="%cd"}.bash
212
+ rescue
213
+ ls_string = "ls -l #{ENV['PWD']}/*".bash
214
+ ls_rows = ls_string.split("\n").map{|lss| lss.strip.split(" ")}
215
+ mod_times = ls_rows.select{|lsr| lsr.length == 8}.map{|lsr| lsr[5..6].join(" ")}
216
+ mod_times.min
217
+ end
230
218
  Time.parse(deploy_time)
231
219
  end
232
220
 
@@ -4,7 +4,7 @@ module Mobilize
4
4
  include Mongoid::Timestamps
5
5
  field :handler, type: String
6
6
  field :path, type: String
7
- field :http_url, type: String
7
+ field :url, type: String
8
8
  field :raw_size, type: Fixnum
9
9
  field :last_cached_at, type: Time
10
10
  field :last_cache_handler, type: String
@@ -18,16 +18,6 @@ module Mobilize
18
18
  return "Mobilize::#{dst.handler.humanize}".constantize.read_by_path(dst.path)
19
19
  end
20
20
 
21
- def Dataset.find_by_url(url)
22
- handler,path = url.split("://")
23
- Dataset.find_by_handler_and_path(handler,path)
24
- end
25
-
26
- def Dataset.find_or_create_by_url(url)
27
- handler,path = url.split("://")
28
- Dataset.find_or_create_by_handler_and_path(handler,path)
29
- end
30
-
31
21
  def Dataset.find_by_handler_and_path(handler,path)
32
22
  Dataset.where(handler: handler, path: path).first
33
23
  end
@@ -38,30 +28,41 @@ module Mobilize
38
28
  return dst
39
29
  end
40
30
 
41
- def Dataset.write_to_url(url,string)
42
- dst = Dataset.find_or_create_by_url(url)
43
- dst.write(string)
44
- url
31
+ def write(string)
32
+ dst = self
33
+ "Mobilize::#{dst.handler.humanize}".constantize.write_by_path(dst.path,string)
34
+ dst.raw_size = string.length
35
+ dst.save!
36
+ return true
45
37
  end
46
38
 
47
- def read
39
+ def cache_valid?
48
40
  dst = self
49
- dst.update_attributes(:last_read_at=>Time.now.utc)
50
- "Mobilize::#{dst.handler.humanize}".constantize.read_by_dataset_path(dst.path)
41
+ return true if dst.last_cached_at and (dst.cache_expire_at.nil? or dst.cache_expire_at > Time.now.utc)
51
42
  end
52
43
 
53
- def write(string)
44
+ def read_cache(cache_handler="gridfs")
54
45
  dst = self
55
- "Mobilize::#{dst.handler.humanize}".constantize.write_by_dataset_path(dst.path,string)
56
- dst.raw_size = string.length
57
- dst.save!
58
- return true
46
+ if cache_valid?
47
+ dst.update_attributes(:last_read_at=>Time.now.utc)
48
+ return "Mobilize::#{cache_handler.humanize}".constantize.read([dst.handler,dst.path].join("://"))
49
+ else
50
+ raise "Cache invalid or not found for #{cache_handler}://#{dst.path}"
51
+ end
59
52
  end
60
53
 
61
- def delete
54
+ def write_cache(string,expire_at=nil,cache_handler="gridfs")
62
55
  dst = self
63
- "Mobilize::#{dst.handler.humanize}".constantize.delete_by_dataset_path(dst.path)
56
+ "Mobilize::#{cache_handler.humanize}".constantize.write([dst.handler,dst.path].join("://"),string)
57
+ dst.update_attributes(:last_cached_at=>Time.now.utc,
58
+ :last_cache_handler=>cache_handler.to_s.downcase,
59
+ :cache_expire_at=>expire_at,
60
+ :size=>string.length)
64
61
  return true
65
62
  end
63
+
64
+ def delete_cache(cache_handler="gridfs")
65
+ return "Mobilize::#{cache_handler.humanize}".constantize.delete(dst.handler, dst.path)
66
+ end
66
67
  end
67
68
  end
@@ -5,6 +5,8 @@ module Mobilize
5
5
  field :path, type: String
6
6
  field :active, type: Boolean
7
7
  field :trigger, type: String
8
+ field :status, type: String
9
+ field :last_completed_at, type: Time
8
10
 
9
11
  index({ path: 1})
10
12
 
@@ -13,9 +15,9 @@ module Mobilize
13
15
  j.path.split("/").last
14
16
  end
15
17
 
16
- def stages
18
+ def tasks
17
19
  j = self
18
- Stage.where(:path=>/^#{j.path.escape_regex}/).to_a.sort_by{|s| s.path}
20
+ Task.where(:path=>/^#{j.path.escape_regex}/).to_a.sort_by{|t| t.path}
19
21
  end
20
22
 
21
23
  def Job.find_or_create_by_path(path)
@@ -24,33 +26,6 @@ module Mobilize
24
26
  return j
25
27
  end
26
28
 
27
- def status
28
- #last stage status
29
- j = self
30
- j.active_stage.status if j.active_stage
31
- end
32
-
33
- def active_stage
34
- j = self
35
- #latest started at or first
36
- j.stages.select{|s| s.started_at}.sort_by{|s| s.started_at}.last || j.stages.first
37
- end
38
-
39
- def completed_at
40
- j = self
41
- j.stages.last.completed_at if j.stages.last
42
- end
43
-
44
- def failed_at
45
- j = self
46
- j.active_stage.failed_at if j.active_stage
47
- end
48
-
49
- def status_at
50
- j = self
51
- j.active_stage.status_at if j.active_stage
52
- end
53
-
54
29
  #convenience methods
55
30
  def runner
56
31
  j = self
@@ -60,13 +35,13 @@ module Mobilize
60
35
 
61
36
  def is_working?
62
37
  j = self
63
- j.stages.select{|s| s.is_working?}.compact.length>0
38
+ j.tasks.select{|t| t.is_working?}.compact.length>0
64
39
  end
65
40
 
66
41
  def is_due?
67
42
  j = self
68
43
  return false if j.is_working? or j.active == false or j.trigger.to_s.starts_with?("after")
69
- last_run = j.completed_at
44
+ last_run = j.last_completed_at
70
45
  #check trigger
71
46
  trigger = j.trigger
72
47
  return true if trigger == 'once'
@@ -5,19 +5,17 @@ module Mobilize
5
5
  field :path, type: String
6
6
  field :active, type: Boolean
7
7
  field :status, type: String
8
- field :started_at, type: Time
9
- field :status_at, type: Time
10
- field :completed_at, type: Time
8
+ field :last_run, type: Time
11
9
 
12
10
  index({ path: 1})
13
11
 
14
12
  def headers
15
- %w{name active trigger status stage1 stage2 stage3 stage4 stage5}
13
+ %w{name active trigger status task1 task2 task3 task4 task5}
16
14
  end
17
15
 
18
- def cached_at
16
+ def last_cached_at
19
17
  r = self
20
- Dataset.find_or_create_by_path(r.path).cached_at
18
+ Dataset.find_or_create_by_path(r.path).last_cached_at
21
19
  end
22
20
 
23
21
  def worker
@@ -41,7 +39,6 @@ module Mobilize
41
39
  r.update_status("no gdrive slot available")
42
40
  return false
43
41
  end
44
- r.update_attributes(:started_at=>Time.now.utc)
45
42
  #make sure any updates to activity are processed first
46
43
  #as in when someone runs a "once" job that has completed
47
44
  r.update_gsheet(gdrive_slot)
@@ -51,15 +48,15 @@ module Mobilize
51
48
  r.jobs.each do |j|
52
49
  begin
53
50
  if j.is_due?
54
- j.stages.first.enqueue!
51
+ j.tasks.first.enqueue!
55
52
  end
56
53
  rescue ScriptError, StandardError => exc
57
- r.update_status("Failed to enqueue #{j.path} with #{exc.to_s}")
54
+ j.update_status("Failed to enqueue with #{exc.to_s}")
58
55
  j.update_attributes(:active=>false)
59
56
  end
60
57
  end
61
58
  r.update_gsheet(gdrive_slot)
62
- r.update_attributes(:completed_at=>Time.now.utc)
59
+ r.update_attributes(:last_run=>Time.now.utc)
63
60
  end
64
61
 
65
62
  def dataset
@@ -71,16 +68,16 @@ module Mobilize
71
68
  Runner.where(:path=>path).first || Runner.create(:path=>path,:active=>true)
72
69
  end
73
70
 
74
- def cache
71
+ def read_cache
75
72
  r = self
76
- Dataset.find_or_create_by_url("gridfs://#{r.path}")
73
+ r.dataset.read_cache
77
74
  end
78
75
 
79
76
  def gsheet(gdrive_slot)
80
77
  r = self
81
78
  jobs_sheet = Gsheet.find_or_create_by_path(r.path,gdrive_slot)
82
79
  jobs_sheet.add_headers(r.headers)
83
- begin;jobs_sheet.delete_sheet1;rescue;end #don't care if sheet1 deletion fails
80
+ jobs_sheet.delete_sheet1
84
81
  return jobs_sheet
85
82
  end
86
83
 
@@ -88,7 +85,7 @@ module Mobilize
88
85
  r = self
89
86
  gsheet_tsv = r.gsheet(gdrive_slot).to_tsv
90
87
  #cache in DB
91
- r.cache.write(gsheet_tsv)
88
+ r.dataset.write_cache(gsheet_tsv)
92
89
  #turn it into a hash array
93
90
  gsheet_jobs = gsheet_tsv.tsv_to_hash_array
94
91
  #go through each job, update relevant job with its params
@@ -96,25 +93,25 @@ module Mobilize
96
93
  #parse out the jobs and update the Job collection
97
94
  gsheet_jobs.each_with_index do |rj,rj_i|
98
95
  #skip non-jobs or jobs without required values
99
- next if (rj['name'].to_s.first == "#" or ['name','active','trigger','stage1'].select{|c| rj[c].to_s.strip==""}.length>0)
96
+ next if (rj['name'].to_s.first == "#" or ['name','active','trigger','task1'].select{|c| rj[c].to_s.strip==""}.length>0)
100
97
  j = Job.find_or_create_by_path("#{r.path}/#{rj['name']}")
101
98
  #update top line params
102
99
  j.update_attributes(:active => rj['active'],
103
100
  :trigger => rj['trigger'])
104
- (1..5).to_a.each do |s_idx|
105
- stage_string = rj["stage#{s_idx.to_s}"]
106
- break if stage_string.to_s.length==0
107
- s = Stage.find_or_create_by_path("#{j.path}/stage#{s_idx.to_s}")
108
- #parse command string, update stage with it
109
- s_handler, call, param_string = [""*3]
110
- stage_string.split(" ").ie do |spls|
111
- s_handler = spls.first.split(".").first
101
+ (1..5).to_a.each do |t_idx|
102
+ task_string = rj["task#{t_idx.to_s}"]
103
+ break if task_string.to_s.length==0
104
+ t = Task.find_or_create_by_path("#{j.path}/task#{t_idx.to_s}")
105
+ #parse command string, update task with it
106
+ t_handler, call, param_string = [""*3]
107
+ task_string.split(" ").ie do |spls|
108
+ t_handler = spls.first.split(".").first
112
109
  call = spls.first.split(".").last
113
110
  param_string = spls[1..-1].join(" ").strip
114
111
  end
115
- s.update_attributes(:call=>call, :handler=>s_handler, :param_string=>param_string)
112
+ t.update_attributes(:call=>call, :handler=>t_handler, :param_string=>param_string)
116
113
  end
117
- r.update_status("Updated #{j.path} stages at #{Time.now.utc}")
114
+ r.update_status("Updated #{j.path} tasks at #{Time.now.utc}")
118
115
  #add this job to list of read ones
119
116
  done_jobs << j
120
117
  end
@@ -131,8 +128,7 @@ module Mobilize
131
128
  def update_gsheet(gdrive_slot)
132
129
  r = self
133
130
  jobs_gsheet = r.gsheet(gdrive_slot)
134
- upd_jobs = r.jobs.select{|j| j.status_at and j.status_at > j.runner.completed_at}
135
- upd_rows = upd_jobs.map{|j| {'name'=>j.name, 'active'=>j.active, 'status'=>j.status}}
131
+ upd_rows = r.jobs.map{|j| {'name'=>j.name, 'active'=>j.active, 'status'=>j.status} }
136
132
  jobs_gsheet.add_or_update_rows(upd_rows)
137
133
  r.update_status("gsheet updated")
138
134
  return true
@@ -151,12 +147,12 @@ module Mobilize
151
147
  def user
152
148
  r = self
153
149
  user_name = r.path.split("_").second.split("(").first.split("/").first
154
- User.where(:name=>user_name).first
150
+ User.where(:email=>[user_name,Gdrive.domain].join("@")).first
155
151
  end
156
152
 
157
153
  def update_status(msg)
158
154
  r = self
159
- r.update_attributes(:status=>msg, :status_at=>Time.now.utc)
155
+ r.update_attributes(:status=>msg)
160
156
  Mobilize::Resque.set_worker_args_by_path(r.path,{'status'=>msg})
161
157
  return true
162
158
  end
@@ -169,8 +165,8 @@ module Mobilize
169
165
  def is_due?
170
166
  r = self.reload
171
167
  return false if r.is_working?
172
- prev_due_time = Time.now.utc - Jobtracker.runner_read_freq
173
- return true if r.started_at.nil? or r.started_at < prev_due_time
168
+ last_due_time = Time.now.utc - Jobtracker.runner_read_freq
169
+ return true if r.last_run.nil? or r.last_run < last_due_time
174
170
  end
175
171
 
176
172
  def enqueue!
@@ -0,0 +1,137 @@
1
+ module Mobilize
2
+ class Task
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ field :path, type: String
6
+ field :handler, type: String
7
+ field :call, type: String
8
+ field :param_string, type: Array
9
+ field :status, type: String
10
+ field :last_completed_at, type: Time
11
+ field :last_run_at, type: Time
12
+
13
+ index({ path: 1})
14
+
15
+ def idx
16
+ t = self
17
+ t.path.split("/").last.gsub("task","").to_i
18
+ end
19
+
20
+ def stdout_dataset
21
+ t = self
22
+ Dataset.find_or_create_by_handler_and_path("gridfs","#{t.path}/stdout")
23
+ end
24
+
25
+ def stderr_dataset
26
+ t = self
27
+ Dataset.find_or_create_by_handler_and_path("gridfs","#{t.path}/stderr")
28
+ end
29
+
30
+ def params
31
+ t = self
32
+ t.param_string.split(",").map do |p|
33
+ ps = p.strip
34
+ ps = ps[1..-1] if ['"',"'"].include?(ps[0])
35
+ ps = ps[0..-2] if ['"',"'"].include?(ps[-1])
36
+ ps
37
+ end
38
+ end
39
+
40
+ def job
41
+ t = self
42
+ job_path = t.path.split("/")[0..-2].join("/")
43
+ Job.where(:path=>job_path).first
44
+ end
45
+
46
+ def Task.find_or_create_by_path(path)
47
+ t = Task.where(:path=>path).first
48
+ t = Task.create(:path=>path) unless t
49
+ return t
50
+ end
51
+
52
+ def prior
53
+ t = self
54
+ j = t.job
55
+ return nil if t.idx==1
56
+ return j.tasks[t.idx-2]
57
+ end
58
+
59
+ def next
60
+ t = self
61
+ j = t.job
62
+ return nil if t.idx == j.tasks.length
63
+ return j.tasks[t.idx]
64
+ end
65
+
66
+ def Task.perform(id,*args)
67
+ t = Task.where(:path=>id).first
68
+ j = t.job
69
+ t.update_status(%{Starting at #{Time.now.utc}})
70
+ stdout, stderr = [nil,nil]
71
+ begin
72
+ stdout = "Mobilize::#{t.handler.humanize}".constantize.send("#{t.call}_by_task_path",t.path).to_s
73
+ rescue ScriptError, StandardError => exc
74
+ stderr = [exc.to_s,exc.backtrace.to_s].join("\n")
75
+ #record the failure in Job so it appears on Runner
76
+ j.update_attributes(:status=>"Failed at #{Time.now.utc.to_s}")
77
+ t.update_attributes(:status=>"Failed at #{Time.now.utc.to_s}")
78
+ raise exc
79
+ end
80
+ if stdout == false
81
+ #re-queue self if output is false
82
+ t.enqueue!
83
+ return false
84
+ end
85
+ #write output to cache
86
+ t.stdout_dataset.write_cache(stdout)
87
+ t.update_attributes(:status=>"Completed at #{Time.now.utc.to_s}")
88
+ if t.idx == j.tasks.length
89
+ j.update_attributes(:status=>"Completed at #{Time.now.utc.to_s}",:last_completed_at=>Time.now.utc)
90
+ j.update_attributes(:active=>false) if j.trigger.strip == "once"
91
+ t.update_attributes(:status=>"Completed at #{Time.now.utc.to_s}",:last_completed_at=>Time.now.utc)
92
+ #check for any dependent jobs, if there are, enqueue them
93
+ r = j.runner
94
+ dep_jobs = r.jobs.select{|dj| dj.active==true and dj.trigger=="after #{j.name}"}
95
+ #put begin/rescue so all dependencies run
96
+ dep_jobs.each{|dj| begin;dj.tasks.first.enqueue! unless dj.is_working?;rescue;end}
97
+ else
98
+ #queue up next task
99
+ t.next.enqueue!
100
+ end
101
+ return true
102
+ end
103
+
104
+ def enqueue!
105
+ t = self
106
+ ::Resque::Job.create("mobilize",Task,t.path,{})
107
+ return true
108
+ end
109
+
110
+ def worker
111
+ t = self
112
+ Mobilize::Resque.find_worker_by_path(t.path)
113
+ end
114
+
115
+ def worker_args
116
+ t = self
117
+ Jobtracker.get_worker_args(t.worker)
118
+ end
119
+
120
+ def set_worker_args(args)
121
+ t = self
122
+ Jobtracker.set_worker_args(t.worker,args)
123
+ end
124
+
125
+ def update_status(msg)
126
+ t = self
127
+ t.update_attributes(:status=>msg)
128
+ Mobilize::Resque.set_worker_args_by_path(t.path,{'status'=>msg})
129
+ return true
130
+ end
131
+
132
+ def is_working?
133
+ t = self
134
+ Mobilize::Resque.active_paths.include?(t.path)
135
+ end
136
+ end
137
+ end
@@ -24,7 +24,7 @@ module Mobilize
24
24
 
25
25
  def jobs(jname=nil)
26
26
  u = self
27
- return u.runner.jobs
27
+ return u.runners.map{|r| r.jobs(jname)}.flatten
28
28
  end
29
29
 
30
30
  def runner_path
@@ -1,3 +1,6 @@
1
+ # require 'resque/tasks'
2
+ # will give you the resque tasks
3
+
1
4
  namespace :mobilize_base do
2
5
  desc "Start a Resque worker"
3
6
  task :work do
@@ -8,7 +11,6 @@ namespace :mobilize_base do
8
11
  require e
9
12
  end
10
13
  rescue Exception=>exc
11
- #do nothing
12
14
  end
13
15
 
14
16
  begin
@@ -21,42 +23,17 @@ namespace :mobilize_base do
21
23
 
22
24
  worker.work(ENV['INTERVAL'] || 5) # interval, will block
23
25
  end
24
- desc "Kill all Resque workers"
25
- task :kill_workers do
26
- require 'mobilize-base'
27
- Mobilize::Jobtracker.kill_workers
28
- end
29
26
  desc "Kill idle workers not in sync with repo"
30
27
  task :kill_idle_and_stale_workers do
31
28
  require 'mobilize-base'
32
29
  Mobilize::Jobtracker.kill_idle_and_stale_workers
33
30
  end
34
- desc "Kill idle workers"
35
- task :kill_idle_workers do
36
- require 'mobilize-base'
37
- Mobilize::Jobtracker.kill_idle_workers
38
- end
39
- desc "Make sure there are the correct # of workers, kill if too many"
31
+ desc "Make sure workers are prepped"
40
32
  task :prep_workers do
41
33
  require 'mobilize-base'
42
34
  Mobilize::Jobtracker.prep_workers
43
35
  end
44
- desc "Stop Jobtracker"
45
- task :stop do
46
- require 'mobilize-base'
47
- Mobilize::Jobtracker.stop!
48
- end
49
- desc "Start Jobtracker"
50
- task :start do
51
- require 'mobilize-base'
52
- Mobilize::Jobtracker.start
53
- end
54
- desc "Restart Jobtracker"
55
- task :restart do
56
- require 'mobilize-base'
57
- Mobilize::Jobtracker.restart!
58
- end
59
- desc "kill all old resque web processes, start new one with resque_web.rb extension file"
36
+ desc "kill all old resque web, start new one with env params"
60
37
  task :resque_web do
61
38
  require 'mobilize-base'
62
39
  port = Mobilize::Base.config('resque')['web_port']
@@ -75,7 +52,9 @@ namespace :mobilize_base do
75
52
  "Mobilize::#{m}".constantize.create_indexes
76
53
  end
77
54
  end
78
- desc "Set up config and log folders and files, populate from samples"
55
+ end
56
+ namespace :mobilize do
57
+ desc "Set up config and log folders and files"
79
58
  task :setup do
80
59
  config_dir = (ENV['MOBILIZE_CONFIG_DIR'] ||= "config/mobilize/")
81
60
  log_dir = (ENV['MOBILIZE_LOG_DIR'] ||= "log/")
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'mobilize-base/tasks'
@@ -1,5 +1,5 @@
1
1
  module Mobilize
2
2
  module Base
3
- VERSION = "1.0.9"
3
+ VERSION = "1.0.51"
4
4
  end
5
5
  end
data/lib/mobilize-base.rb CHANGED
@@ -66,7 +66,7 @@ if File.exists?(mongoid_config_path)
66
66
  require "mobilize-base/models/user"
67
67
  require "mobilize-base/models/runner"
68
68
  require "mobilize-base/models/job"
69
- require "mobilize-base/models/stage"
69
+ require "mobilize-base/models/task"
70
70
  end
71
71
  require 'google_drive'
72
72
  require 'resque'
@@ -29,6 +29,7 @@ Gem::Specification.new do |s|
29
29
  s.add_runtime_dependency 'redis',"~>3.0.0"
30
30
  s.add_runtime_dependency 'resque','1.21.0'
31
31
  s.add_runtime_dependency 'google_drive','0.3.2'
32
+ s.add_runtime_dependency 'bluepill','0.0.60'
32
33
  s.add_runtime_dependency 'popen4','0.1.2'
33
34
  s.add_runtime_dependency 'actionmailer','3.1.1'
34
35
  end
@@ -0,0 +1,3 @@
1
+ - {test_header: t1, test_header2: t1, test_header3: t1}
2
+ - {test_header: t2, test_header2: t2, test_header3: t2}
3
+ - {test_header: t3, test_header2: t3, test_header3: t3}
@@ -2,12 +2,12 @@
2
2
  active: true
3
3
  trigger: once
4
4
  status: ""
5
- stage1: 'gsheet.read source:"Runner_mobilize(test)/base1_stage1.in"'
6
- stage2: 'gsheet.write source:"base1/stage1", target:"Runner_mobilize(test)/base1.out"'
5
+ task1: 'gsheet.read "Runner_mobilize(test)/base1_task1.in"'
6
+ task2: 'gsheet.write "base1/task1", "Runner_mobilize(test)/base1.out"'
7
7
 
8
8
  - name: "base2"
9
9
  active: true
10
10
  trigger: "after base1"
11
11
  status: ""
12
- stage1: 'gsheet.read source:"Runner_mobilize(test)/base1.out"'
13
- stage2: 'gsheet.write source:"stage1", target:"Runner_mobilize(test)/base2.out"'
12
+ task1: 'gsheet.read "Runner_mobilize(test)/base1.out"'
13
+ task2: 'gsheet.write "task1", "Runner_mobilize(test)/base2.out"'
@@ -32,35 +32,27 @@ describe "Mobilize" do
32
32
  r = u.runner
33
33
  jobs_sheet = r.gsheet(gdrive_slot)
34
34
  tsv = jobs_sheet.to_tsv
35
- assert tsv.length == 61 #headers only
35
+ assert tsv.length == 56 #headers only
36
36
 
37
- puts "add base1_stage1 input sheet"
38
- test_source_sheet = Mobilize::Gsheet.find_or_create_by_path("#{r.path.split("/")[0..-2].join("/")}/base1_stage1.in",gdrive_slot)
37
+ puts "add base1_task1 input sheet"
38
+ test_source_sheet = Mobilize::Gsheet.find_or_create_by_path("#{r.path.split("/")[0..-2].join("/")}/base1_task1.in",gdrive_slot)
39
39
 
40
- test_source_ha = ::YAML.load_file("#{Mobilize::Base.root}/test/base1_stage1.yml")*40
40
+ test_source_ha = ::YAML.load_file("#{Mobilize::Base.root}/test/base1_task1.yml")*40
41
41
  test_source_tsv = test_source_ha.hash_array_to_tsv
42
42
  test_source_sheet.write(test_source_tsv)
43
43
 
44
44
  puts "add row to jobs sheet, wait 120s"
45
45
  test_job_rows = ::YAML.load_file("#{Mobilize::Base.root}/test/base_job_rows.yml")
46
46
  jobs_sheet.add_or_update_rows(test_job_rows)
47
+
48
+ puts "job row added, force enqueued runner"
49
+ r.enqueue!
47
50
  sleep 120
48
51
 
49
52
  puts "jobtracker posted test sheet data to test destination, and checksum succeeded?"
50
- test_target_sheet_1 = Mobilize::Gsheet.find_by_path("#{r.path.split("/")[0..-2].join("/")}/base1.out",gdrive_slot)
51
- test_target_sheet_2 = Mobilize::Gsheet.find_by_path("#{r.path.split("/")[0..-2].join("/")}/base2.out",gdrive_slot)
52
-
53
- assert test_target_sheet_1.to_tsv == test_source_sheet.to_tsv
53
+ test_target_sheet = Mobilize::Gsheet.find_by_path("#{r.path.split("/")[0..-2].join("/")}/base1.out",gdrive_slot)
54
54
 
55
- puts "delete both output sheets, set first job to active=true"
56
- [test_target_sheet_1,test_target_sheet_2].each{|s| s.delete}
57
-
58
- jobs_sheet.add_or_update_rows([{'name'=>'base1','active'=>true}])
59
- sleep 90
60
-
61
- test_target_sheet_2 = Mobilize::Gsheet.find_by_path("#{r.path.split("/")[0..-2].join("/")}/base1.out",gdrive_slot)
62
- puts "jobtracker posted test sheet data to test destination, and checksum succeeded?"
63
- assert test_target_sheet_2.to_tsv == test_source_sheet.to_tsv
55
+ assert test_target_sheet.to_tsv == test_source_sheet.to_tsv
64
56
 
65
57
  end
66
58
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mobilize-base
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.9
4
+ version: 1.0.51
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-22 00:00:00.000000000 Z
12
+ date: 2012-12-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -139,6 +139,22 @@ dependencies:
139
139
  - - '='
140
140
  - !ruby/object:Gem::Version
141
141
  version: 0.3.2
142
+ - !ruby/object:Gem::Dependency
143
+ name: bluepill
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - '='
148
+ - !ruby/object:Gem::Version
149
+ version: 0.0.60
150
+ type: :runtime
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - '='
156
+ - !ruby/object:Gem::Version
157
+ version: 0.0.60
142
158
  - !ruby/object:Gem::Dependency
143
159
  name: popen4
144
160
  requirement: !ruby/object:Gem::Requirement
@@ -207,9 +223,10 @@ files:
207
223
  - lib/mobilize-base/models/dataset.rb
208
224
  - lib/mobilize-base/models/job.rb
209
225
  - lib/mobilize-base/models/runner.rb
210
- - lib/mobilize-base/models/stage.rb
226
+ - lib/mobilize-base/models/task.rb
211
227
  - lib/mobilize-base/models/user.rb
212
- - lib/mobilize-base/tasks.rb
228
+ - lib/mobilize-base/rakes.rb
229
+ - lib/mobilize-base/tasks/mobilize-base.rake
213
230
  - lib/mobilize-base/version.rb
214
231
  - lib/samples/gdrive.yml
215
232
  - lib/samples/gridfs.yml
@@ -219,7 +236,7 @@ files:
219
236
  - lib/samples/resque.yml
220
237
  - lib/samples/resque_web.rb
221
238
  - mobilize-base.gemspec
222
- - test/base1_stage1.yml
239
+ - test/base1_task1.yml
223
240
  - test/base_job_rows.yml
224
241
  - test/mobilize-base_test.rb
225
242
  - test/redis-test.conf
@@ -238,7 +255,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
238
255
  version: '0'
239
256
  segments:
240
257
  - 0
241
- hash: 576426973092652786
258
+ hash: -989061027210314242
242
259
  required_rubygems_version: !ruby/object:Gem::Requirement
243
260
  none: false
244
261
  requirements:
@@ -247,7 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
247
264
  version: '0'
248
265
  segments:
249
266
  - 0
250
- hash: 576426973092652786
267
+ hash: -989061027210314242
251
268
  requirements: []
252
269
  rubyforge_project: mobilize-base
253
270
  rubygems_version: 1.8.24
@@ -256,7 +273,7 @@ specification_version: 3
256
273
  summary: Moves datasets and schedules data transfers using MongoDB, Resque and Google
257
274
  Docs
258
275
  test_files:
259
- - test/base1_stage1.yml
276
+ - test/base1_task1.yml
260
277
  - test/base_job_rows.yml
261
278
  - test/mobilize-base_test.rb
262
279
  - test/redis-test.conf
@@ -1,141 +0,0 @@
1
- module Mobilize
2
- class Stage
3
- include Mongoid::Document
4
- include Mongoid::Timestamps
5
- field :path, type: String
6
- field :handler, type: String
7
- field :call, type: String
8
- field :param_string, type: Array
9
- field :status, type: String
10
- field :out_url, type: String
11
- field :completed_at, type: Time
12
- field :started_at, type: Time
13
- field :failed_at, type: Time
14
- field :status_at, type: Time
15
-
16
- index({ path: 1})
17
-
18
- def idx
19
- s = self
20
- s.path.split("/").last.gsub("stage","").to_i
21
- end
22
-
23
- def out_dst
24
- #this gives a dataset that points to the output
25
- #allowing you to determine its size
26
- #before committing to a read or write
27
- s = self
28
- Dataset.find_by_url(s.out_url) if s.out_url
29
- end
30
-
31
- def params
32
- s = self
33
- #evaluates param_string to ruby hash
34
- #using YAML parser
35
- #TODO: eliminate ridiculousness
36
- begin
37
- YAML.load(s.param_string)
38
- raise "Must resolve to Hash" unless result.class==Hash
39
- rescue
40
- sub_param_string = s.param_string.gsub(":\"",": \"").gsub(":'",": '").gsub(":[",": [").gsub(":{",": {").gsub(/(:[0-9])/,'stageparamsgsub\1').gsub('stageparamsgsub:',': ')
41
- YAML.load("{#{sub_param_string}}")
42
- end
43
- end
44
-
45
- def job
46
- s = self
47
- job_path = s.path.split("/")[0..-2].join("/")
48
- Job.where(:path=>job_path).first
49
- end
50
-
51
- def Stage.find_or_create_by_path(path)
52
- s = Stage.where(:path=>path).first
53
- s = Stage.create(:path=>path) unless s
54
- return s
55
- end
56
-
57
- def prior
58
- s = self
59
- j = s.job
60
- return nil if s.idx==1
61
- return j.stages[s.idx-2]
62
- end
63
-
64
- def next
65
- s = self
66
- j = s.job
67
- return nil if s.idx == j.stages.length
68
- return j.stages[s.idx]
69
- end
70
-
71
- def Stage.perform(id,*args)
72
- s = Stage.where(:path=>id).first
73
- j = s.job
74
- s.update_attributes(:started_at=>Time.now.utc)
75
- s.update_status(%{Starting at #{Time.now.utc}})
76
- begin
77
- #get response by running method
78
- s.out_url = "Mobilize::#{s.handler.humanize}".constantize.send("#{s.call}_by_stage_path",s.path)
79
- s.save!
80
- unless s.out_url
81
- #re-queue self if no response
82
- s.enqueue!
83
- return false
84
- end
85
- rescue ScriptError, StandardError => exc
86
- j.update_attributes(:active=>false)
87
- s.update_attributes(:failed_at=>Time.now.utc)
88
- s.update_status("Failed at #{Time.now.utc.to_s}")
89
- raise exc
90
- end
91
- s.update_attributes(:completed_at=>Time.now.utc)
92
- s.update_status("Completed at #{Time.now.utc.to_s}")
93
- if s.idx == j.stages.length
94
- #job has completed
95
- j.update_attributes(:active=>false) if j.trigger.strip.downcase == "once"
96
- #check for any dependent jobs, if there are, enqueue them
97
- r = j.runner
98
- dep_jobs = r.jobs.select{|dj| dj.active==true and dj.trigger.strip.downcase == "after #{j.name}"}
99
- #put begin/rescue so all dependencies run
100
- dep_jobs.each{|dj| begin;dj.stages.first.enqueue! unless dj.is_working?;rescue;end}
101
- else
102
- #queue up next stage
103
- s.next.enqueue!
104
- end
105
- return true
106
- end
107
-
108
- def enqueue!
109
- s = self
110
- ::Resque::Job.create("mobilize",Stage,s.path,{})
111
- return true
112
- end
113
-
114
- def worker
115
- s = self
116
- Mobilize::Resque.find_worker_by_path(s.path)
117
- end
118
-
119
- def worker_args
120
- s = self
121
- Jobtracker.get_worker_args(s.worker)
122
- end
123
-
124
- def set_worker_args(args)
125
- s = self
126
- Jobtracker.set_worker_args(s.worker,args)
127
- end
128
-
129
- def update_status(msg)
130
- s = self
131
- s.update_attributes(:status=>msg,:status_at=>Time.now.utc)
132
- Mobilize::Resque.set_worker_args_by_path(s.path,{'status'=>msg})
133
- return true
134
- end
135
-
136
- def is_working?
137
- s = self
138
- Mobilize::Resque.active_paths.include?(s.path)
139
- end
140
- end
141
- end
@@ -1,3 +0,0 @@
1
- - {test_header: s1, test_header2: s1, test_header3: s1}
2
- - {test_header: s2, test_header2: s2, test_header3: s2}
3
- - {test_header: s3, test_header2: s3, test_header3: s3}