symphony 0.12.3 → 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
2
+ # frozen_string_literal: true
3
3
 
4
4
  require 'loggability'
5
5
  require 'symphony' unless defined?( Symphony )
@@ -1,5 +1,5 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
2
+ # frozen_string_literal: true
3
3
 
4
4
  require 'set'
5
5
  require 'sysexits'
@@ -7,7 +7,7 @@ require 'pluggability'
7
7
  require 'loggability'
8
8
 
9
9
  require 'msgpack'
10
- require 'yajl'
10
+ require 'json'
11
11
  require 'yaml'
12
12
 
13
13
  require 'symphony' unless defined?( Symphony )
@@ -47,6 +47,15 @@ class Symphony::Task
47
47
  plugin_prefixes 'symphony/tasks'
48
48
 
49
49
 
50
+ @queue = nil
51
+ @acknowledge = true
52
+ @routing_keys = Set.new
53
+ @prefetch = 10
54
+ @persistent = false
55
+ @always_rebind = false
56
+ @queue_type = nil
57
+
58
+
50
59
  ### Create a new Task object and listen for work. Exits with the code returned
51
60
  ### by #start when it's done.
52
61
  def self::run( exit_on_idle=false )
@@ -79,11 +88,15 @@ class Symphony::Task
79
88
  def self::inherited( subclass )
80
89
  super
81
90
 
91
+ subclass.instance_variable_set( :@queue, nil )
92
+ subclass.instance_variable_set( :@queue_type, nil )
93
+ subclass.instance_variable_set( :@always_rebind, false )
82
94
  subclass.instance_variable_set( :@routing_keys, Set.new )
83
95
  subclass.instance_variable_set( :@acknowledge, true )
84
96
  subclass.instance_variable_set( :@work_model, :longlived )
85
97
  subclass.instance_variable_set( :@prefetch, 10 )
86
98
  subclass.instance_variable_set( :@timeout_action, :reject )
99
+ subclass.instance_variable_set( :@timeout, nil )
87
100
  subclass.instance_variable_set( :@persistent, false )
88
101
  subclass.instance_variable_set( :@idle_timeout, DEFAULT_IDLE_TIMEOUT )
89
102
  end
@@ -132,6 +145,16 @@ class Symphony::Task
132
145
  end
133
146
 
134
147
 
148
+ ### Specify an x-queue-type for the underlying queue
149
+ def self::queue_type( type=nil )
150
+ if type
151
+ @queue_type = type
152
+ end
153
+
154
+ return @queue_type
155
+ end
156
+
157
+
135
158
  ### Set up one or more topic key patterns to use when binding the Task's queue
136
159
  ### to the exchange.
137
160
  def self::subscribe_to( *routing_keys )
@@ -438,7 +461,7 @@ class Symphony::Task
438
461
  when 'application/x-msgpack'
439
462
  MessagePack.unpack( payload )
440
463
  when 'application/json', 'text/javascript'
441
- Yajl::Parser.parse( payload )
464
+ JSON.parse( payload )
442
465
  when 'application/x-yaml', 'text/x-yaml'
443
466
  YAML.load( payload )
444
467
  else
@@ -1,5 +1,5 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
2
+ # frozen_string_literal: true
3
3
 
4
4
  require 'set'
5
5
  require 'pluggability'
@@ -1,5 +1,5 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
2
+ # frozen_string_literal: true
3
3
 
4
4
  require 'set'
5
5
  require 'symphony/task_group' unless defined?( Symphony::TaskGroup )
@@ -35,8 +35,9 @@ class Symphony::TaskGroup::LongLived < Symphony::TaskGroup
35
35
  return [ pid ]
36
36
  end
37
37
 
38
- @queue ||= self.get_message_counting_queue
39
-
38
+ return nil
39
+ rescue Timeout::Error => err
40
+ self.log.warn "%p while adjusting workers: %s" % [ err.class, err.message ]
40
41
  return nil
41
42
  end
42
43
 
@@ -44,11 +45,10 @@ class Symphony::TaskGroup::LongLived < Symphony::TaskGroup
44
45
  ### Return +true+ if the task group should scale up by one.
45
46
  def needs_a_worker?
46
47
  return true if self.workers.empty?
47
- return false unless @queue
48
-
48
+ queue = self.get_message_counting_queue or return false
49
49
 
50
50
  # Calculate the number of workers across the whole broker
51
- if ( cc = @queue.consumer_count ) >= self.max_workers
51
+ if ( cc = queue.consumer_count ) >= self.max_workers
52
52
  self.log.debug "%p: Already at max workers (%d)" % [ self.task_class, self.max_workers ]
53
53
  return false
54
54
  else
