pipeline_toolkit 1.2.16 → 1.2.17

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -1,6 +1,19 @@
1
1
  # Pipeline Toolkit #
2
2
  by VisFleet
3
3
 
4
+
5
+ ===============
6
+ |^^:^^^^:Mw^^^| Pipeline Toolkit
7
+ | : .:Mw; | By VisFleet
8
+ \-------------/ (c) 2009
9
+ |^:^^^^:Mw^^|
10
+ | : :Mw; |
11
+ | : :Mw; |
12
+ | : :Mw; |
13
+ | : .:Mw; |
14
+ -------------
15
+
16
+
4
17
  Command line tools for processing messages by constructing a pipeline of machines. [AMQP](http://amqp.rubyforge.org/ "AMQP") and Unix pipes are used to construct the pipeline. Messages are simple Hashes (serialized as JSON) so they can hold any values and change throughout the processing.
5
18
 
6
19
  Provides:
@@ -60,17 +73,17 @@ All gem dependancies are installed automatically, but if you're curious checkout
60
73
 
61
74
  You can learn more about the command line tools and what options are available by using their help command.
62
75
 
63
- > msg_subscriber --help
64
- > msg_push --help
65
- > msg_sink --help
66
- > msg_probe --help
76
+ > msg_subscriber --help
77
+ > msg_push --help
78
+ > msg_sink --help
79
+ > msg_probe --help
67
80
 
68
81
  ## Examples ##
69
82
 
70
83
  In the example, open two terminal windows and then execute the following commands in each:
71
84
 
72
- > msg_generator | msg_push -x test-exchange
73
- > msg_subscribe -a false --http-port 9090 -x test-exchange -q test_queue > /dev/null
85
+ > msg_generator | msg_push -x test-exchange
86
+ > msg_subscribe -a false --http-port 9090 -x test-exchange -q test_queue > /dev/null
74
87
 
75
88
  The example does the following:
76
89
 
@@ -83,8 +96,8 @@ The example does the following:
83
96
 
84
97
  Now lets switch on acknowledgements:
85
98
 
86
- > msg_generator | msg_push -x test-exchange
87
- > msg_subscribe -x test-exchange -q test_queue | msg_sink
99
+ > msg_generator | msg_push -x test-exchange
100
+ > msg_subscribe -x test-exchange -q test_queue | msg_sink
88
101
 
89
102
  This example does the same as above, but this time with acknowledgements switched on.
90
103
  This guarantees that a message isn't removed from the message server until handled.
@@ -43,13 +43,17 @@ module PipelineToolkit
43
43
  def initialize_connection
44
44
  DefaultLogger.debug("Amqp::Abstract#initialize_connection") if options[:env] == "development"
45
45
  @connection = AMQP.connect(options.select_keys(:host, :port, :user, :pass, :vhost))
46
+ end
46
47
 
47
- # Override Signals, so that connection is shutdown gracefully
48
- Signal.trap('INT') { @connection.close; EM.stop }
49
- Signal.trap('TERM') { @connection.close; EM.stop }
50
- Signal.trap('PIPE') { @connection.close; EM.stop }
48
+ ##
49
+ # Gracefully shuts down the AMQP connection. Calls the given block if provided
50
+ #
51
+ def stop_connection
52
+ # NB: Next tick seems to give it enough time to receieve and send outstanding acks. But I don't
53
+ # really understand timing, so keep an eye on it.
54
+ EM.next_tick { @connection.close { yield if block_given? } }
51
55
  end
52
-
56
+
53
57
  ##
54
58
  # Returns a new channel. A channel is a bidirectional virtual connection between the client
55
59
  # and the AMQP server.
@@ -19,7 +19,9 @@ module PipelineToolkit
19
19
  @ack_headers ||= {}
20
20
  initialize_connection
21
21
  initialize_channel
22
- @channel.prefetch(1) # We only want to handle one message at a time
22
+ # NB: Used to be 1 to prevent deadlocks. Think deadlocks won't happen anymore (because doing asyn
23
+ # reads now), but keep an eye on this parameter.
24
+ @channel.prefetch(25)
23
25
  initialize_exchange
24
26
  initialize_queue
25
27
  bind_queue
@@ -13,6 +13,14 @@ module PipelineToolkit
13
13
  @mq.start
14
14
  end
15
15
 
16
+ def connected?
17
+ @mq.connected?
18
+ end
19
+
20
+ def close
21
+ @mq.stop
22
+ end
23
+
16
24
  def purge_queue(queue)
17
25
  @mq.queue(queue).purge
18
26
  end
@@ -3,6 +3,11 @@ Given /^an amqp server running on "(\w+)" at port (\d+)$/ do |host, port|
3
3
  @amqp.start(host, port)
4
4
  end
5
5
 
6
+ # Clean up connection after each scenario
7
+ After do
8
+ @amqp.close if @amqp && @amqp.connected?
9
+ end
10
+
6
11
  Given /^amqp queue "(\w+)" is empty$/ do |queue|
7
12
  @amqp.purge_queue(queue)
8
13
  end
@@ -18,6 +18,10 @@ module PipelineToolkit
18
18
  @process.kill
19
19
  @process.wait
20
20
  end
21
+
22
+ def running?
23
+ @process.running?
24
+ end
21
25
 
22
26
  def pid
23
27
  @process.pid
@@ -6,7 +6,11 @@ end
6
6
 
7
7
  # Clean up backround processes after each scenario
8
8
  After do
9
- @process.kill unless @process.nil?
9
+ @process.kill if @process && @process.running?
10
+ end
11
+
12
+ When /^I kill the machine$/ do
13
+ @process.kill
10
14
  end
11
15
 
12
16
  # Lets you use JSON to express a complex message
@@ -61,9 +61,9 @@ module PipelineToolkit
61
61
  def start
62
62
  DefaultLogger.debug("MessageCommand#start") if @options[:env] == "development"
63
63
 
64
- Signal.trap('INT') { EM.stop }
65
- Signal.trap('TERM') { EM.stop }
66
- Signal.trap('PIPE') { EM.stop }
64
+ Signal.trap('INT') { self.stop }
65
+ Signal.trap('TERM') { self.stop }
66
+ Signal.trap('PIPE') { self.stop }
67
67
 
68
68
  begin
69
69
  EM.run do
@@ -77,16 +77,23 @@ module PipelineToolkit
77
77
  DefaultLogger.error("#{e.class.name}: #{e.message}\n" << e.backtrace.join("\n"))
78
78
  raise e
79
79
  ensure
80
- shutdown
80
+ cleanup
81
81
  end
82
82
  end
83
83
 
84
84
  ##
85
- # Stops the machine
85
+ # Stops the command. This stops the event loop, giving it enough time to clear its buffers
86
86
  #
87
- def shutdown
87
+ def stop
88
88
  DefaultLogger.info("Shutting down #{self.class.name}")
89
89
  DefaultLogger.info "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
90
+ EM.next_tick { EM.stop }
91
+ end
92
+
93
+ ##
94
+ # Cleans up any used resource, such as pipes and files.
95
+ #
96
+ def cleanup
90
97
  @ack_pipe.close if @ack_pipe
91
98
  end
92
99
 
@@ -110,6 +117,7 @@ module PipelineToolkit
110
117
  # @param message<Hash> The message to acknowledge
111
118
  #
112
119
  def acknowledge(message)
120
+ return if message[:ack_id].nil?
113
121
  DefaultLogger.debug("MessageCommand#acknowledge(message)") if options[:env] == "development"
114
122
  ack_message = {:msg_type => "ack", :ack_id => message[:ack_id]}
115
123
  write_to_pipe(ack_message, @ack_pipe)
@@ -34,7 +34,16 @@ module PipelineToolkit
34
34
  def initialize_machine
35
35
  DefaultLogger.debug("MessagePusher#initialize_machine") if options[:env] == "development"
36
36
  initialize_writer
37
- initialize_queues
37
+ initialize_queues
38
+ end
39
+
40
+ ##
41
+ # Override stop, so that we can close AMQP connection gracefully.
42
+ #
43
+ def stop
44
+ DefaultLogger.info("Shutting down #{self.class.name}")
45
+ DefaultLogger.info "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
46
+ stop_connection { EM.stop }
38
47
  end
39
48
 
40
49
  def description
@@ -8,6 +8,7 @@ module PipelineToolkit
8
8
  $stdout.puts(message.inspect)
9
9
  $stdout.flush
10
10
  end
11
+ sleep(0.1)
11
12
  acknowledge(message) if @options[:acknowledge]
12
13
  end
13
14
 
@@ -54,6 +54,10 @@ module PipelineToolkit
54
54
  begin
55
55
  create_sys_pipe
56
56
 
57
+ Signal.trap('INT') { self.stop }
58
+ Signal.trap('TERM') { self.stop }
59
+ Signal.trap('PIPE') { self.stop }
60
+
57
61
  EM.run do
58
62
  @start_time = Time.now
59
63
 
@@ -73,16 +77,23 @@ module PipelineToolkit
73
77
  DefaultLogger.error "#{e.class.name}: #{e.message}\n" << e.backtrace.join("\n")
74
78
  raise e
75
79
  ensure
76
- shutdown
80
+ cleanup
77
81
  end
78
82
  end
79
83
 
80
84
  ##
81
- # Stop the subscriber
85
+ # Stops the command. This stops the event loop, giving it enough time to clear its buffers
82
86
  #
83
- def shutdown
87
+ def stop
84
88
  DefaultLogger.info("Shutting down #{self.class.name}")
85
89
  DefaultLogger.info "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^"
90
+ stop_connection { EM.stop }
91
+ end
92
+
93
+ ##
94
+ # Cleans up any used resource, such as pipes and files.
95
+ #
96
+ def cleanup
86
97
  destroy_sys_pipe
87
98
  end
88
99
 
@@ -48,7 +48,7 @@
48
48
  <td>host:</td><td><%= hostname %></td>
49
49
  </tr>
50
50
  <tr>
51
- <td>throughput:</td><td><%= mps.to_i %></td>
51
+ <td>throughput:</td><td><%= "%.3f" % (mps || 0) %></td>
52
52
  </tr>
53
53
  <tr>
54
54
  <td>uptime:</td><td><%= uptime / 60 %>mins</td>
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 2
8
- - 16
9
- version: 1.2.16
8
+ - 17
9
+ version: 1.2.17
10
10
  platform: ruby
11
11
  authors:
12
12
  - Aisha Fenton
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-08-30 00:00:00 +12:00
18
+ date: 2010-08-31 00:00:00 +12:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency