asynk 0.0.1

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.
Files changed (92) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +172 -0
  5. data/README.md +168 -0
  6. data/asynk.gemspec +27 -0
  7. data/bin/asynk +12 -0
  8. data/bin/asynkctl +93 -0
  9. data/consumer.rb +52 -0
  10. data/lib/asynk/benchmark.rb +21 -0
  11. data/lib/asynk/broker.rb +33 -0
  12. data/lib/asynk/cli.rb +146 -0
  13. data/lib/asynk/config.rb +33 -0
  14. data/lib/asynk/consumer.rb +98 -0
  15. data/lib/asynk/logging.rb +97 -0
  16. data/lib/asynk/message.rb +30 -0
  17. data/lib/asynk/publisher.rb +28 -0
  18. data/lib/asynk/response.rb +57 -0
  19. data/lib/asynk/server.rb +62 -0
  20. data/lib/asynk/sync_publisher.rb +36 -0
  21. data/lib/asynk/test_helper.rb +52 -0
  22. data/lib/asynk/version.rb +3 -0
  23. data/lib/asynk/worker.rb +56 -0
  24. data/lib/asynk.rb +65 -0
  25. data/myapp/.gitignore +17 -0
  26. data/myapp/Gemfile +16 -0
  27. data/myapp/Gemfile.lock +175 -0
  28. data/myapp/README.rdoc +28 -0
  29. data/myapp/Rakefile +6 -0
  30. data/myapp/app/assets/images/.keep +0 -0
  31. data/myapp/app/assets/javascripts/application.js +16 -0
  32. data/myapp/app/assets/stylesheets/application.css +15 -0
  33. data/myapp/app/consumers/wallet_events_consumer.rb +22 -0
  34. data/myapp/app/controllers/application_controller.rb +5 -0
  35. data/myapp/app/controllers/concerns/.keep +0 -0
  36. data/myapp/app/helpers/application_helper.rb +2 -0
  37. data/myapp/app/mailers/.keep +0 -0
  38. data/myapp/app/models/.keep +0 -0
  39. data/myapp/app/models/concerns/.keep +0 -0
  40. data/myapp/app/models/user.rb +2 -0
  41. data/myapp/app/views/layouts/application.html.erb +14 -0
  42. data/myapp/bin/bundle +3 -0
  43. data/myapp/bin/rails +8 -0
  44. data/myapp/bin/rake +8 -0
  45. data/myapp/bin/setup +29 -0
  46. data/myapp/bin/spring +15 -0
  47. data/myapp/config/application.rb +26 -0
  48. data/myapp/config/boot.rb +3 -0
  49. data/myapp/config/database.yml +32 -0
  50. data/myapp/config/environment.rb +5 -0
  51. data/myapp/config/environments/development.rb +41 -0
  52. data/myapp/config/environments/production.rb +79 -0
  53. data/myapp/config/environments/test.rb +42 -0
  54. data/myapp/config/initializers/assets.rb +11 -0
  55. data/myapp/config/initializers/backtrace_silencers.rb +7 -0
  56. data/myapp/config/initializers/cookies_serializer.rb +3 -0
  57. data/myapp/config/initializers/filter_parameter_logging.rb +4 -0
  58. data/myapp/config/initializers/inflections.rb +16 -0
  59. data/myapp/config/initializers/mime_types.rb +4 -0
  60. data/myapp/config/initializers/session_store.rb +3 -0
  61. data/myapp/config/initializers/wrap_parameters.rb +14 -0
  62. data/myapp/config/locales/en.yml +23 -0
  63. data/myapp/config/routes.rb +56 -0
  64. data/myapp/config/secrets.yml +22 -0
  65. data/myapp/config.ru +4 -0
  66. data/myapp/db/migrate/20150826104429_create_users.rb +10 -0
  67. data/myapp/db/schema.rb +26 -0
  68. data/myapp/db/seeds.rb +7 -0
  69. data/myapp/lib/assets/.keep +0 -0
  70. data/myapp/lib/tasks/.keep +0 -0
  71. data/myapp/log/.keep +0 -0
  72. data/myapp/public/404.html +67 -0
  73. data/myapp/public/422.html +67 -0
  74. data/myapp/public/500.html +66 -0
  75. data/myapp/public/favicon.ico +0 -0
  76. data/myapp/public/robots.txt +5 -0
  77. data/myapp/test/controllers/.keep +0 -0
  78. data/myapp/test/fixtures/.keep +0 -0
  79. data/myapp/test/fixtures/users.yml +9 -0
  80. data/myapp/test/helpers/.keep +0 -0
  81. data/myapp/test/integration/.keep +0 -0
  82. data/myapp/test/mailers/.keep +0 -0
  83. data/myapp/test/models/.keep +0 -0
  84. data/myapp/test/models/user_test.rb +7 -0
  85. data/myapp/test/test_helper.rb +10 -0
  86. data/myapp/vendor/assets/javascripts/.keep +0 -0
  87. data/myapp/vendor/assets/stylesheets/.keep +0 -0
  88. data/publisher.rb +15 -0
  89. data/test/consumer_example.rb +31 -0
  90. data/test/consumer_testing_example_test.rb +21 -0
  91. data/test/test_helper.rb +7 -0
  92. metadata +271 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b6ead08e1f2e9906b0871dd76ba54dd493c3873b