@@ -62,9 +62,10 @@ class Symphony::TaskGroup::LongLived < Symphony::TaskGroup
62
62
 
63
63
  ### Add the current number of workers to the samples.
64
64
  def sample_queue_status
65
- return unless @queue
65
+ return if self.workers.empty?
66
66
 
67
- count = @queue.message_count
67
+ queue = self.get_message_counting_queue or return
68
+ count = queue.message_count
68
69
  self.add_sample( count )
69
70
  end
70
71
 
@@ -82,11 +83,20 @@ class Symphony::TaskGroup::LongLived < Symphony::TaskGroup
82
83
  ### Get a queue for counting the number of messages in the queue for this
83
84
  ### worker.
84
85
  def get_message_counting_queue
85
- channel = Symphony::Queue.amqp_channel
86
- queue = channel.queue( self.task_class.queue_name, passive: true, prefetch: 0 )
86
+ @queue ||= begin
87
+ self.log.debug "Creating the message-counting queue."
88
+ channel = Symphony::Queue.amqp_channel
89
+ channel.queue( self.task_class.queue_name, passive: true, prefetch: 0 )
90
+ end
91
+
92
+ unless @queue.channel.open?
93
+ self.log.info "Message-counting queue's channel was closed: resetting."
94
+ Symphony::Queue.reset
95
+ @queue = nil
96
+ end
87
97
 
88
- return queue
89
- rescue Bunny::NotFound => err
98
+ return @queue
99
+ rescue Bunny::NotFound, Bunny::ChannelAlreadyClosed
90
100
  self.log.info "Child hasn't created the queue yet; deferring"
91
101
  Symphony::Queue.reset
92
102
 
@@ -1,5 +1,5 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
2
+ # frozen_string_literal: true
3
3
 
4
4
  require 'symphony/task_group' unless defined?( Symphony::TaskGroup )
5
5
 
@@ -48,6 +48,10 @@ module Symphony::SpecHelpers
48
48
  def initialize
49
49
  @queue = nil
50
50
  @exchange = nil
51
+ @open = true
52
+ end
53
+ def open?
54
+ return @open
51
55
  end
52
56
  def queue( name, opts={} )
53
57
  return @queue ||= DummySession::Queue.new( self )
@@ -60,7 +64,9 @@ module Symphony::SpecHelpers
60
64
  def number
61
65
  return 1
62
66
  end
63
- def close; end
67
+ def close
68
+ @open = false
69
+ end
64
70
  end
65
71
 
66
72
  class Exchange
@@ -86,14 +92,24 @@ end
86
92
 
87
93
  ### Mock with RSpec
88
94
  RSpec.configure do |config|
89
- config.run_all_when_everything_filtered = true
90
- config.filter_run :focus
91
- config.order = 'random'
92
- config.expect_with( :rspec )
93
- config.mock_with( :rspec ) do |mock|
94
- mock.syntax = :expect
95
+ config.expect_with :rspec do |expectations|
96
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
97
+ expectations.syntax = :expect
98
+ end
99
+
100
+ config.mock_with :rspec do |mocks|
101
+ mocks.verify_partial_doubles = true
95
102
  end
96
103
 
104
+ config.run_all_when_everything_filtered = true
105
+ config.filter_run_when_matching :focus
106
+ config.order = :random
107
+ config.example_status_persistence_file_path = 'spec/.state'
108
+ config.disable_monkey_patching!
109
+ config.warnings = true
110
+ config.profile_examples = 5
111
+
112
+
97
113
  config.include( Loggability::SpecHelpers )
98
114
  config.include( Symphony::SpecHelpers )
99
115
  end
@@ -1,5 +1,5 @@
1
1
  # -*- ruby -*-
2
- #encoding: utf-8
2
+ # frozen_string_literal: true
3
3
  # vim: set noet nosta sw=4 ts=4 :
4
4
 
5
5
 
@@ -19,7 +19,7 @@ class Test3Task < Symphony::Task
19
19
  end
20
20
 
21
21
 
22
- describe Symphony::Daemon do
22
+ RSpec.describe Symphony::Daemon do
23
23
 
24
24
  before( :all ) do
25
25
  @pids = ( 200..65534 ).cycle
@@ -5,12 +5,16 @@ require_relative '../helpers'
5
5
  require 'symphony/mixins'
6
6
 
7
7
 
8
- describe Symphony, 'mixins' do
8
+ RSpec.describe Symphony, 'mixins' do
9
9
 
10
10
  describe Symphony::MethodUtilities, 'used to extend a class' do
11
11
 
12
12
  let!( :extended_class ) do
13
- klass = Class.new
13
+ klass = Class.new do
14
+ def initialize
15
+ @foo = nil
16
+ end
17
+ end
14
18
  klass.extend( Symphony::MethodUtilities )
