gorgon 0.8.4 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ODE4OGJiNzI0ZTBkNmRhYjJjNGJkNzg0Y2FjNmQ0M2ZlYWY2Mjk0NA==
4
+ NTA0MWUwMjQ4ZmIzZmM0ZjAyYWJjOWYxMTA1NWQwZGFiZTQ0MzQ5Yg==
5
5
  data.tar.gz: !binary |-
6
- NjVkNjkwNGE1ZTE0N2NmMTNjNzE3ZjExYWVkMjYwZjUzYTE3NjdjZA==
6
+ MTA4NGNjZjU2OWQxOWQxMmZkYTlkOGNjYjI0MmIxYTI5ODMzZGEzYQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NDQxMzVmNjk2YTM3NThjZWNkMjkxNDc5MzVlMWE2ZWIwZmZhOWU0ZjJhZTlj
10
- MWYxZDZmM2RkNTFlNDJmM2FhNWIxZDJkODA4NTIyZjVhYzgzYmQ2NGY4Zjgy
11
- MzBkMzg0ZmE3MjU5ODdjOTBhYjA0MGY1MTRiYjg2OThlZmEwMmY=
9
+ N2U2ZWZlMWNkNDI2YTEyOTkwNGYwZjQwNGI0NWJmMGEzOGI0ZDg2YTA0MWYw
10
+ MDgxNGQzMTcwOTZmYmY3OTk4MzY3YTk3NDBmNjEyYjhlMjQwMGEwNDQ0Y2Jk
11
+ MGJhYTk3M2EyZWE2ZjU5MzZiNTAyNWNhOTdkZTYzYWU0YzViYzk=
12
12
  data.tar.gz: !binary |-
13
- NTM0ZDExMTcyMTM4MGIyNzU1ZmRjM2RkZTY4NTU2NGUxYTJjYzQ5YzliZmEy
14
- ZmVjMmVjMGQ1NWI2N2U5YjdhNTc2YWU1YmY4NmI5ZGQ0MWU4ZGQwMDM3ODcw
15
- MjU3Njg3OTE1ZDAwZWMyMWE4ZjQ5ZTM2Mzk3ZTFmZTZmYTUzYTE=
13
+ Mzg3NDc4MWZjNzE0MDYwMjZmNWMzMjE1MzNhY2JkYTU2MzBhZTQ0ZmYzNTdm
14
+ MjdkYTM3YTY5MWVlMjE2ZjRiZjMyYjdmMDNjZDZmMTQ4ODM5Njk3NGU0ZjIy
15
+ MmYyMDYxOTJkNGFiMzVjZjgxZWRlMDk3NzZhMzQ3M2E5NzEwNjk=
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gorgon (0.8.4)
4
+ gorgon (0.9.0)
5
5
  amqp (~> 1.1.0)
6
6
  awesome_print
7
7
  colorize (~> 0.5.8)
@@ -17,10 +17,10 @@ GEM
17
17
  amqp (1.1.8)
18
18
  amq-protocol (>= 1.9.2)
19
19
  eventmachine
20
- awesome_print (1.2.0)
20
+ awesome_print (1.6.1)
21
21
  colorize (0.5.8)
22
22
  diff-lcs (1.1.3)
23
- eventmachine (1.0.4)
23
+ eventmachine (1.0.7)
24
24
  open4 (1.3.4)
25
25
  rake (0.9.2.2)
26
26
  rspec (2.11.0)
data/README.md CHANGED
@@ -21,7 +21,7 @@ Installing listener as a Daemon process (Ubuntu 9.10 or later)
21
21
  Gotchas
22
22
  ----------------------------------------------------------------
23
23
 
24
- * if you get `cannot load such file -- qrack/qrack (LoadError)`, just add `gem 'gorgon', '~> 0.8.3' , :group => :remote_test` to your Gemfile, and run tests using `bundle exec gorgon`
24
+ * if you get `cannot load such file -- qrack/qrack (LoadError)`, just add `gem 'gorgon', '~> 0.8.4' , :group => :remote_test` to your Gemfile, and run tests using `bundle exec gorgon`
25
25
  * If `gorgon install_listener` didn't work for you, you can try [these steps](/daemon_with_upstart_and_rvm.md)
26
26
 
27
27
  Also note that the steps in the tutorial are **not** meant to work on every project, they will only give you initial settings. You will probably have to modify the following files:
@@ -28,6 +28,7 @@ class Listener
28
28
  log "Listener #{Gorgon::VERSION} initializing"
29
29
  connect
30
30
  initialize_personal_job_queue