4
+ data.tar.gz: 872bbb7241da16c78dd5e54200d76f396852fd46
5
+ SHA512:
6
+ metadata.gz: d60bf2cafe43ce3ff502459ec7d0ddb007e45257387eb3e3078c1af22bf0ad6dfc6f5103b5ed4f955a1a7fa16a7f96d933577bf243c3aa1d1306e656404b25f9
7
+ data.tar.gz: 30a07b0855bf08a7086914a9189f294ea61850fe74bde41868d605d58f1c806bd61880f0ea9cf5c84ce67083c3261265d2efa4fe95a3abef2fd09496502964ca
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ # See https://help.github.com/articles/ignoring-files for more about ignoring files.
2
+ #
3
+ # If you find yourself ignoring temporary files generated by your text editor
4
+ # or operating system, you probably want to add a global ignore instead:
5
+ # git config --global core.excludesfile '~/.gitignore_global'
6
+
7
+ # Ignore bundler config.
8
+ /.bundle
9
+
10
+ # Ignore the default SQLite database.
11
+ /db/*.sqlite3
12
+ /db/*.sqlite3-journal
13
+
14
+ # Ignore all logfiles and tempfiles.
15
+ /log/*
16
+ /log/.keep
17
+ /tmp
18
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,172 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ asynk (0.0.1)
5
+ activesupport
6
+ bunny
7
+ celluloid (~> 0.17.0)
8
+ celluloid-io
9
+ connection_pool
10
+ json (~> 1.0)
11
+
12
+ GEM
13
+ remote: http://rubygems.org/
14
+ specs:
15
+ actionmailer (4.2.3)
16
+ actionpack (= 4.2.3)
17
+ actionview (= 4.2.3)
18
+ activejob (= 4.2.3)
19
+ mail (~> 2.5, >= 2.5.4)
20
+ rails-dom-testing (~> 1.0, >= 1.0.5)
21
+ actionpack (4.2.3)
22
+ actionview (= 4.2.3)
23
+ activesupport (= 4.2.3)
24
+ rack (~> 1.6)
25
+ rack-test (~> 0.6.2)
26
+ rails-dom-testing (~> 1.0, >= 1.0.5)
27
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
28
+ actionview (4.2.3)
29
+ activesupport (= 4.2.3)
30
+ builder (~> 3.1)
31
+ erubis (~> 2.7.0)
32
+ rails-dom-testing (~> 1.0, >= 1.0.5)
33
+ rails-html-sanitizer (~> 1.0, >= 1.0.2)
34
+ activejob (4.2.3)
35
+ activesupport (= 4.2.3)
36
+ globalid (>= 0.3.0)
37
+ activemodel (4.2.3)
38
+ activesupport (= 4.2.3)
39
+ builder (~> 3.1)
40
+ activerecord (4.2.3)
41
+ activemodel (= 4.2.3)
42
+ activesupport (= 4.2.3)
43
+ arel (~> 6.0)
44
+ activesupport (4.2.3)
45
+ i18n (~> 0.7)
46
+ json (~> 1.7, >= 1.7.7)
47
+ minitest (~> 5.1)
48
+ thread_safe (~> 0.3, >= 0.3.4)
49
+ tzinfo (~> 1.1)
50
+ amq-protocol (2.0.0)
51
+ arel (6.0.3)
52
+ builder (3.2.2)
53
+ bunny (2.2.0)
54
+ amq-protocol (>= 2.0.0)
55
+ celluloid (0.17.1.2)
56
+ bundler
57
+ celluloid-essentials
58
+ celluloid-extras
59
+ celluloid-fsm
60
+ celluloid-pool
61
+ celluloid-supervision
62
+ dotenv
63
+ nenv
64
+ rspec-logsplit (>= 0.1.2)
65
+ timers (>= 4.1.1)
66
+ celluloid-essentials (0.20.2.1)
67
+ bundler
68
+ dotenv
69
+ nenv
70
+ rspec-logsplit (>= 0.1.2)
71
+ timers (>= 4.1.1)
72
+ celluloid-extras (0.20.1)
73
+ bundler
74
+ dotenv
75
+ nenv
76
+ rspec-logsplit (>= 0.1.2)
77
+ timers (>= 4.1.1)
78
+ celluloid-fsm (0.20.1)
79
+ bundler
80
+ dotenv
81
+ nenv
82
+ rspec-logsplit (>= 0.1.2)
83
+ timers (>= 4.1.1)
84
+ celluloid-io (0.17.1)
85
+ bundler
86
+ celluloid (>= 0.17.1.1)
87
+ dotenv
88
+ nenv
89
+ nio4r (>= 1.1)
90
+ rspec-logsplit (>= 0.1.2)
91
+ timers (>= 4.1.1)
92
+ celluloid-pool (0.20.1)
93
+ bundler
94
+ dotenv
95
+ nenv
96
+ rspec-logsplit (>= 0.1.2)
97
+ timers (>= 4.1.1)
98
+ celluloid-supervision (0.20.1.1)
99
+ bundler
100
+ dotenv
101
+ nenv
102
+ rspec-logsplit (>= 0.1.2)
103
+ timers (>= 4.1.1)
104
+ connection_pool (2.2.0)
105
+ dotenv (2.0.2)
106
+ erubis (2.7.0)
107
+ globalid (0.3.6)
108
+ activesupport (>= 4.1.0)
109
+ hitimes (1.2.2)
110
+ i18n (0.7.0)
111
+ json (1.8.3)
112
+ loofah (2.0.3)
113
+ nokogiri (>= 1.5.9)
114
+ mail (2.6.3)
115
+ mime-types (>= 1.16, < 3)
116
+ mime-types (2.6.1)
117
+ mini_portile (0.6.2)
118
+ minitest (5.8.0)
119
+ nenv (0.2.0)
120
+ nio4r (1.1.1)
121
+ nokogiri (1.6.6.2)
122
+ mini_portile (~> 0.6.0)
123
+ rack (1.6.4)
124
+ rack-test (0.6.3)
125
+ rack (>= 1.0)
126
+ rails (4.2.3)
127
+ actionmailer (= 4.2.3)
128
+ actionpack (= 4.2.3)
129
+ actionview (= 4.2.3)
130
+ activejob (= 4.2.3)
131
+ activemodel (= 4.2.3)
132
+ activerecord (= 4.2.3)
133
+ activesupport (= 4.2.3)
134
+ bundler (>= 1.3.0, < 2.0)
135
+ railties (= 4.2.3)
136
+ sprockets-rails
137
+ rails-deprecated_sanitizer (1.0.3)
138
+ activesupport (>= 4.2.0.alpha)
139
+ rails-dom-testing (1.0.7)
140
+ activesupport (>= 4.2.0.beta, < 5.0)
141
+ nokogiri (~> 1.6.0)
142
+ rails-deprecated_sanitizer (>= 1.0.1)
143
+ rails-html-sanitizer (1.0.2)
144
+ loofah (~> 2.0)
145
+ railties (4.2.3)
146
+ actionpack (= 4.2.3)
147
+ activesupport (= 4.2.3)
148
+ rake (>= 0.8.7)
149
+ thor (>= 0.18.1, < 2.0)
150
+ rake (10.4.2)
151
+ rspec-logsplit (0.1.3)
152
+ sprockets (3.3.3)
153
+ rack (~> 1.0)
154
+ sprockets-rails (2.3.2)
155
+ actionpack (>= 3.0)
156
+ activesupport (>= 3.0)
157
+ sprockets (>= 2.8, < 4.0)
158
+ thor (0.19.1)
159
+ thread_safe (0.3.5)
160
+ timers (4.1.1)
161
+ hitimes
162
+ tzinfo (1.2.2)
163
+ thread_safe (~> 0.1)
164
+
165
+ PLATFORMS
166
+ ruby
167
+
168
+ DEPENDENCIES
169
+ asynk!
170
+ minitest (~> 5.7, >= 5.7.0)
171
+ rails (~> 4)
172
+ rake (~> 10.0)
data/README.md ADDED
@@ -0,0 +1,168 @@
1
+ # Asynk
2
+
3
+ Asynk is a Ruby library for enabling synchronous/asynchronous inter-service communication, using RabbitMQ.
4
+
5
+ # Overview
6
+
7
+ It's takes concepts of ruby gem called Hutch, but using Cellouid under hood for creating workers for processing queues, which requires significant memory requirements.
8
+ Also as limitation of ruby you cannot make heavy computations in ruby and gather true concurrency. Asynk offers synchronous calls (RPC).
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'asynk'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install asynk
23
+
24
+ ## Usage
25
+
26
+
27
+ Firstly you should define consumer, Example of consumer
28
+
29
+ ```ruby
30
+ class V1::PaymentOrdersConsumer
31
+ include Asynk::Consumer
32
+
33
+ set_consume 'sample_app.v1.users.create', 'sample_app.v1.users.notifications'
34
+
35
+ set_queue_options ack: true
36
+ set_subscribe_arguments manual_ack: true
37
+ set_concurrency 2
38
+ set_route_ending_as_action true
39
+
40
+ # handling asynchronous request from amqp
41
+ def notifications(params)
42
+ # do here some works
43
+ ensure
44
+ ack! # required if you manually processing acknowledgments, available methods reject!, requeue!
45
+ end
46
+
47
+ # example for handling synchronous request
48
+ def create(params)
49
+ result = my_method # here we doing some work, and saving result of
50
+ result = Asynk::Response.new(status: :ok, body: result) # result should any object which implements to_json.
51
+ respond(result) # if producer expecting response, we should response with some data.
52
+ # Is not required to use any format of response. But preferred way is to use class Asynk::Response,
53
+ # which used as lightweight implementation of http. (Containing body, status, and error_message).
54
+ ensure
55
+ ack!
56
+ end
57
+ end
58
+ ```
59
+
60
+ Firstly you should define Class, and include Asynk::Consumer.
61
+ * `set_consume` list of topics to consume
62
+ * `set_queue_options` set for options which created after server initialized
63
+ * `set_subscribe_arguments` set options which passed to when subscribing queue to exchange
64
+ * `set_concurrency` amount of workers which will consume for each consumer
65
+ * `set_route_ending_as_action` this options defines, that last item of consume topic is used as method name (ex: sample_app.v1.users.show, last item show, will be called in this class.)
66
+
67
+ Also, after instance creation, has several methods,
68
+ * `log` logger object for sending logs for default Logger of Asynk.
69
+ * `ack!`, `reject!`, `requeue!` methods is used for handling messages, if you want manually work with acknowledgments
70
+
71
+
72
+
73
+ After declaring consumer, now you can send some request using default Asynk::Publisher, it has two options:
74
+ * `sync_publish` synchronous sending of message, and waiting for response from consumer. You should define timeouts, if consumers crashes it never receives a message. timeout - says the amount of time in seconds for waiting message, if timeout reaches it sends TimeoutError.
75
+ * `publish` just sending message, and forgets about it.
76
+
77
+ ```ruby
78
+ # here sending synchronous messages
79
+ Asynk::Publisher.sync_publish('sample_app.v1.users.create', { name: 'Tom', surname: 'Lane', timeout: 10 })
80
+
81
+ # here sending asynchronous messages
82
+ Asynk::Publisher.publish('sample_app.v1.users.notifications', { name: 'Tom', surname: 'Lane' })
83
+ ```
84
+
85
+
86
+ Asynk is using pool for channels for receiving and sending messages.
87
+ Usage in rails, should initialize authentication data and init connection to RabbitMQ server.
88
+
89
+ ```ruby
90
+ # Init authentication
91
+ Asynk.config[:mq_host] = ENV['MQ_HOST']
92
+ Asynk.config[:mq_username] = ENV['MQ_USERNAME']
93
+ Asynk.config[:mq_password] = ENV['MQ_PASSWORD']
94
+
95
+ # Init connection to server.
96
+ Asynk::Broker.connect
97
+
98
+ # here we initializing logger.
99
+ if Rails.env.stage? || Rails.env.production?
100
+ if Asynk.booted_inside? # if we booting inside asynk, it's separate process than rails server.
101
+ Asynk.logger.level = ::Logger::DEBUG
102
+ else # If we booted inside rails project, we can use rails's logger.
103
+ Asynk.logger = Rails.logger
104
+ end
105
+ else
106
+ Asynk.logger.level = ::Logger::INFO
107
+ Asynk.config[:publisher_execution_time] = false
108
+ end
109
+
110
+ ```
111
+ ## Config options
112
+ * `mq_exchange` exchange to use for publishing (`default` 'asynk_exchange_topic')
113
+ * `sync_publish_wait_timeout` time to wait for sync requests. If timeout reaches, the timeout raised. (`default` 10 seconds)
114
+ * `default_consumer_concurrency` numbers of workers to start per consumer (`default` 1)
115
+ * `logfile` log file for default logger of asynk (`default` 'log/asynk.log')
116
+ * `pidifle` Asynk consumers is running on different process, this file is used to store pid file (`default` 'tmp/pids/asynk.pid')
117
+ * `mq_host` host for connection to broker (RabbitMQ) (`default` 'localhost')
118
+ * `mq_port` port for connection to broker (RabbitMQ) (`default` 5672)
119
+ * `mq_vhost` vhost for connection to broker (RabbitMQ) (`default` '/')
120
+ * `mq_username` username for connection to broker (RabbitMQ) (`default` 'guest')
121
+ * `mq_password` password for connection to broker (RabbitMQ) (`default` 'guest')
122
+ * `publisher_execution_time` used for profiling time to send when using Asynk::Publisher (`default` true)
123
+ * `respond_back_execution_time` used for profiling time used for processing sync response (`default` true)
124
+ * `ignored_consumers` this parameter used for disabling unused consumers as array of strings with consumer class names(`default` [])
125
+
126
+
127
+ # Testing your consumers
128
+ Firstly you should include `Asynk::TestHelper` to your test class, and then call `sync_publish` method for sending request, if this is rpc call,
129
+ invoke the asynk_response method for getting response.
130
+
131
+ Example using with Rails and MiniTest.
132
+ ```ruby
133
+ # test_helper.rb
134
+ class ActiveSupport::TestCase
135
+ # include the test helper.
136
+ include Asynk::TestHelper
137
+
138
+ # wrapping the response with Asynk::Response class, otherwise it will be just string value.
139
+ def asynk_response
140
+ Asynk::Response.try_to_create_from_hash(super)
141
+ end
142
+ end
143
+
144
+
145
+ # some_consumer_test.rb
146
+
147
+ test 'should show profile' do
148
+ publish_sync 'some_route', { name: 'Chris' }
149
+
150
+ assert asynk_response.success? # testing for status of the response
151
+ assert asynk_response[:unread_messages] # testing the returned data
152
+ assert asynk_response[:unread_message_count]
153
+ end
154
+ ```
155
+
156
+ ## Known problems
157
+
158
+ * Poor documentation (source are poorly documented)
159
+ * Poor test coverage (there are almost no test)
160
+ * RPC calls implementation. Currently is implemented as continues loop, which tries get data from reply queue. Before it was implemented using Mutex, which caused huge time usage on handling them. I am not sure that current implementation is correct, but is id much faster in current tests. (On my machine 1-2 ms vs 7-8 ms).
161
+
162
+ ## Contributing
163
+
164
+ 1. Fork it ( https://github.com/[my-github-username]/gm_server/fork )
165
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
166
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
167
+ 4. Push to the branch (`git push origin my-new-feature`)
168
+ 5. Create a new Pull Request
data/asynk.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/asynk/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Danil Nurgaliev"]
6
+ gem.email = ["jkonalegi@gmail.com"]
7
+ gem.summary = "Async/sync inter sevrer communication tool."
8
+ gem.description = "Async/sync inter sevrer communication tool, based on RabbitMQ and Celluloid"
9
+ gem.license = "LGPL-3.0"
10
+ gem.homepage = "https://github.com/konalegi/asynk"
11
+
12
+ gem.files = `git ls-files -z`.split("\x0")
13
+ gem.executables = gem.files.grep(%r{^bin/}) { |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "asynk"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = Asynk::VERSION
18
+ gem.add_dependency 'celluloid', '~> 0.17'
19
+ gem.add_dependency 'celluloid-io', '~> 0.17'
20
+ gem.add_dependency 'connection_pool', '~> 2.2'
21
+ gem.add_dependency 'activesupport', '~> 4.2'
22
+ gem.add_dependency 'json', '~> 1.0'
23
+ gem.add_dependency 'bunny', '~> 2.3'
24
+ gem.add_development_dependency 'minitest', '~> 5.7', '>= 5.7.0'
25
+ gem.add_development_dependency 'rake', '~> 10.0'
26
+ gem.add_development_dependency 'rails', '~> 4'
27
+ end
data/bin/asynk ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require_relative '../lib/asynk/cli'
4
+
5
+ begin
6
+ cli = Asynk::CLI.instance
7
+ cli.run
8
+ rescue => e
9
+ STDERR.puts e.message
10
+ STDERR.puts e.backtrace.join("\n")
11
+ exit 1
12
+ end
data/bin/asynkctl ADDED
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'fileutils'
4
+
5
+ class Asynkctl
6
+ DEFAULT_KILL_TIMEOUT = 10
7
+
8
+ attr_reader :stage, :pidfile, :kill_timeout
9
+
10
+ def self.print_usage
11
+ puts "#{File.basename($0)} - stop a Asynk process from the command line."
12
+ puts
13
+ puts "Usage: #{File.basename($0)} <command> <pidfile> <kill_timeout>"
14
+ puts " where <command> is either 'quiet' or 'stop'"
15
+ puts " <pidfile> is path to a pidfile"
16
+ puts " <kill_timeout> is number of seconds to wait until Asynk exits"
17
+ puts " (default: #{Asynkctl::DEFAULT_KILL_TIMEOUT}), after which Asynk will be KILL'd"
18
+ puts
19
+ puts "Be sure to set the kill_timeout LONGER than Asynk's -t timeout. If you want"
20
+ puts "to wait 60 seconds for jobs to finish, use `Asynk -t 60` and `Asynkctl stop"
21
+ puts " path_to_pidfile 61`"
22
+ puts
23
+ end
24
+
25
+ def initialize(stage, pidfile, timeout)
26
+ @stage = stage
27
+ @pidfile = pidfile
28
+ @kill_timeout = timeout
29
+
30
+ done('No pidfile given', :error) if !pidfile
31
+ done("Pidfile #{pidfile} does not exist", :warn) if !File.exist?(pidfile)
32
+ done('Invalid pidfile content', :error) if pid == 0
33
+
34
+ fetch_process
35
+
36
+ begin
37
+ send(stage)
38
+ rescue NoMethodError
39
+ done "Invalid command: #{stage}", :error
40
+ end
41
+ end
42
+
43
+ def fetch_process
44
+ Process.getpgid(pid)
45
+ rescue Errno::ESRCH
46
+ done "Process doesn't exist", :error
47
+ end
48
+
49
+ def done(msg, error = nil)
50
+ puts msg
51
+ exit(exit_signal(error))
52
+ end
53
+
54
+ def exit_signal(error)
55
+ (error == :error) ? 1 : 0
56
+ end
57
+
58
+ def pid
59
+ @pid ||= File.read(pidfile).to_i
60
+ end
61
+
62
+ def quiet
63
+ Process.kill(:USR1, pid)
64
+ end
65
+
66
+ def stop
67
+ Process.kill(:TERM, pid)
68
+ kill_timeout.times do
69
+ begin
70
+ Process.getpgid(pid)
71
+ rescue Errno::ESRCH
72
+ FileUtils.rm_f pidfile
73
+ done 'Asynk shut down gracefully.'
74
+ end
75
+ sleep 1
76
+ end
77
+ Process.kill(:KILL, pid)
78
+ FileUtils.rm_f pidfile
79
+ done 'Asynk shut down forcefully.'
80
+ end
81
+ alias_method :shutdown, :stop
82
+ end
83
+
84
+ if ARGV.length < 2
85
+ Asynkctl.print_usage
86
+ else
87
+ stage = ARGV[0]
88
+ pidfile = ARGV[1]
89
+ timeout = ARGV[2].to_i
90
+ timeout = Asynkctl::DEFAULT_KILL_TIMEOUT if timeout == 0
91
+
92
+ Asynkctl.new(stage, pidfile, timeout)
93
+ end
data/consumer.rb ADDED
@@ -0,0 +1,52 @@
1
+ require 'celluloid'
2
+ require 'celluloid/io'
3
+ require 'celluloid/autostart'
4
+ require 'bunny'
5
+
6
+ class Worker
7
+ include Celluloid::IO
8
+ finalizer :shutdown
9
+
10
+ def initialize(conn)
11
+ @ch = conn.create_channel
12
+ q = @ch.queue('task_queue', :durable => true)
13
+ q.subscribe manual_ack: true, &method(:on_event)
14
+ p 'worker accepting connections'
15
+ end
16
+
17
+ def on_event(delivery_info, properties, body)
18
+ p "#{Time.now.strftime('%FT %T.%L')} started work: #{body}"
19
+ sleep(10)
20
+ p "#{Time.now.strftime('%FT %T.%L')} completed work: #{body}"
21
+ @ch.ack(delivery_info.delivery_tag)
22
+ end
23
+
24
+ def shutdown
25
+ p 'trying to shutdown...'
26
+ @ch.close
27
+ p 'hey shutdown'
28
+ end
29
+ end
30
+
31
+ class Consumer
32
+ def initialize(options = {})
33
+ @size = (ENV['POOL'] || 2).to_i
34
+ @connection = Bunny.new(options)
35
+ @connection.start
36
+ @workers = @size.times.map{ Worker.new(@connection) }
37
+ end
38
+
39
+ def close_connection
40
+ futures = @workers.map { |w| w.future(:finalize) }
41
+ @connection.close if futures.all?
42
+ end
43
+ end
44
+
45
+ begin
46
+ @consumer = Consumer.new
47
+ rescue Interrupt => _
48
+ @consumer.close_connection
49
+ end
50
+
51
+ sleep
52
+
@@ -0,0 +1,21 @@
1
+ module Asynk
2
+ class Benchmark
3
+ class << self
4
+
5
+ def measure_around(&block)
6
+ start_time = Time.now.to_f
7
+ block.call
8
+ ((Time.now.to_f - start_time)*1000).round(2)
9
+ end
10
+
11
+ def start
12
+ Time.now.to_f
13
+ end
14
+
15
+ def end(start_time)
16
+ ((Time.now.to_f - start_time)*1000).round(2)
17
+ end
18
+
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,33 @@
1
+ # require 'carrot-top'
2
+
3
+ module Asynk
4
+ class Broker
5
+ class << self
6
+ def connect
7
+ @amqp_connection = Bunny.new(host: Asynk.config[:mq_host],
8
+ port: Asynk.config[:mq_port],
9
+ username: Asynk.config[:mq_username],
10
+ password: Asynk.config[:mq_password],
11
+ vhost: Asynk.config[:mq_vhost])
12
+ Asynk.logger.info [ "Connection to Rabbit with params host: #{Asynk.config[:mq_host]}:#{Asynk.config[:mq_port]}",
13
+ "username: '#{Asynk.config[:mq_username]}' ", "vhost: '#{Asynk.config[:mq_vhost]}'"
14
+ ].join(' ')
15
+
16
+ @amqp_connection.start
17
+
18
+ @pool = ConnectionPool.new(size: 10, timeout: 5) do
19
+ channel = @amqp_connection.create_channel(nil, nil)
20
+ [channel, channel.topic(Asynk.config[:mq_exchange]), channel.queue('', exclusive: true)]
21
+ end
22
+ end
23
+
24
+ def disconnect
25
+ @amqp_connection.close if @amqp_connection
26
+ @amqp_connection = nil
27
+ end
28
+
29
+ def pool; @pool; end
30
+ def amqp_connection; @amqp_connection; end
31
+ end
32
+ end
33
+ end