manband 0.6.1 → 0.7.0

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.
data/README CHANGED
@@ -108,6 +108,9 @@ Webband may use this gem, or use current files with same hierarchy
108
108
 
109
109
  ## History
110
110
 
111
+ 0.7:
112
+ Add IF management
113
+ Fix some message dispatching issues
111
114
  0.6.1: Increase file path max size
112
115
  0.6.0: Remove mb-minion dependency. New bunny gem is incompatible now, code has been rewriten to remove the dependency and use only amqp.
113
116
 
data/bin/env.sh ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+
3
+ MYSQL_URL=mysql://root:neptune@localhost/genflow
4
+ AMQP_URL=amqp://guest:guest@localhost/
5
+
6
+ export MYSQL_URL
7
+ export AMQP_URL
data/bin/jobhandler.rb CHANGED
@@ -28,7 +28,7 @@ require 'manband/store.rb'
28
28
  handler = Time.now.to_s
29
29
 
30
30
  log = Logger.new(STDOUT)
31
- log.level = Logger::INFO
31
+ log.level = Logger::DEBUG
32
32
 
33
33
  options = {}
34
34
 
@@ -116,7 +116,8 @@ EventMachine.run do
116
116
  exchange = channel.direct()
117
117
  queue = channel.queue('manband.node'+options[:queue], :auto_delete => false, :durable => true)
118
118
  queue.bind(exchange).subscribe(:ack => true) do |metadata, message|
119
- puts "##DEBUG "+message
119
+ log.debug "Received msg: "+message.to_s
120
+ doack = true
120
121
  args = JSON.parse(message)
121
122
  msg = JSON.parse(args["msg"])
122
123
  if args["operation"] == OP_DESTROY
@@ -137,6 +138,8 @@ EventMachine.run do
137
138
  log.error "Error: job does not exists "+msg["id"]
138
139
  else
139
140
  if args["operation"] == OP_RUN
141
+ myjob.setAck(channel,metadata.delivery_tag)
142
+ doack = false
140
143
  if msg["instance"]!=nil
141
144
  myjob.run(handler, msg["instance"].to_i)
142
145
  else
@@ -153,7 +156,9 @@ EventMachine.run do
153
156
  end
154
157
 
155
158
 
156
- channel.acknowledge(metadata.delivery_tag, false)
159
+ if doack
160
+ channel.acknowledge(metadata.delivery_tag, false)
161
+ end
157
162
  end
158
163
 
159
164
  end
@@ -30,7 +30,7 @@ require 'manband/job.rb'
30
30
  require 'manband/bandmanager.rb'
31
31
 
32
32
  log = Logger.new(STDOUT)
33
- log.level = Logger::INFO
33
+ log.level = Logger::DEBUG
34
34
 
35
35
 
36
36
  @@options = {}
@@ -108,6 +108,7 @@ EventMachine.run do
108
108
  queue.bind(exchange).subscribe(:ack => true) do |metadata, message|
109
109
 
110
110
  begin
111
+ log.debug "Received msg: "+message.to_s
111
112
  args = JSON.parse(message)
112
113
  msg = JSON.parse(args["msg"])
113
114
  rescue Exception => e
@@ -130,12 +131,12 @@ EventMachine.run do
130
131
  end
131
132
  if args["operation"] == OP_SKIP
132
133
  savemessage(msg["id"],args["operation"],args["msg"])
133
- workflow = WorkFlow.get(msg["id"])
134
+ workflow = WorkFlow.get(msg["workflow"])
134
135
  if workflow == nil
135
- log.error "Error: workflow does not exists "+msg["id"]
136
+ log.error "Error: workflow does not exists "+msg["workflow"]
136
137
  else
137
138
  workflow.update(:status => STATUS_RUNNING)
138
- myjob = Job.get(msg["root"])
139
+ myjob = Job.get(msg["id"])
139
140
  myjob.runnext(true)
140
141
  end
141
142
  end
@@ -156,15 +157,19 @@ EventMachine.run do
156
157
  if args["operation"] == OP_FINISH
157
158
  savemessage(msg["workflow"],args["operation"],args["msg"])
158
159
  myjob = Job.get(msg["id"])
160
+ doSkip = false
159
161
  if myjob == nil
160
162
  log.error "Error: job does not exists "+msg["id"]
161
163
  else
164
+ if myjob.status == STATUS_SKIP
165
+ doSkip = true
166
+ end
162
167
  if msg["handler"]!=nil && myjob.handler != msg["handler"]
163
168
  log.debug "Finish received from a different handler "+myjob.handler+" vs "+msg["handler"]+", skipping message"
164
169
  else
165
170
  myjob.finish
166
171
  if myjob.isover?
167
- myjob.runnext
172
+ myjob.runnext(doSkip)
168
173
  end
169
174
  end
170
175
  end
@@ -134,9 +134,10 @@ class BandManager
134
134
  # Request workflow management