31
+ announce_readiness_to_originators
31
32
  end
32
33
 
33
34
  def listen
@@ -44,11 +45,17 @@ class Listener
44
45
  end
45
46
 
46
47
  def initialize_personal_job_queue
47
- @job_queue = @bunny.queue("", :exclusive => true)
48
- exchange = @bunny.exchange(job_queue_name, :type => :fanout)
48
+ @job_queue = @bunny.queue("job_queue_" + UUIDTools::UUID.timestamp_create.to_s, :auto_delete => true)
49
+ exchange = @bunny.exchange(job_exchange_name, :type => :fanout)
49
50
  @job_queue.bind(exchange)
50
51
  end
51
52
 
53
+ def announce_readiness_to_originators
54
+ exchange = @bunny.exchange(originator_exchange_name, :type => :fanout)
55
+ data = {:listener_queue_name => @job_queue.name}
56
+ exchange.publish(Yajl::Encoder.encode(data))
57
+ end
58
+
52
59
  def poll
53
60
  message = @job_queue.pop
54
61
  return false if message == [nil, nil, nil]
@@ -175,8 +182,12 @@ class Listener
175
182
  reply_exchange.publish(Yajl::Encoder.encode(message))
176
183
  end
177
184
 
178
- def job_queue_name
179
- OriginatorProtocol.job_queue_name(configuration.fetch(:cluster_id, nil))
185
+ def job_exchange_name
186
+ OriginatorProtocol.job_exchange_name(configuration.fetch(:cluster_id, nil))
187
+ end
188
+
189
+ def originator_exchange_name
190
+ OriginatorProtocol.originator_exchange_name(configuration.fetch(:cluster_id, nil))
180
191
  end
181
192
 
182
193
  def connection_information
@@ -69,6 +69,10 @@ class Originator
69
69
  @protocol.receive_payloads do |payload|
70
70
  handle_reply(payload)
71
71
  end
72
+
73
+ @protocol.receive_new_listener_notifications do |payload|
74
+ handle_new_listener_notification(payload)
75
+ end
72
76
  end
73
77
 
74
78
  callback_handler.after_job_finishes
@@ -83,7 +87,7 @@ class Originator
83
87
  create_job_state_and_observers
84
88
 
85
89
  @logger.log "Publishing Job..."
86
- @protocol.publish_job job_definition
90
+ @protocol.publish_job_to_all job_definition
87
91
  @logger.log "Job Published"
88
92
  end
89
93
 
@@ -135,6 +139,17 @@ class Originator
135
139
  cleanup_if_job_complete
136
140
  end
137
141
 
142
+ def handle_new_listener_notification(payload)
143
+ payload = Yajl::Parser.new(:symbolize_keys => true).parse(payload)
144
+
145
+ if payload[:listener_queue_name]
146
+ @protocol.publish_job_to_one(job_definition, payload[:listener_queue_name])
147
+ else
148
+ puts "Received unexpected payload on originator queue"
149
+ ap payload
150
+ end
151
+ end
152
+
138
153
  def create_job_state_and_observers
139
154
  @job_state = JobState.new files.count
140
155
  RuntimeRecorder.new @job_state, configuration[:runtime_file]
@@ -6,11 +6,20 @@ require 'uuidtools'
6
6
 
7
7
  class OriginatorProtocol
8
8
  def initialize(logger, cluster_id=nil)
9
- @job_queue_name = OriginatorProtocol.job_queue_name(cluster_id)
9
+ @originator_exchange_name = OriginatorProtocol.originator_exchange_name(cluster_id)
10
+ @job_exchange_name = OriginatorProtocol.job_exchange_name(cluster_id)
10
11
  @logger = logger
11
12
  end
12
13
 
13
- def self.job_queue_name(cluster_id)
14
+ def self.originator_exchange_name(cluster_id)
15
+ if cluster_id
16
+ "gorgon.originators.#{cluster_id}"
17
+ else
18
+ "gorgon.originators"
19
+ end
20
+ end
21
+
22
+ def self.job_exchange_name(cluster_id)
14
23
  if cluster_id
15
24
  "gorgon.jobs.#{cluster_id}"
16
25
  else
@@ -33,17 +42,29 @@ class OriginatorProtocol
33
42
  end
34
43
  end
35
44
 