15
19
  klass
16
20
  end
@@ -4,7 +4,7 @@ require_relative '../helpers'
4
4
 
5
5
  require 'symphony/queue'
6
6
 
7
- describe Symphony::Queue do
7
+ RSpec.describe Symphony::Queue do
8
8
 
9
9
 
10
10
  before( :each ) do
@@ -128,7 +128,33 @@ describe Symphony::Queue do
128
128
  expect( new_channel ).to receive( :prefetch ).
129
129
  with( Symphony::Queue::DEFAULT_PREFETCH )
130
130
  expect( new_channel ).to receive( :queue ).
131
- with( queue.name, auto_delete: true ).
131
+ with( queue.name, auto_delete: true, arguments: {} ).
132
+ and_return( amqp_queue )
133
+ expect( amqp_queue ).to receive( :bind ).
134
+ with( described_class.amqp_exchange, routing_key: 'floppy.rabbit.#' )
135
+
136
+ expect( queue.create_amqp_queue ).to be( amqp_queue )
137
+ end
138
+
139
+
140
+ it "can declare the queue's x-queue-type" do
141
+ testing_task_class.subscribe_to( 'floppy.rabbit.#' )
142
+ testing_task_class.queue_type( 'classic' )
143
+ expect( described_class.amqp_channel ).to receive( :queue ).
144
+ with( queue.name, passive: true ).
145
+ and_raise( Bunny::NotFound.new("no such queue", described_class.amqp_channel, true) )
146
+ expect( described_class.amqp_channel ).to receive( :open? ).
147
+ and_return( false )
148
+
149
+ # Channel is reset after queue creation fails
150
+ new_channel = double( "New AMQP channel" )
151
+ amqp_queue = double( "AMQP queue" )
152
+ allow( described_class.amqp_session ).to receive( :create_channel ).
153
+ and_return( new_channel )
154
+ expect( new_channel ).to receive( :prefetch ).
155
+ with( Symphony::Queue::DEFAULT_PREFETCH )
156
+ expect( new_channel ).to receive( :queue ).
157
+ with( queue.name, auto_delete: true, arguments: { 'x-queue-type' => 'classic' } ).
132
158
  and_return( amqp_queue )
133
159
  expect( amqp_queue ).to receive( :bind ).
134
160
  with( described_class.amqp_exchange, routing_key: 'floppy.rabbit.#' )
@@ -7,7 +7,7 @@ require 'symphony'
7
7
  require 'symphony/routing'
8
8
 
9
9
 
10
- describe Symphony::Routing do
10
+ RSpec.describe Symphony::Routing do
11
11
 
12
12
  let( :task_class ) do
13
13
  Class.new( Symphony::Task ) do
@@ -5,7 +5,7 @@ require_relative '../helpers'
5
5
  require 'symphony/statistics'
6
6
 
7
7
 
8
- describe Symphony::Statistics do
8
+ RSpec.describe Symphony::Statistics do
9
9
 
10
10
 
11
11
  let( :including_class ) do
@@ -4,7 +4,7 @@ require_relative '../../helpers'
4
4
 
5
5
  require 'symphony/task_group/longlived'
6
6
 
7
- describe Symphony::TaskGroup::LongLived do
7
+ RSpec.describe Symphony::TaskGroup::LongLived do
8
8
 
9
9
  FIRST_PID = 414
10
10
 
@@ -23,6 +23,9 @@ describe Symphony::TaskGroup::LongLived do
23
23
  def self::run
24
24
  self.has_run = true
25
25
  end
26
+ def self::name
27
+ return "TestTask"
28
+ end
26
29
  end
27
30
  end
28
31
 
@@ -75,8 +78,8 @@ describe Symphony::TaskGroup::LongLived do
75
78
 
76
79
  allow( Process ).to receive( :setpgid )
77
80
 
78
- channel = double( Bunny::Channel )
79
- queue = double( Bunny::Queue )
81
+ channel = double( Bunny::Channel, open?: true )
82
+ queue = double( Bunny::Queue, channel: channel )
80
83
  expect( Symphony::Queue ).to receive( :amqp_channel ).
81
84
  and_return( channel )
82
85
  expect( channel ).to receive( :queue ).
@@ -89,7 +92,8 @@ describe Symphony::TaskGroup::LongLived do
89
92
  expect( queue ).to receive( :message_count ).and_return( *samples )
90
93
 
91
94
  start = 1414002605
92
- start.upto( start + samples.size + 1 ) do |time|
95
+ start.upto( start + samples.size ) do |time|
96
+ Loggability.logger.debug "Foom"
93
97
  Timecop.freeze( time ) do
