kinetic 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 67a4ff614b5f65c94ff43ae5e18e7a73944c13e3
4
- data.tar.gz: 41f13ae0b524573c98a63f853d7be3c458c12a96
3
+ metadata.gz: b7a08f594cae0d5c01c00f340386df7c7788a745
4
+ data.tar.gz: 280fe43699041a8a233b455887d795b6c47e42f8
5
5
  SHA512:
6
- metadata.gz: 72ce1e7b862c33785117568f17944f7d40401c158e78e80a3a44e7b865d299ef1c521c24104a81b666397689e069273434be0cbaa553f5fb6f83b7a6411c4625
7
- data.tar.gz: 575a3a38d19d22d92125da043f9a065cd18f53d348003f3eda1ac9ef0679476ed636f923bc0a2d722d6c16e3dd08d87df3f18a87f532869463f1f3f50cb8f1be
6
+ metadata.gz: 65871da55313e959082177229600037b1ffdf5e94b1886bebb525e9099effe4b249fb7b581f54d45ed908fa68eac60e0ce7e44841e96f0738d7ae1fc731a8c3f
7
+ data.tar.gz: e8452cb376cab92b21796269deff0ac5ab24306099675eca52eeb9d64071cced80ba649e0b6399748f77d113b13e6bdd7f7aecbcf1a4bc1cbf386faa30be73ff
data/.gitignore CHANGED
@@ -17,3 +17,5 @@ test/version_tmp
17
17
  tmp