135
135
  msg = '{ "id" : "'+workflow.id.to_s+'", "root" : "'+rootjob.id.to_s+'"}'
136
136
  if debug
137
+ msg = '{ "id" : "'+rootjob.id.to_s+'","workflow" : "'+workflow.id.to_s+'", "node" : "'+rootjob.id.to_s+'"}'
137
138
  Utils.publish("manband.master", { "operation" => OP_SKIP, "msg" => msg })
138
139
  else
139
- Utils.publish("manband.master", { "operation" => OP_START, "msg" => msg })
140
+ Utils.publish("manband.master", { "operation" => OP_START, "msg" => msg })
140
141
  end
141
142
  end
142
143
  end
@@ -35,6 +35,13 @@ OP_CLEAN = "clean" # Delete work dirs of workflow
35
35
  OP_DESTROY = "destroy" # Delete workflow and its work dirs
36
36
  OP_STORE = "store" # Store result to S3
37
37
 
38
+ # Basic actor
39
+ ACTOR = -1
40
+ # If actor, i.e. ony one of the following jobs will be executed. Selected job match the exit code of the command. Type of the node will be set to selected output
41
+ # WARNING: input of IF actors MUST NOT be a pattern matchng multiple files. The IF condition must be executed only once, not on a bunch of files.
42
+ IF_ACTOR = -2
43
+
44
+
38
45
  # This class holds the base config
39
46
  class FlowConfig
40
47
  @@workdir='/tmp'
data/lib/manband/job.rb CHANGED
@@ -34,7 +34,19 @@ class Job
34
34
  end
35
35
 
36
36
  @@log = Logger.new(STDOUT)
37
- @@log.level = Logger::INFO
37
+ @@log.level = Logger::DEBUG
38
+
39
+ @channel = nil
40
+ @delivery_tag = nil
41
+
42
+ def setAck(channel,tag)
43
+ @channel = channel
44
+ @tag = tag
45
+ end
46
+
47
+ def ack()
48
+ @channel.acknowledge(@tag, false)
49
+ end
38
50
 
39
51
  property :id, Serial
40
52
  property :wid, Integer # id of the worflow
@@ -48,6 +60,7 @@ class Job
48
60
  property :queue, String, :default => "" # Queue to handle the job
49
61
  property :error, Text, :default => "[]" # JSON Array of error, per instance
50
62
  property :store, Integer, :default => STORE_NO # Storage status
63
+ property :type, Integer, :default => ACTOR # Type of the job
51
64
 
52
65
  # Update job status and launch the command locally
53
66
  # Sends a finish message or an error message according to the job status.
@@ -67,9 +80,17 @@ class Job
67
80
  if instance>0
68
81
  workdir = workdir + "/node" + instance.to_s
69
82
  end
83
+
70
84
  EventMachine.defer do
71
85
  err = runcommand(workdir,instance)
72
- if err == nil || err == false
86
+ # In the case of IF_ACTOR, exit code is not an error
87
+ # but the job to select. Reset error code after updating the type.
88
+ if @type == IF_ACTOR
89
+ @type = err + 1
90
+ curjob.update(:type => (err + 1))
91
+ err = 0
92
+ end
93
+ if err == nil || err > 0
73
94
  # An error occured
74
95
  jobmsg = '{ "workflow" : "'+@wid.to_s+'" , "node" : "'+@node+'", "id" : "'+@id.to_s+'", "handler" : "'+curhandler.to_s+'", "instance" : "'+instance.to_s+'" }'
75
96
  sendmessage(OP_ERROR,jobmsg)
@@ -82,6 +103,7 @@ class Job
82
103
  jobmsg = '{ "workflow" : "'+@wid.to_s+'" , "node" : "'+@node+'", "id" : "'+@id.to_s+'", "handler" : "'+curhandler.to_s+'", "instance" : "'+instance.to_s+'" }'
83
104
  sendmessage(OP_FINISH,jobmsg)
84
105
  end
106
+ ack()
85
107
  end # End EventMachine
86
108
  end
87
109
 
@@ -119,6 +141,7 @@ class Job
119
141
  end
120
142
  @@log.debug cmd
121
143
  system(cmd)
144
+ return $?.exitstatus
122
145
  end
123
146
 
124
147
  # Change instance counter
@@ -245,12 +268,17 @@ class Job
245
268
  workflow.isover?
246
269
  return true
247
270
  end
271
+ # Which next job is it?
272
+ # Start at 1 because 0 is a valid status code, consider if type from value 1
273
+ count = 1
274
+ # For each job to follow
248
275
  nexts.each do |link|
249
276
  job = Job.get(link.to)
250
277
  #nexts.each do |nextnode|
251
278
  #nextnode.strip!
252
279
  #queue = workflow.getnodequeue(nextnode)