94
98
  task_group.adjust_workers
95
99
  end
@@ -106,8 +110,8 @@ describe Symphony::TaskGroup::LongLived do
106
110
 
107
111
  allow( Process ).to receive( :setpgid )
108
112
 
109
- channel = double( Bunny::Channel )
110
- queue = double( Bunny::Queue )
113
+ channel = double( Bunny::Channel, open?: true )
114
+ queue = double( Bunny::Queue, channel: channel )
111
115
  expect( Symphony::Queue ).to receive( :amqp_channel ).
112
116
  and_return( channel )
113
117
  expect( channel ).to receive( :queue ).
@@ -120,7 +124,7 @@ describe Symphony::TaskGroup::LongLived do
120
124
  expect( queue ).to receive( :message_count ).and_return( *samples )
121
125
 
122
126
  start = 1414002605
123
- start.upto( start + samples.size + 1 ) do |time|
127
+ start.upto( start + samples.size ) do |time|
124
128
  Timecop.freeze( time ) do
125
129
  task_group.adjust_workers
126
130
  end
@@ -136,8 +140,8 @@ describe Symphony::TaskGroup::LongLived do
136
140
 
137
141
  allow( Process ).to receive( :setpgid )
138
142
 
139
- channel = double( Bunny::Channel )
140
- queue = double( Bunny::Queue )
143
+ channel = double( Bunny::Channel, open?: true )
144
+ queue = double( Bunny::Queue, channel: channel )
141
145
  expect( Symphony::Queue ).to receive( :amqp_channel ).
142
146
  and_return( channel )
143
147
  expect( channel ).to receive( :queue ).
@@ -150,7 +154,7 @@ describe Symphony::TaskGroup::LongLived do
150
154
  expect( queue ).to receive( :message_count ).and_return( *samples )
151
155
 
152
156
  start = 1414002605
153
- start.upto( start + samples.size + 1 ) do |time|
157
+ start.upto( start + samples.size ) do |time|
154
158
  Timecop.freeze( time ) do
155
159
  task_group.adjust_workers
156
160
  end
@@ -166,8 +170,8 @@ describe Symphony::TaskGroup::LongLived do
166
170
 
167
171
  allow( Process ).to receive( :setpgid )
168
172
 
169
- channel = double( Bunny::Channel )
170
- queue = double( Bunny::Queue )
173
+ channel = double( Bunny::Channel, open?: true )
174
+ queue = double( Bunny::Queue, channel: channel )
171
175
  expect( Symphony::Queue ).to receive( :amqp_channel ).
172
176
  and_return( channel )
173
177
  expect( channel ).to receive( :queue ).
@@ -178,7 +182,7 @@ describe Symphony::TaskGroup::LongLived do
178
182
  expect( queue ).to receive( :message_count ).and_return( *samples )
179
183
 
180
184
  start = 1414002605
181
- start.upto( start + samples.size + 1 ) do |time|
185
+ start.upto( start + samples.size ) do |time|
182
186
  Timecop.freeze( time ) do
183
187
  task_group.adjust_workers
184
188
  end
@@ -194,8 +198,8 @@ describe Symphony::TaskGroup::LongLived do
194
198
 
195
199
  allow( Process ).to receive( :setpgid )
196
200
 
197
- channel = double( Bunny::Channel )
198
- queue = double( Bunny::Queue )
201
+ channel = double( Bunny::Channel, open?: true )
202
+ queue = double( Bunny::Queue, channel: channel )
199
203
  expect( Symphony::Queue ).to receive( :amqp_channel ).
200
204
  and_return( channel )
201
205
  expect( channel ).to receive( :queue ).
@@ -208,7 +212,7 @@ describe Symphony::TaskGroup::LongLived do
208
212
  expect( queue ).to receive( :message_count ).and_return( *samples )
209
213
 
210
214
  start = 1414002605
211
- start.upto( start + samples.size + 1 ) do |time|
215
+ start.upto( start + samples.size ) do |time|
212
216
  Timecop.freeze( time ) do
213
217
  task_group.adjust_workers
214
218
  end
@@ -5,7 +5,7 @@ require_relative '../../helpers'
5
5
  require 'symphony/task_group/oneshot'
6
6
 
7
7
 
8
- describe Symphony::TaskGroup::Oneshot do
8
+ RSpec.describe Symphony::TaskGroup::Oneshot do
9
9
 
10
10
  let( :task ) do
11
11
  Class.new( Symphony::Task ) do
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_relative '../helpers'
4
4
 
5
- describe Symphony::TaskGroup do
5
+ RSpec.describe Symphony::TaskGroup do
6
6
 
7
7
  let( :task ) do
8
8
  Class.new( Symphony::Task ) do