36
- def publish_job job_definition
45
+ def publish_job_to_all job_definition
46
+ job_definition = append_protocol_information_to_job_definition(job_definition)
47
+ @channel.fanout(@job_exchange_name).publish(job_definition.to_json)
48
+ end
49
+
50
+ def publish_job_to_one job_definition, listener_queue_name
51
+ job_definition = append_protocol_information_to_job_definition(job_definition)
52
+ @channel.default_exchange.publish(job_definition.to_json, :routing_key => listener_queue_name)
53
+ end
54
+
55
+ def append_protocol_information_to_job_definition job_definition
56
+ job_definition = job_definition.dup
57
+
37
58
  job_definition.file_queue_name = @file_queue.name
38
59
  job_definition.reply_exchange_name = @reply_exchange.name
39
60
 
40
- @channel.fanout(@job_queue_name).publish(job_definition.to_json)
61
+ return job_definition
41
62
  end
42
63
 
43
64
  def send_message_to_listeners type, body={}
44
65
  # TODO: we probably want to use a different exchange for this type of messages
45
66
  message = {:type => type, :reply_exchange_name => @reply_exchange.name, :body => body}
46
- @channel.fanout(@job_queue_name).publish(Yajl::Encoder.encode(message))
67
+ @channel.fanout(@job_exchange_name).publish(Yajl::Encoder.encode(message))
47
68
  end
48
69
 
49
70
  def receive_payloads
@@ -52,6 +73,12 @@ class OriginatorProtocol
52
73
  end
53
74
  end
54
75
 
76
+ def receive_new_listener_notifications
77
+ @originator_queue.subscribe do |payload|
78
+ yield payload
79
+ end
80
+ end
81
+
55
82
  def cancel_job
56
83
  @file_queue.purge if @file_queue
57
84
  @channel.fanout("gorgon.worker_managers").publish(cancel_message) if @channel
@@ -69,12 +96,18 @@ class OriginatorProtocol
69
96
  @reply_queue = @channel.queue("reply_queue_" + UUIDTools::UUID.timestamp_create.to_s, :auto_delete => true)
70
97
  @reply_exchange = @channel.direct("reply_exchange_" + UUIDTools::UUID.timestamp_create.to_s, :auto_delete => true)
71
98
  @reply_queue.bind(@reply_exchange)
99
+
100
+ # Provides a way for new listeners to announce their presence to originators that have already started the job
101
+ @originator_queue = @channel.queue("originator_queue_" + UUIDTools::UUID.timestamp_create.to_s, :auto_delete => true)
102
+ @originator_exchange = @channel.fanout(@originator_exchange_name)
103
+ @originator_queue.bind(@originator_exchange)
72
104
  end
73
105
 
74
106
  def cleanup_queues_and_exchange
75
107
  @reply_queue.delete if @reply_queue
76
108
  @file_queue.delete if @file_queue
77
109
  @reply_exchange.delete if @reply_exchange
110
+ @originator_queue.delete if @originator_queue
78
111
  end
79
112
 
80
113
  def cancel_message
@@ -8,7 +8,7 @@ module Settings
8
8
  @file_server_host = FilesContent.get_file_server_host
9
9
  @sync_exclude = [".git", ".rvmrc","doc","log","tmp"]
10
10
  @originator_log_file = 'log/gorgon-originator.log'
11
- @failed_files = 'tmp/gorgon-failed-files.json'
11
+ @failed_files = 'gorgon-failed-files.json'
12
12
  create_callbacks
13
13
  end
14
14
 
@@ -88,7 +88,7 @@ class GorgonCallbacks < Gorgon::DefaultCallbacks
88
88
  load './Rakefile'
89
89
 
90
90
  begin
91
- if Rails.env = 'remote_test'
91
+ if Rails.env == 'remote_test'
92
92
  Rake::Task['db:drop'].execute
93
93
  end
94
94
  rescue Exception => ex
@@ -1,3 +1,3 @@
1
1
  module Gorgon
2
- VERSION = "0.8.4"
2
+ VERSION = "0.9.0"
3
3
  end
@@ -2,7 +2,7 @@ require 'gorgon/listener'
2
2
 
3
3
  describe Listener do
4
4
  let(:connection_information) { double }
5
- let(:queue) { double("GorgonBunny Queue", :bind => nil) }
5
+ let(:queue) { double("GorgonBunny Queue", :bind => nil, :name => "some supposedly unique string") }
6
6
  let(:exchange) { double("GorgonBunny Exchange", :publish => nil) }
7
7
  let(:bunny) { double("GorgonBunny", :start => nil, :queue => queue, :exchange => exchange) }
8
8
  let(:logger) { double("Logger", :info => true, :datetime_format= => "")}
@@ -14,23 +14,6 @@ describe Listener do
14
14
  Listener.any_instance.stub(:connection_information => connection_information)