253
- if skip==true || @status == STATUS_SKIP
280
+ # Explicit skip, or IF actor, we skip all actors but one
281
+ if skip==true || @status == STATUS_SKIP || (@type>0 && count!= @type)
254
282
  jobstatus = STATUS_SKIP
255
283
  operation = OP_SKIP
256
284
  commands = [ "skipcommand"]
@@ -259,6 +287,7 @@ class Job
259
287
  operation = OP_RUN
260
288
  commands = workflow.getnodecommand(job.node)
261
289
  end
290
+ count=count+1
262
291
  if commands == nil
263
292
  @@log.error "Could not get command for node "+job.id.to_s
264
293
  job.update(:command => "", :status => STATUS_ERROR, :instances => 0, :maxinstances => 0, :workdir => FlowConfig.getjobdir(workflow.workdir))
@@ -293,6 +322,7 @@ class Job
293
322
  queue = "manband.node"+jobqueue
294
323
  end
295
324
  if queue != nil
325
+ @@log.debug "Send #"+operation+","+msg
296
326
  Utils.enqueue(queue, { "operation" => operation, "msg" => msg })
297
327
  logMessage(operation,msg)
298
328
  end
data/lib/manband/store.rb CHANGED
@@ -11,7 +11,7 @@ require 'manband/user.rb'
11
11
  class Storeband
12
12
 
13
13
  @@log = Logger.new(STDOUT)
14
- @@log.level = Logger::DEBUG
14
+ @@log.level = Logger::INFO
15
15
 
16
16
  # Compress a directory
17
17
  def compress(dir,name)
data/lib/manband/util.rb CHANGED
@@ -26,7 +26,8 @@ class Utils
26
26
  msg = data.to_json
27
27
  queue = @@channel.queue(dest, :auto_delete => false, :durable => true)
28
28
  queue.bind(@@exchange)
29
- @@exchange.publish(msg)
29
+ #@@exchange.publish(msg, :routing_key => dest)
30
+ @@channel.direct("").publish(msg, :routing_key => dest)
30
31
  end
31
32
 
32
33
  # Creates a context and sends a message
@@ -38,10 +39,11 @@ class Utils
38
39
  EventMachine.run do
39
40
  connection = AMQP.connect(FlowConfig.config())
40
41
  channel = AMQP::Channel.new(connection)
41
- exchange = channel.direct()
42
- queue = channel.queue(dest, :auto_delete => false, :durable => true)
43
- queue.bind(exchange)
44
- exchange.publish(msg) do
42
+ #exchange = channel.direct()
43
+ #queue = channel.queue(dest, :auto_delete => false, :durable => true)
44
+ #queue.bind(exchange)
45
+ #exchange.publish(msg, :routing_key => dest) do
46
+ channel.direct("").publish(msg, :routing_key => dest) do
45
47
  connection.close { EventMachine.stop }
46
48
  end
47
49
  end
@@ -19,7 +19,7 @@ class WorkFlow
19
19
  include DataMapper::Resource
20
20
 
21
21
  @@log = Logger.new(STDOUT)
22
- @@log.level = Logger::INFO
22
+ @@log.level = Logger::DEBUG
23
23
 
24
24
  property :id, Serial # An auto-increment integer key
25
25
  property :uid, Text # user id
@@ -109,11 +109,15 @@ class WorkFlow
109
109
  @@log.debug "Add store option for job "+job
110
110
  store = STORE_DO
111
111
  end
112
+ type = ACTOR
113
+ if fworkflow["workflow"][job]["type"]=='if'
114
+ type = IF_ACTOR
115
+ end
112
116
  workdir = FlowConfig.getjobdir(@workdir)
113
117
  if curnode == "root"
114
118
  workdir = self.workdir + "/root";
115
119
  end
116
- newjob = Job.new(:wid => @id, :node => job, :command => "", :status => status, :instances => 0, :maxinstances => 0, :queue => queue, :workdir => FlowConfig.getjobdir(@workdir), :store => store)
120
+ newjob = Job.new(:wid => @id, :node => job, :command => "", :status => status, :instances => 0, :maxinstances => 0, :queue => queue, :workdir => FlowConfig.getjobdir(@workdir), :store => store, :type => type)
117
121
  newjob.save
118
122
  if id != nil
119
123
  @@log.debug "Add link "+id.to_s+"->"+newjob.id.to_s+","+newjob.node
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manband
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
- - 6
9
- - 1
10
- version: 0.6.1
8
+ - 7
9
+ - 0
10
+ version: 0.7.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Olivier Sallou
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-07-17 00:00:00 Z
18
+ date: 2012-07-18 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: amqp
@@ -125,6 +125,7 @@ extra_rdoc_files:
125
125
  - README
126
126
  - LICENSE
127
127
  files:
128
+ - bin/env.sh
128
129
  - bin/manband.rb
129
130
  - bin/remoteband.rb
130
131
  - bin/jobhandler.rb