18
18
  .idea/**
19
19
  *.iml
20
+ doc/**
21
+ *.pid
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ script: rspec spec
2
+ rvm:
3
+ - "1.9.3"
4
+ - "2.0.0"
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # Kinetic
2
2
 
3
+ [<img src="https://secure.travis-ci.org/fugufish/kinetic.png">](http://travis-ci.org/fugufish/kinetic)
4
+ [![Code Climate](https://codeclimate.com/repos/52b06fa413d637197401ebb7/badges/c71d7f47797b4caec5ae/gpa.png)](https://codeclimate.com/repos/52b06fa413d637197401ebb7/feed)
5
+
6
+
3
7
  Kinetic is an AMQP worker framework designed in vein of microframeworks such as sinatra. Its goal is to provide an
4
8
  easy way to configure and run AMQP consumers in order to reduce developer overhead when working with AMQP. Kinetic
5
9
  follows the master/worker convention used in Unicorn, and its prefork code is mostly based on that of Unicorn's.
data/kinetic.gemspec CHANGED
@@ -28,7 +28,8 @@ Gem::Specification.new do |spec|
28
28
 
29
29
  spec.add_development_dependency 'bundler', '~> 1.3'
30
30
  spec.add_development_dependency 'rake'
31
-
31
+ spec.add_development_dependency 'rspec'
32
+ spec.add_development_dependency 'yard'
32
33
 
33
34
 
34
35
  end
data/lib/kinetic/base.rb CHANGED
@@ -17,6 +17,8 @@ require_relative '../kinetic/version'
17
17
  require_relative '../kinetic/configuration'
18
18
  require_relative '../kinetic/master'
19
19
  require_relative '../kinetic/worker'
20
+ require_relative '../kinetic/dsl'
21
+ require_relative '../kinetic/errors'
20
22
 
21
23
  module Kinetic
22
24
 
@@ -34,28 +36,10 @@ module Kinetic
34
36
  class Base
35
37
 
36
38
  class << self
39
+ include Kinetic::DSL
37
40
 
38
- attr_reader :exchanges
39
-
40
- def set(key, value)
41
- config[key] = value
42
- end
43
-
44
- def config
45
- @config ||= Kinetic::Configuration.new
46
- end
47
-
48
- def logger
49
- @logger ||= reopen_logger
50
- end
51
-
52
- def reopen_logger
53
- @logger = Logger.new(STDOUT)
54
- end
55
-
56
- def on(key, &block)
57
- logger.debug "Setting up '#{key}' on 'direct'"
58
- direct[key] = block
41
+ def exchanges
42
+ @exchanges ||= {}
59
43
  end
60
44
 
61
45
  private
@@ -65,22 +49,11 @@ module Kinetic
65
49
  end
66
50
 
67
51
 
68
- def exchanges
69
- @exchanges ||= {}
70
- end
71
-
72
- end
73
52
 
74
- delegate :logger, to: :class
75
- delegate :config, to: :class
76
53
 
77
- def reopen_logger
78
- self.class.reopen_logger
79
54
  end
80
55
 
81
- def exchanges
82
- self.class.send(:exchanges)
83
- end
56
+ delegate :logger, :set, :get, :get!, :exchanges, to: :class
84
57
 
85
58
  end
86
59
 
@@ -6,6 +6,7 @@ module Kinetic
6
6
  root: File.dirname($0),
7
7
  app_file: $0,
8
8
  workers: 1,
9
+ log_file: STDOUT,
9
10
  }
10
11
 
11
12
  def initialize
@@ -0,0 +1,74 @@
1
+ module Kinetic
2
+
3
+ module DSL
4
+
5
+ # Sets a configuration value
6
+ #
7
+ # @param [Symbol] key the configuration key to set
8
+ # @param [Symbol] value the configuration value
9
+ #
10
+ # @return [Boolean] returns true
11
+ def set(key, value)
12
+ config[key.to_sym] = value
13
+ true
14
+ end
15
+
16
+ # Gets a configuration value
17
+ #
18
+ # @param [Symbol] key the key of the value to get
19
+ #
20
+ # @return [Object, nil] returns the requested configuration value or nil if the value does not exist
21
+ def get(key)
22
+ config[key.to_sym]
23
+ end
24
+
25
+ # Gets a configuration value and returns an exception if the value is not present
26
+ #
27
+ # @param [Symbol] key the key of the value to get
28
+ #
29
+ # @return [Object]
30
+ #
31
+ # @raise [Kinetic::Errors::MissingConfigurationValue] if the value does not exist
32
+ def get!(key)
33
+ raise Kinetic::Errors::MissingConfigurationValue.new(key) unless (value = get(key))
34
+ value
35
+ end
36
+
37
+ # Defines a direct queue subscription. Direct queues do not allow fuzzy matching so all messages sent to this queue
38
+ # must exactly match the key.
39
+ #
40
+ # @param [String] key the key of the queue to which to subscribe.
41
+ #
42
+ # @yield [message] yields the message passed to the queue to the block
43
+ #
44
+ # @raise [Kinetic::Errors::NoSubcriberBlock] if a block is not passed
45
+ # @raise [Kinetic::Errors::KeyMustBeString] if the passed key is not a string
46
+ def on_direct(key, &block)
47
+ raise Kinetic::Errors::NoSubscriberBlock unless block_given?
48
+ raise Kinetic::Errors::KeyMustBeString unless key.is_a? String
49
+ logger.debug "Setting up '#{key}' on 'direct'"
50
+ direct[key] = block
51
+ end
52
+
53
+ alias :on :on_direct
54
+
55
+ # @return [Logger] returns the application logger instance
56
+ def logger
57
+ @logger ||= reopen_logger
58
+ end
59
+
60
+ private
61
+
62
+ def config
63
+ @config ||= Kinetic::Configuration.new
64
+ end
65
+
66
+ def reopen_logger
67
+ @logger = Logger.new(config.log_file)
68
+ end
69
+
70
+
71
+
72
+ end
73
+
74
+ end
@@ -3,16 +3,17 @@ module Kinetic
3
3
 
4
4
  class KineticError < StandardError; end
5
5
 
6
- class ConnectionError < KineticError
6
+ class NoSubscriberBlock < KineticError; end
7
+ class KeyMustBeString < KineticError; end
7
8
 
8
- def initialize(error)
9
- message = error.message
10
- backtrace = error.backtrace
11
- super message
12
- self.set_backtrace(backtrace)
9
+ class MissingConfigurationValue < KineticError
10
+
11
+ def initialize(key)
12
+ super "Expected configuration for '#{key}' but the configuration was not found."
13
13
  end
14
14
 
15
15
  end
16
16
 
17
+
17
18
  end
18
19
  end
@@ -7,8 +7,8 @@ module Kinetic
7
7
  WORKERS = {}
8
8
  SIG_QUEUE = []
9
9
 
10
- delegate :logger, to: :app
11
- delegate :config, to: :app
10
+ delegate :logger, :get, :get!, :set, to: :app
11
+
12
12
 
13
13
  attr_reader :app
14
14
 
@@ -23,12 +23,15 @@ module Kinetic
23
23
  begin
24
24
  logger.info "Starting Kinetic #{Kinetic::VERSION} with PID #{Process.pid}"
25
25
  logger.debug 'Configuration:'
26
- logger.ap config.to_hash
26
+ logger.ap app.class.send(:config).to_hash
27
27
  write_pidfile!
28
28
  initialize_self_pipe!
29
29
  initialize_signal_traps!
30
30
  spawn_missing_workers
31
31
  join
32
+ rescue => e
33
+ logger.fatal e
34
+ logger.fatal 'Unable to start worker!'
32
35
  ensure
33
36
  call_on_exit_callbacks
34
37
  exit!
@@ -53,11 +56,24 @@ module Kinetic
53
56
 
54
57
  private
55
58
 
59
+ def master_sleep(time)
60
+ IO.select([ SELF_PIPE[0] ], nil, nil, time) or return
61
+ SELF_PIPE[0].kgio_tryread(11)
62
+ end
63
+
56
64
  def join
57
- logger.debug "joining thread"
58
- loop do
59
- sleep 1
60
- end
65
+ logger.debug 'Joining thread'
66
+ case SIG_QUEUE.shift
67
+ when :QUIT
68
+ break
69
+ when :TERM, :INT
70
+ logger.warn "#{get(:name)} is shutting down immediately!"
71
+ exit!(1)
72
+ break
73
+ else
74
+ master_sleep(0.5)
75
+ end while true
76
+ logger.warn "#{get(:name)} is going down!"
61
77
  end
62
78
 
63
79
  # Based on Unicorn's self-pipe
@@ -73,33 +89,40 @@ module Kinetic
73
89
  end
74
90
 
75
91
  def awaken_master
76
- logger.debug 'Awakening master'
77
92
  SELF_PIPE[1].kgio_trywrite('.')
78
93
  end
79
94
 
80
95
  def write_pidfile!
81
- config.pid ||= File.join(config.root, "#{config.name}.pid")
82
- logger.info "Writing PID file to #{config.pid}"
83
- File.open(config.pid, 'w') { |f| f.write(Process.pid) }
96
+ set(:pid, File.join(get!(:root), "#{get!(:name)}.pid"))
97
+ logger.info "Writing PID file to #{get!(:pid)}"
98
+ File.open(get!(:pid), 'w') { |f| f.write(Process.pid) }
84
99
  end
85
100
 
86
101
  def call_on_exit_callbacks
87
102
  ensure
88
- FileUtils.rm(config.pid)
103
+ FileUtils.rm(get(:pid)) if get(:pid)
89
104
  end
90
105
 
91
106
  def spawn_missing_workers
92
107
  logger.debug 'Spawning missing workers'
93
108
  worker_nr = -1
94
- until (worker_nr += 1) == config.workers
109
+ until (worker_nr += 1) == get!(:workers)
95
110
  WORKERS.value?(worker_nr) and next
111
+ #noinspection RubyArgCount
96
112
  worker = Worker.new(worker_nr, @app)
97
113
  logger.debug 'Calling before_fork block'
98
114
  before_fork.call(self, worker)
99
115
  logger.debug 'Forking worker'
116
+ parent = Process.pid
100
117
  pid = fork do
101
- app.reopen_logger
102
- worker.run
118
+ begin
119
+ #noinspection RubyArgCount
120
+ worker.run
121
+ rescue => e
122
+ logger.fatal e
123
+ logger.fatal 'Unable to start workers'
124
+ Process.kill(:TERM, parent)
125
+ end
103
126
  end
104
127
  logger.debug "Worker #{worker_nr} started on #{pid}"
105
128
  end
@@ -1,3 +1,3 @@
1
1
  module Kinetic
2
- VERSION = "0.0.1"
2
+ VERSION = '0.0.2'
3
3
  end
@@ -1,8 +1,7 @@
1
1
  module Kinetic
2
2
  class Worker
3
3
 
4
- delegate :logger, to: :app
5
- delegate :config, to: :app
4
+ delegate :logger, :get, :get!, :set, to: :app
6
5
 
7
6
  attr_reader :id, :app, :channel, :exchanges
8
7
 
@@ -24,9 +23,8 @@ module Kinetic
24
23
  end
25
24
 
26
25
  def run
27
- logger.debug "Establishing connection host: '#{config.host}', port: '#{config.port}'"
28
- AMQP.start(host: config.host, port: config.port) do |connection|
29
- app.reopen_logger
26
+ logger.debug "Establishing connection host: '#{get!(:host)}', port: '#{get!(:port)}'"
27
+ AMQP.start(host: get!(:host), port: get!(:port)) do |connection|
30
28
  logger.debug "AMQP started with conneciton #{connection}"
31
29
  initialize_channel!(connection)
32
30
  initialize_exchanges!
@@ -45,7 +43,7 @@ module Kinetic
45
43
  def initialize_exchanges!
46
44
  logger.debug 'Initializing exchanges'
47
45
  @exchanges = {}
48
- prefix = config.name
46
+ prefix = get!(:name)
49
47
  app.exchanges.each_key do |name|
50
48
  logger.debug " Initializing #{name} exchange"
51
49
  @exchanges[name] = channel.send(name, "#{prefix}.#{name}")
data/spec/base_spec.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/kinetic/base'
3
+
4
+ describe Kinetic::Base do
5
+
6
+
7
+
8
+ end
data/spec/dsl_spec.rb ADDED
@@ -0,0 +1,103 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/kinetic/dsl'
3
+ require_relative '../lib/kinetic/errors'
4
+ class TestClass
5
+ extend Kinetic::DSL
6
+ end
7
+
8
+ describe Kinetic::DSL do
9
+ # setting this to open brackes helps us test the returns true case
10
+
11
+ let(:config) { { key: 'value' } }
12
+
13
+ before :each do
14
+ stub_const("Kinetic::Configuration", config)
15
+ end
16
+
17
+ subject do
18
+ TestClass
19
+ end
20
+
21
+ before :each do
22
+ subject.stub(config: config)
23
+ end
24
+
25
+ describe '::set' do
26
+
27
+ it 'returns true' do
28
+ subject.set('foo', 'baz').should == true
29
+ end
30
+
31
+ it 'sets the configuration value' do
32
+ subject.set(:baz, 'bar')
33
+ subject.send(:config)[:baz].should == 'bar'
34
+ end
35
+
36
+ it 'symbolizes strings into keys' do
37
+ subject.set('foo', 'bar')
38
+ subject.send(:config)[:foo].should == 'bar'
39
+ end
40
+
41
+ end
42
+
43
+ describe '::get' do
44
+
45
+ it 'returns the value of the config key' do
46
+ config[:foo] = 'bar'
47
+ subject.get(:foo).should == 'bar'
48
+ end
49
+
50
+ it 'symbolizes the key' do
51
+ config[:baz] = 'bar'
52
+ subject.get('baz').should == 'bar'
53
+ end
54
+
55
+ end
56
+
57
+ describe '::get!' do
58
+
59
+ it 'raises Kinetic::Errors::MissingConfigurationValue if the value is not present' do
60
+ expect do
61
+ subject.send(:get!, :nonexistentkey)
62
+ end.to raise_error(Kinetic::Errors::MissingConfigurationValue)
63
+ end
64
+
65
+ it 'returns the value if the value is present and does not raise an exception' do
66
+ config[:existentkey] = 'foo'
67
+ expect do
68
+ subject.get!(:existentkey).should == 'foo'
69
+ end.not_to raise_error
70
+ end
71
+
72
+ it 'symbolizes the key' do
73
+ config[:akey] = 'foo'
74
+ expect do
75
+ subject.get!(:akey)
76
+ end.not_to raise_error
77
+ end
78
+
79
+ end
80
+
81
+ describe '::logger' do
82
+
83
+ let(:logger) { double('Logger') }
84
+
85
+ after :each do
86
+ subject.instance_variable_set(:@logger, nil)
87
+ end
88
+
89
+ it 'returns calls reopen_logger and returns the result if @logger is nil' do
90
+ subject.instance_variable_set(:@logger, nil)
91
+ subject.should_receive(:reopen_logger).and_return(logger)
92
+ subject.logger.should == logger
93
+ end
94
+
95
+ it 'returns the existing logger if already set' do
96
+ subject.instance_variable_set(:@logger, logger)
97
+ subject.should_not_receive(:reopen_logger)
98
+ subject.logger.should == logger
99
+ end
100
+
101
+ end
102
+
103
+ end
@@ -0,0 +1 @@
1
+ require 'rspec'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kinetic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jarod Reid
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-16 00:00:00.000000000 Z
11
+ date: 2013-12-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: confstruct
@@ -136,6 +136,34 @@ dependencies:
136
136
  - - '>='
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rspec
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: yard
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
139
167
  description: A powerful yet simple AMQP worker framework
140
168
  email:
141
169
  - jreid@voyst.com
@@ -144,6 +172,7 @@ extensions: []
144
172
  extra_rdoc_files: []
145
173
  files:
146
174
  - .gitignore
175
+ - .travis.yml
147
176
  - Gemfile
148
177
  - LICENSE.txt
149
178
  - README.md
@@ -154,11 +183,15 @@ files:
154
183
  - lib/kinetic/base.rb
155
184
  - lib/kinetic/cli.rb
156
185
  - lib/kinetic/configuration.rb
186
+ - lib/kinetic/dsl.rb
157
187
  - lib/kinetic/errors.rb
158
188
  - lib/kinetic/master.rb
159
189
  - lib/kinetic/publisher.rb
160
190
  - lib/kinetic/version.rb
161
191
  - lib/kinetic/worker.rb
192
+ - spec/base_spec.rb
193
+ - spec/dsl_spec.rb
194
+ - spec/spec_helper.rb
162
195
  homepage: ''
163
196
  licenses:
164
197
  - MIT
@@ -183,5 +216,8 @@ rubygems_version: 2.0.3
183
216
  signing_key:
184
217
  specification_version: 4
185
218
  summary: A powerful yet simple AMQP worker framework
186
- test_files: []
219
+ test_files:
220
+ - spec/base_spec.rb
221
+ - spec/dsl_spec.rb
222
+ - spec/spec_helper.rb
187
223
  has_rdoc: