sevak 0.4.4 → 0.5.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,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 20d0243cb06ba1e8a220389877af139bc91baee3
4
- data.tar.gz: 1737e507cd67efa773052cfb41e2079ae1cedda7
3
+ metadata.gz: 952420aaf9a1ee5df304b591f5834a91204e0d95
4
+ data.tar.gz: 8c49b4bf7c75b5795eb63c5352f981f9f2b1c77b
5
5
  SHA512:
6
- metadata.gz: 4da67a783427a9c8efb63994a961d40a31b0f2196164c76af11e2a614570c63dd419d1588131130aaecd00cb919ce090a76b0c52e201f1adce221d6cc151a944
7
- data.tar.gz: '089ff8a69948db534625f10aada9d4fe3a037acc9948d378152dd0f8da0d45dd42940c14812aec7e85860b8f5582d56dfdea3624af0edfcffcd39c41b3d813fb'
6
+ metadata.gz: '0982036b4ce6d2c568b8fb81192bfb496441c46aa3ff011f4365dacec48ceb66dd9d17fa8cf121e222d2bc51387a9da2d217531c9e2251f4f7197b8676d01b4e'
7
+ data.tar.gz: 53feaed12dc1abe46de31842be7c321e9f1f3c5da230130dbd92aeffc8a023301e9b9a8f16a115bd912f2fff66d03070fc3891d6ee8cc722b67780af118dc8b2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- sevak (0.4.4)
4
+ sevak (0.5.0)
5
5
  bunny (~> 2.7)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # Current version
2
2
 
3
- 0.4.3
3
+ 0.4.4
4
4
 
5
5
  Sevak gem makes it easy to send and receive messages from rabbitmq queues. It is built on top of the bunny gem.