15
15
  end
16
16
 
17
- describe "initialization" do
18
-
19
- before do
20
- Listener.any_instance.stub(:connect => nil, :initialize_personal_job_queue => nil)
21
- end
22
-
23
- it "connects" do
24
- Listener.any_instance.should_receive(:connect)
25
- Listener.new
26
- end
27
-
28
- it "initializes the personal job queue" do
29
- Listener.any_instance.should_receive(:initialize_personal_job_queue)
30
- Listener.new
31
- end
32
- end
33
-
34
17
  describe "logging to a file" do
35
18
  context "passing a log file path in the configuration" do
36
19
  before do
@@ -84,23 +67,36 @@ describe Listener do
84
67
 
85
68
  describe "#initialize_personal_job_queue" do
86
69
  it "creates the job queue" do
87
- bunny.should_receive(:queue).with("", :exclusive => true)
70
+ UUIDTools::UUID.stub(:timestamp_create => "abcd1234")
71
+
72
+ bunny.should_receive(:queue).with("job_queue_abcd1234", :auto_delete => true)
88
73
  listener.initialize_personal_job_queue
89
74
  end
90
75
 
91
- it "build job_queue_name using job_id from configuration" do
76
+ it "builds job_exchange_name using cluster_id from configuration" do
92
77
  Listener.any_instance.stub(:configuration).and_return(:cluster_id => 'cluster5')
93
78
  bunny.should_receive(:exchange).with('gorgon.jobs.cluster5', anything).and_return(exchange)
94
79
  listener.initialize_personal_job_queue
95
80
  end
96
81
 
97
- it "binds the exchange to the queue. Uses gorgon.jobs if there is no job_queue_name in configuration" do
82
+ it "binds the exchange to the queue. Uses gorgon.jobs if there is no job_exchange_name in configuration" do
98
83
  bunny.should_receive(:exchange).with("gorgon.jobs", :type => :fanout).and_return(exchange)
99
84
  queue.should_receive(:bind).with(exchange)
100
85
  listener.initialize_personal_job_queue
101
86
  end
102
87
  end
103
88
 
89
+ describe "#announce_readiness_to_originators" do
90
+ it "publishes data to the originator exchange" do
91
+ originator_exchange = double
92
+
93
+ bunny.should_receive(:exchange).with("gorgon.originators", :type => :fanout).and_return(originator_exchange)
94
+ originator_exchange.should_receive(:publish).with({:listener_queue_name => "some supposedly unique string"}.to_json)
95
+
96
+ listener.announce_readiness_to_originators
97
+ end
98
+ end
99
+
104
100
  describe "#poll" do
105
101
 
106
102
  let(:empty_queue) { [nil, nil, nil] }
@@ -65,19 +65,19 @@ describe OriginatorProtocol do
65
65
  end
66
66
  end
67
67
 
68
- describe "#publish_job" do
68
+ describe "#publish_job_to_all" do
69
69
  before do
70
70
  connect_and_publish_files(@originator_p)
71
71
  end
72
72
 
73
- it "add queue's names to job_definition and fanout using 'gorgon.jobs' exchange" do
73
+ it "adds queue's names to job_definition and fanout using 'gorgon.jobs' exchange" do
74
74
  channel.should_receive(:fanout).with("gorgon.jobs")
75
- exp_job_definition = JobDefinition.new
76
- exp_job_definition.file_queue_name = "queue"
77
- exp_job_definition.reply_exchange_name = "exchange"
75
+ expected_job_definition = JobDefinition.new
76
+ expected_job_definition.file_queue_name = "queue"
77
+ expected_job_definition.reply_exchange_name = "exchange"
78
78
 
79
- exchange.should_receive(:publish).with(exp_job_definition.to_json)
80
- @originator_p.publish_job JobDefinition.new
79
+ exchange.should_receive(:publish).with(expected_job_definition.to_json)
80
+ @originator_p.publish_job_to_all JobDefinition.new
81
81
  end
82
82
 
83
83
  it "uses cluster_id in job_queue_name, when it is specified" do
@@ -85,7 +85,24 @@ describe OriginatorProtocol do
85
85
 
86
86
  channel.should_receive(:fanout).with("gorgon.jobs.cluster1")
87
87
 
