gorgon 0.8.4 → 0.9.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.
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