6
6
  It also supports delayed queuing using [rabbitmq delayed exchange plugin](https://github.com/rabbitmq/rabbitmq-delayed-message-exchange)
7
7
 
8
+
9
+ Durable option is enabled for all the queues to have persisting queues.
10
+
8
11
  # Dependencies
9
12
 
10
13
  * [rabbitmq delayed exchange plugin](https://github.com/rabbitmq/rabbitmq-delayed-message-exchange):
@@ -19,6 +22,21 @@ To install this plugin:
19
22
  # Installation
20
23
 
21
24
  gem install sevak
25
+
26
+ # Make sure the rabbitmq server is running
27
+
28
+ You can either install and run the rabbitmq server from the appropriate package for your os or you can run the preconfigured docker image for local testing.
29
+
30
+ The image can be found here.
31
+
32
+ https://hub.docker.com/r/deepakkumarnd/sevak/
33
+
34
+ You can run the rabbitmq by doing the following step
35
+
36
+ docker pull deepakkumarnd/sevak
37
+ docker run -d --name rabbitmq_test -p 15672:15672 -p 5672:5672 deepakkumarnd/sevak
38
+
39
+ After this you will be able to access the management console by going to http://localhost:15672. You can login using guest, guest as username and password.
22
40
 
23
41
  # Configuration
24
42
 
@@ -73,3 +91,10 @@ To receive message from this queue and process the message create a consumer fil
73
91
  end
74
92
 
75
93
  The return status can have three values :ok, :error, :retry.
94
+
95
+ ### Run the preconfigured docker container for testing purpose
96
+
97
+ https://hub.docker.com/r/deepakkumarnd/sevak/
98
+
99
+ docker pull deepakkumarnd/sevak
100
+ docker run -d --name rabbitmq_test -p 15672:15672 -p 5672:5672 deepakkumarnd/sevak
@@ -0,0 +1,5 @@
1
+ host: 'localhost'
2
+ port: '5672'
3
+ user: 'guest'
4
+ password: 'guest'
5
+ prefetch_count: 10
data/lib/sevak.rb CHANGED
@@ -11,9 +11,28 @@ module Sevak
11
11
  class Config
12
12
 
13
13
  # allowed configurations
14
- CONFIGURATION = %w(host port user password prefetch_count)
14
+ CONFIGURATION = %w(
15
+ host
16
+ port
17
+ user
18
+ password
19
+ prefetch_count
20
+ autoscale
21
+ max_process_limit
22
+ min_process_limit).freeze
15
23
 
16
24
  def initialize
25
+ @config = {
26
+ 'host' => 'localhost',
27
+ 'port' => '5672',
28
+ 'user' => 'guest',
29
+ 'password' => 'guest',
30
+ 'prefetch_count' => 10,
31
+ 'autoscale' => false,
32
+ 'max_process_limit' => 10,
33
+ 'min_process_limit' => 1
34
+ }
35
+
17
36
  load_configuration_from_yml
18
37
  end
19
38
 
@@ -36,13 +55,15 @@ module Sevak
36
55
  end
37
56
  end
38
57
 
58
+ def to_h
59
+ @config
60
+ end
61
+
39
62
  private
40
63
 
41
64
  def load_configuration_from_yml
42
- @config = {}
43
-
44
65
  if File.exists?('config/sevak.yml')
45
- @config = YAML.load(File.read('config/sevak.yml'))
66
+ @config = @config.merge(YAML.load(File.read('config/sevak.yml')))
46
67
  end
47
68
  end
48
69
 
@@ -64,19 +85,6 @@ module Sevak
64
85
  config
65
86
  end
66
87
 
67
- def self.establish_connection
68
- return @conn if @conn
69
-
70
- @conn ||= Bunny.new(
71
- host: config.host,
72
- port: config.port,
73
- username: config.user,
74
- password: config.password)
75
-
76
- @conn.start
77
- @conn
78
- end
79
-
80
88
  def self.get_logger
81
89
  if !Dir.exist? 'log'
82
90
  FileUtils.mkdir('log')
@@ -93,11 +101,6 @@ module Sevak
93
101
  @logger = Logger.new(logfile, 'weekly')
94
102
  end
95
103
 
96
- def self.log(data)
97
- @logger ||= get_logger
98
- @logger.info(data.inspect)
99
- end
100
-
101
104
  def self.testing?
102
105
  defined?(SEVAK_ENV) && (SEVAK_ENV == 'test')
103
106
  end
@@ -109,5 +112,6 @@ module Sevak
109
112
  end
110
113
 
111
114
  require 'sevak/core'
115
+ require 'sevak/autoscale'
112
116
  require 'sevak/consumer'
113
117
  require 'sevak/publisher'
@@ -0,0 +1,100 @@
1
+ module Sevak
2
+ module Autoscale
3
+ Signal.trap('TERM') { Process.waitall; exit }
4
+ Signal.trap('INT') { Process.waitall; exit }
5
+
6
+ def pids
7
+ @pids ||= []
8
+ end
9
+
10
+ def save_pid
11
+ @pids
12
+ end
13
+
14
+ def stop
15
+ exit
16
+ end
17
+
18
+ def fork_process
19
+ begin
20
+ pid = fork do
21
+ trap('HUP') { stop }
22
+ trap('TERM') { stop }
23
+ trap('INT') { stop }
24
+
25
+ self.class.new.start_worker
26
+ end
27
+
28
+ pids.push(pid)
29
+
30
+ rescue => e
31
+ log("Unable to fork process #{e.message}")
32
+ end
33
+ end
34
+
35
+ def kill_all
36
+ pids.each do |pid|
37
+ kill_process(pid)
38
+ end
39
+ pids = []
40
+ end
41
+
42
+ def kill_process(pid)
43
+ return if pid.nil?
44
+
45
+ begin
46
+ Process.kill("HUP", pid)
47
+ Process.wait
48
+ rescue => e
49
+ log("Unable to kill process #{e.message}")
50
+ end
51
+ end
52
+
53
+ def process_count
54
+ pids.size
55
+ end
56
+
57
+ def cleanup
58
+ kill_all
59
+ exit
60
+ end
61
+
62
+ def calculate_average_load
63
+ ratio = begin
64
+ message_count / process_count
65
+ rescue ZeroDivisionError => e
66
+ 10
67
+ end
68
+
69
+ if ratio >= 10
70
+ :high
71
+ elsif ratio <= 2
72
+ :low
73
+ else
74
+ :medium
75
+ end
76
+ end
77
+
78
+ def start_master_worker
79
+ fork_process
80
+
81
+ loop do
82
+ avg_load = calculate_average_load
83
+
84
+ if (avg_load == :high) && (pids.size < config.max_process_limit)
85
+ fork_process
86
+ elsif (avg_load == :low) && (process_count > config.min_process_limit)
87
+ pid = pids.shift
88
+ kill_process(pid) if pid
89
+ else
90
+ end
91
+
92
+ sleep 5
93
+ end
94
+ rescue => e
95
+ cleanup
96
+ ensure
97
+ cleanup
98
+ end
99
+ end
100
+ end
@@ -6,6 +6,7 @@ module Sevak
6
6
  class ConsumerBase
7
7
 
8
8
  include Core
9
+ include Autoscale
9
10
 
10
11
  DEFAULT_PREFETCH_COUNT = 10
11
12
 
@@ -36,6 +37,14 @@ module Sevak
36
37
  end
37
38
 
38
39
  def start
40
+ if config.autoscale
41
+ start_master_worker
42
+ else
43
+ start_worker
44
+ end
45
+ end
46
+
47
+ def start_worker
39
48
  channel.prefetch(config.prefetch_count || DEFAULT_PREFETCH_COUNT)
40
49
 
41
50
  queue.subscribe(manual_ack: true, exclusive: false) do |delivery_info, metadata, payload|
@@ -47,7 +56,7 @@ module Sevak
47
56
  begin
48
57
  status = run(body)
49
58
  rescue => ex
50
- Sevak.log(exception_details(ex, payload))
59
+ log(exception_details(ex, payload))
51
60
  status = :error
52
61
  end
53
62
 
@@ -91,7 +100,7 @@ module Sevak
91
100
  def run(payload)
92
101
  # implement business logic in the corresponding consumer, the run method should respond with
93
102
  # status :ok, :error, :retry after the processing is over
94
- Sevak.log("Implement run method. Payload: #{payload.inspect} #{}")
103
+ log("Implement run method. Payload: #{payload.inspect} #{}")
95
104
  :ok
96
105
  end
97
106
  end
data/lib/sevak/core.rb CHANGED
@@ -1,7 +1,20 @@
1
1
  module Sevak
2
2
  module Core
3
3
  def connection
4
- ::Sevak.establish_connection
4
+ return @conn if @conn
5
+ @conn ||= Bunny.new(
6
+ host: config.host,
7
+ port: config.port,
8
+ username: config.user,
9
+ password: config.password)
10
+
11
+ @conn.start
12
+ @conn
13
+ end
14
+
15
+ def log(data)
16
+ @logger ||= ::Sevak.get_logger
17
+ @logger.info(data.inspect)
5
18
  end
6
19
 
7
20
  def config
data/lib/sevak/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Sevak
2
- VERSION = '0.4.4'
2
+ VERSION = '0.5.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sevak
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.4
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Deepak Kumar
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-03-01 00:00:00.000000000 Z
11
+ date: 2018-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bunny
@@ -42,7 +42,9 @@ files:
42
42
  - Rakefile
43
43
  - bin/console
44
44
  - bin/setup
45
+ - config/sevak.yml.example
45
46
  - lib/sevak.rb
47
+ - lib/sevak/autoscale.rb
46
48
  - lib/sevak/consumer.rb
47
49
  - lib/sevak/core.rb
48
50
  - lib/sevak/publisher.rb