88
- originator_p.publish_job JobDefinition.new
88
+ originator_p.publish_job_to_all JobDefinition.new
89
+ end
90
+ end
91
+
92
+ describe "#publish_job_to_one" do
93
+ before do
94
+ connect_and_publish_files(@originator_p)
95
+ end
96
+
97
+ it "publishes the job to the specified listener queue" do
98
+ expected_listener_queue_name = "abcd1234"
99
+ expected_job_definition = JobDefinition.new
100
+ expected_job_definition.file_queue_name = "queue"
101
+ expected_job_definition.reply_exchange_name = "exchange"
102
+
103
+ exchange.should_receive(:publish).with(expected_job_definition.to_json, {:routing_key => expected_listener_queue_name})
104
+
105
+ @originator_p.publish_job_to_one(JobDefinition.new, expected_listener_queue_name)
89
106
  end
90
107
  end
91
108
 
@@ -147,7 +164,7 @@ describe OriginatorProtocol do
147
164
 
148
165
  it "deletes reply_exchange and reply and file queues" do
149
166
  @originator_p.publish_files []
150
- queue.should_receive(:delete).twice
167
+ queue.should_receive(:delete).exactly(3).times
151
168
  exchange.should_receive(:delete)
152
169
  @originator_p.disconnect
153
170
  end
@@ -2,16 +2,17 @@ require 'gorgon/originator'
2
2
 
3
3
  describe Originator do
4
4
  let(:protocol){ double("Originator Protocol", :connect => nil, :publish_files => nil,
5
- :publish_job => nil, :receive_payloads => nil, :cancel_job => nil,
6
- :disconnect => nil)}
5
+ :publish_job_to_all => nil, :publish_job_to_one => nil, :receive_payloads => nil, :cancel_job => nil,
6
+ :disconnect => nil, :receive_new_listener_notifications => nil)}
7
7
 
8
8
  let(:configuration){ {:job => {}, :files => ["some/file"], :file_server => {:host => 'host-name'}}}
9
9
  let(:job_state){ double("JobState", :is_job_complete? => false, :file_finished => nil,
10
- :add_observer => nil)}
10
+ :add_observer => nil)}
11
11
  let(:progress_bar_view){ double("Progress Bar View", :show => nil)}
12
12
  let(:originator_logger){ double("Originator Logger", :log => nil, :log_message => nil)}
13
13
  let(:source_tree_syncer) { double("Source Tree Syncer", :push => nil, :exclude= => nil, :success? => true,
14
- :sys_command => 'command')}
14
+ :sys_command => 'command')}
15
+ let(:job_definition){ JobDefinition.new }
15
16
 
16
17
  before do
17
18
  OriginatorLogger.stub(:new).and_return originator_logger
@@ -146,6 +147,16 @@ describe Originator do
146
147
  end
147
148
  end
148
149
 
150
+ describe "#handle_new_listener_notification" do
151
+ it "re-publishes the job definition directly to the queue specified by the notification" do
152
+ stub_methods
153
+ @originator.publish
154
+
155
+ protocol.should_receive(:publish_job_to_one).with(job_definition, 'abcd1234')
156
+ @originator.handle_new_listener_notification({:listener_queue_name => 'abcd1234'}.to_json)
157
+ end
158
+ end
159
+
149
160
  describe "#job_definition" do
150
161
  it "returns a JobDefinition object" do
151
162
  @originator.stub(:configuration).and_return configuration
@@ -182,7 +193,7 @@ describe Originator do
182
193
  OriginatorProtocol.stub(:new).and_return protocol
183
194
  @originator.stub(:configuration).and_return configuration
184
195
  @originator.stub(:connection_information).and_return 'host'
185
- @originator.stub(:job_definition).and_return JobDefinition.new
196
+ @originator.stub(:job_definition).and_return job_definition
186
197
  end
187
198
 
188
199
  def start_payload
data/tutorial.md CHANGED
@@ -21,7 +21,14 @@ Run `rspec` and make sure all tests pass.
21
21
 
22
22
  1. Install [RabbitMQ](https://www.rabbitmq.com/download.html).
23
23
 
24
- 2. Add Gorgon to the Gemfile: `gem 'gorgon', '0.8.3'`
24
+ If you are using Homebrew on OSX, run the following:
25
+
26
+ ```bash
27
+ brew install rabbitmq
28
+ /usr/local/sbin/rabbitmq-server # runs the server
29
+ ```
30
+
31
+ 2. Add Gorgon to the Gemfile: `gem 'gorgon', '0.8.4'`
25
32
 
26
33
  3. `bundle`
27
34
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gorgon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.4
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Fitzsimmons
@@ -12,7 +12,7 @@ authors:
12
12
  autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
- date: 2015-02-16 00:00:00.000000000 Z
15
+ date: 2015-05-04 00:00:00.000000000 Z
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
18
18
  name: rake