sevak 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 255061d49d7c114c2635cf303f0741b632001222
4
+ data.tar.gz: 72ed6a68f4979c751ff3116c091c397c6b3b7e79
5
+ SHA512:
6
+ metadata.gz: 7572555dc028728c8460d1a3304124cfb548d45e171c9325bd080df76263ee186aaf01042eb22aeb7c4b85aa41680b5c0ea85e6d187d40fe0aaf8481a80c732d
7
+ data.tar.gz: 88fd6c8ece0a9c02216d19f561e87bd01b2726c112b78ee3955b125feff70bf565d480733f9b2bceeb785100e331a5ea96ad64081b081bddb8f5b9954d89594c
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ vendor/
10
+ /log/
11
+ /.idea/
@@ -0,0 +1 @@
1
+ 2.4.0
@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.4.0
data/Gemfile ADDED
@@ -0,0 +1,12 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sevak.gemspec
4
+ gemspec
5
+
6
+ gem 'bunny'
7
+ gem 'pry'
8
+ gem 'guard'
9
+ gem 'guard-minitest'
10
+ gem 'mocha'
11
+ gem 'highline'
12
+ gem 'rake'
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ sevak (0.2.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ amq-protocol (2.2.0)
10
+ bunny (2.7.0)
11
+ amq-protocol (>= 2.2.0)
12
+ coderay (1.1.2)
13
+ ffi (1.9.18)
14
+ formatador (0.2.5)
15
+ guard (2.14.1)
16
+ formatador (>= 0.2.4)
17
+ listen (>= 2.7, < 4.0)
18
+ lumberjack (~> 1.0)
19
+ nenv (~> 0.1)
20
+ notiffany (~> 0.0)
21
+ pry (>= 0.9.12)
22
+ shellany (~> 0.0)
23
+ thor (>= 0.18.1)
24
+ guard-compat (1.2.1)
25
+ guard-minitest (2.4.6)
26
+ guard-compat (~> 1.2)
27
+ minitest (>= 3.0)
28
+ highline (1.7.8)
29
+ listen (3.1.5)
30
+ rb-fsevent (~> 0.9, >= 0.9.4)
31
+ rb-inotify (~> 0.9, >= 0.9.7)
32
+ ruby_dep (~> 1.2)
33
+ lumberjack (1.0.12)
34
+ metaclass (0.0.4)
35
+ method_source (0.8.2)
36
+ minitest (5.10.3)
37
+ mocha (1.3.0)
38
+ metaclass (~> 0.0.1)
39
+ nenv (0.3.0)
40
+ notiffany (0.1.1)
41
+ nenv (~> 0.1)
42
+ shellany (~> 0.0)
43
+ pry (0.11.0)
44
+ coderay (~> 1.1.0)
45
+ method_source (~> 0.8.1)
46
+ rake (12.1.0)
47
+ rb-fsevent (0.10.2)
48
+ rb-inotify (0.9.10)
49
+ ffi (>= 0.5.0, < 2)
50
+ ruby_dep (1.5.0)
51
+ shellany (0.0.1)
52
+ thor (0.20.0)
53
+
54
+ PLATFORMS
55
+ ruby
56
+
57
+ DEPENDENCIES
58
+ bunny
59
+ guard
60
+ guard-minitest
61
+ highline
62
+ mocha
63
+ pry
64
+ rake
65
+ sevak!
66
+
67
+ BUNDLED WITH
68
+ 1.15.4
@@ -0,0 +1,42 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ ## Uncomment and set this to only include directories you want to watch
5
+ # directories %w(app lib config test spec features) \
6
+ # .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
7
+
8
+ ## Note: if you are using the `directories` clause above and you are not
9
+ ## watching the project directory ('.'), then you will want to move
10
+ ## the Guardfile to a watched dir and symlink it back, e.g.
11
+ #
12
+ # $ mkdir config
13
+ # $ mv Guardfile config/
14
+ # $ ln -s config/Guardfile .
15
+ #
16
+ # and, you'll have to watch "config/Guardfile" instead of "Guardfile"
17
+
18
+ guard :minitest do
19
+ # with Minitest::Unit
20
+ watch(%r{^test/(.*)\/?test_(.*)\.rb$})
21
+ watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
22
+ watch(%r{^test/test_helper\.rb$}) { 'test' }
23
+
24
+ # with Minitest::Spec
25
+ # watch(%r{^spec/(.*)_spec\.rb$})
26
+ # watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
27
+ # watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
28
+
29
+ # Rails 4
30
+ # watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
31
+ # watch(%r{^app/controllers/application_controller\.rb$}) { 'test/controllers' }
32
+ # watch(%r{^app/controllers/(.+)_controller\.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
33
+ # watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
34
+ # watch(%r{^lib/(.+)\.rb$}) { |m| "test/lib/#{m[1]}_test.rb" }
35
+ # watch(%r{^test/.+_test\.rb$})
36
+ # watch(%r{^test/test_helper\.rb$}) { 'test' }
37
+
38
+ # Rails < 4
39
+ # watch(%r{^app/controllers/(.*)\.rb$}) { |m| "test/functional/#{m[1]}_test.rb" }
40
+ # watch(%r{^app/helpers/(.*)\.rb$}) { |m| "test/helpers/#{m[1]}_test.rb" }
41
+ # watch(%r{^app/models/(.*)\.rb$}) { |m| "test/unit/#{m[1]}_test.rb" }
42
+ end
@@ -0,0 +1 @@
1
+ Copyright (c) 2016 Backwater Technologies Pvt Ltd
@@ -0,0 +1,37 @@
1
+ Sevak gem provides makes it easy to send and receive messages from rabbitmq queues. It is buit on top of the bunny gem.
2
+
3
+
4
+ Usage:
5
+
6
+ Install
7
+
8
+ gem install sevak
9
+
10
+ In your code to publish some message to a queue 'sms'.
11
+
12
+
13
+ Sevak::Publisher.publish('sms', message = { name: 'Deepak', msisdn: '9078657543' })
14
+
15
+ If the queue is not present already it will be created automatically.
16
+
17
+
18
+ To receive message from this queue and process the message a create a consumer.
19
+
20
+
21
+ class SmsConsumer < Sevak::Consumer
22
+
23
+ queue_name 'sms'
24
+
25
+ def run(message)
26
+ status = process(message)
27
+ status
28
+ end
29
+
30
+ ..
31
+ end
32
+
33
+ The return status can have three values :ok, :error, :retry.
34
+
35
+ Publishing to the queue
36
+
37
+ Publisher.publish('in.chillr.email', { name: 'Deepak Kumar', message: 'welcome', email: 'deepak@chillr.in' })
@@ -0,0 +1,85 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'sevak'
3
+ require 'highline'
4
+
5
+ # run tests by running command `rake test`
6
+ require 'rake/testtask'
7
+
8
+ Rake::TestTask.new do |t|
9
+ t.libs << 'test'
10
+ t.verbose = true
11
+ t.test_files = FileList['test/**/*_spec.rb']
12
+ t.warning = false
13
+ end
14
+
15
+ # Load all rake tasks in the tasks folder
16
+
17
+ tasks = FileList["tasks/*.rake"]
18
+
19
+ tasks.each { |task| load(task) }
20
+
21
+ namespace :consumer do
22
+
23
+ desc 'Interactively create a new consumer'
24
+ task :new do
25
+
26
+ cli = HighLine.new
27
+
28
+ consumer_name = cli.ask('Input consumer name(eg. push_alert) :') { |q| q.validate = /\A[a-z]+[a-z_]+[a-z]\z/}
29
+ queue_name = cli.ask('Input queue name(eg. in.chillr.push.default)') { |q| q.validate = /\A[a-z]+[a-z.]+[a-z]\z/}
30
+
31
+ to_class_name = Proc.new do |name|
32
+ name.split('_').map(&:capitalize).join
33
+ end
34
+
35
+ text1 = <<-CODE
36
+
37
+ module ChillrSevak
38
+
39
+ class #{to_class_name.call(consumer_name)}Consumer < Consumer
40
+
41
+ queue_name "#{queue_name}"
42
+
43
+ def run(payload)
44
+ puts "Consumer running"
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ CODE
51
+
52
+ if File.exists?("lib/sevak/consumers/#{consumer_name}_consumer.rb")
53
+ puts "Already exists file: lib/sevak/consumers/#{consumer_name}_consumer.rb"
54
+ ans = cli.ask('Do you want to overwrite it ? (y/n)') { |q| q.validate = /Y|N|y|n/}
55
+ exit(-1) if ans.downcase == 'n'
56
+ end
57
+
58
+ file = File.open("lib/sevak/consumers/#{consumer_name}_consumer.rb", 'w+')
59
+ file.write(text1)
60
+ file.close
61
+
62
+ text2 = <<-CODE
63
+ namespace :sevak do
64
+
65
+ desc "Run the #{consumer_name} worker"
66
+ task :#{consumer_name} do
67
+ consumer = ChillrSevak::#{to_class_name.call(consumer_name)}Consumer.new
68
+ consumer.start
69
+ end
70
+ end
71
+
72
+ CODE
73
+
74
+ if File.exists?("tasks/#{consumer_name}.rake")
75
+ puts "Already exists file: tasks/#{consumer_name}.rake"
76
+ ans = cli.ask('Do you want to overwrite it ? (y/n)') { |q| q.validate = /Y|N|y|n/}
77
+ exit(-1) if ans.downcase == 'n'
78
+ end
79
+
80
+ file = File.open("tasks/#{consumer_name}.rake", 'w+')
81
+ file.write(text2)
82
+ file.close
83
+
84
+ end
85
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'sevak'
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require 'irb'
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sevak/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'sevak'
8
+ spec.version = Sevak::VERSION
9
+ spec.authors = ['Deepak Kumar']
10
+ spec.email = ['deepakkumarnd@gmail.com']
11
+
12
+ spec.summary = %q{Consumers for chillr api}
13
+ spec.description = %q{Consumers for chillr api}
14
+ spec.homepage = ''
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ # spec.add_development_dependency 'bundler', '~> 1.9'
23
+ # spec.add_development_dependency 'rake', '~> 10.0'
24
+ end
@@ -0,0 +1,5 @@
1
+ host: 'localhost'
2
+ port: '5672'
3
+ user: 'guest'
4
+ password: 'guest'
5
+ prefetch_count: 10
@@ -0,0 +1,110 @@
1
+ Bundler.require(:default)
2
+
3
+ require 'yaml'
4
+ require 'json'
5
+ require 'logger'
6
+ require 'fileutils'
7
+ require 'sevak/version'
8
+
9
+ module Sevak
10
+
11
+ # initialize configuration from the config/*.yml file
12
+ class Config
13
+
14
+ # allowed configurations
15
+ CONFIGURATION = %w(host port user password prefetch_count)
16
+
17
+ def initialize
18
+ load_configuration_from_yml
19
+ end
20
+
21
+ def method_missing(name, *args)
22
+ setter = false
23
+
24
+ name = name.to_s
25
+
26
+ if name =~ /=$/
27
+ name = name.to_s.chop
28
+ setter = true
29
+ end
30
+
31
+ super(name, args) unless CONFIGURATION.include?(name)
32
+
33
+ if setter
34
+ set(name, args.first)
35
+ else
36
+ get(name)
37
+ end
38
+ end
39
+
40
+ private
41
+
42
+ def load_configuration_from_yml
43
+ @config = YAML.load(File.read('config/default.yml'))
44
+ end
45
+
46
+ def set(key, val)
47
+ @config[key] = val
48
+ end
49
+
50
+ def get(key)
51
+ @config[key]
52
+ end
53
+ end
54
+
55
+ def self.config
56
+ @config ||= Config.new
57
+ end
58
+
59
+ def self.configure
60
+ yield(config) if block_given?
61
+ config
62
+ end
63
+
64
+ def self.establish_connection
65
+ return @conn if @conn
66
+
67
+ @conn ||= Bunny.new(
68
+ host: config.host,
69
+ port: config.port,
70
+ username: config.user,
71
+ password: config.password)
72
+
73
+ @conn.start
74
+ @conn
75
+ end
76
+
77
+ def self.get_logger
78
+ if !Dir.exist? 'log'
79
+ FileUtils.mkdir('log')
80
+ end
81
+
82
+ logfile = if !testing?
83
+ File.open('log/sevak.log', 'a')
84
+ else
85
+ File.open('log/sevak_test.log', 'a')
86
+ end
87
+
88
+ # TODO make configurable
89
+ logfile.sync = true
90
+ @logger = Logger.new(logfile, 'weekly')
91
+ end
92
+
93
+ def self.log(data)
94
+ @logger ||= get_logger
95
+ @logger.info(data.inspect)
96
+ end
97
+
98
+ def self.testing?
99
+ defined?(SEVAK_ENV) && (SEVAK_ENV == 'test')
100
+ end
101
+
102
+ def self.root
103
+ File.expand_path(File.dirname(File.dirname(__FILE__)))
104
+ end
105
+
106
+ end
107
+
108
+ require 'sevak/core'
109
+ require 'sevak/consumer'
110
+ require 'sevak/publisher'
@@ -0,0 +1,98 @@
1
+ module Sevak
2
+
3
+ # Base class for all queue consumers, all consumers should inherit from the base Sevak::Consumer and must implement a
4
+ # run method. The run method should implement the business logic.
5
+
6
+ class ConsumerBase
7
+
8
+ include Core
9
+
10
+ DEFAULT_PREFETCH_COUNT = 10
11
+
12
+ # class methods
13
+ def self.queue_name(name='default')
14
+ @queue_name ||= name
15
+ end
16
+ # end of class methods
17
+
18
+ def initialize
19
+ @queue_name = self.class.queue_name
20
+ end
21
+
22
+ def queue_name
23
+ @queue_name
24
+ end
25
+
26
+ def queue
27
+ @queue ||= channel.queue(queue_name)
28
+ end
29
+
30
+ def channel
31
+ @channel ||= connection.create_channel
32
+ end
33
+
34
+ def message_count
35
+ queue.message_count
36
+ end
37
+
38
+ def start
39
+ channel.prefetch(config.prefetch_count || DEFAULT_PREFETCH_COUNT)
40
+
41
+ queue.subscribe(manual_ack: true, exclusive: false) do |delivery_info, metadata, payload|
42
+ body = JSON.parse(payload)
43
+
44
+ # p delivery_info
45
+ # p metadata
46
+
47
+ begin
48
+ status = run(body)
49
+ rescue => ex
50
+ Sevak.log(exception_details(ex, payload))
51
+ status = :error
52
+ end
53
+
54
+ if status == :ok
55
+ channel.ack(delivery_info.delivery_tag)
56
+ elsif status == :retry
57
+ channel.reject(delivery_info.delivery_tag, true)
58
+ else # :error, nil etc
59
+ channel.reject(delivery_info.delivery_tag, false)
60
+ end
61
+ end
62
+
63
+ wait_for_threads
64
+ end
65
+
66
+ def wait_for_threads
67
+ sleep
68
+ end
69
+
70
+ def exception_details(e, payload = nil)
71
+ h = {
72
+ source: "#{self.class}",
73
+ type: "#{e.class}",
74
+ message: e.message,
75
+ payload: payload.inspect,
76
+ backtrace: (e.backtrace || []).take(3).join("\n")
77
+ }
78
+
79
+ msg = h.map { |k,v| "#{k.to_s.capitalize}: #{v.to_s}"}.join(' | ')
80
+
81
+ "Sevak Exception: #{msg}"
82
+ end
83
+
84
+ end
85
+
86
+ class Consumer < ConsumerBase
87
+
88
+ # Set the queue name for the consumer
89
+ queue_name 'sevak.default'
90
+
91
+ def run(payload)
92
+ # implement business logic in the corresponding consumer, the run method should respond with
93
+ # status :ok, :error, :retry after the processing is over
94
+ Sevak.log("Implement run method. Payload: #{payload.inspect} #{}")
95
+ :ok
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,11 @@
1
+ module Sevak
2
+ module Core
3
+ def connection
4
+ ::Sevak.establish_connection
5
+ end
6
+
7
+ def config
8
+ ::Sevak.config
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ require 'singleton'
2
+
3
+ module Sevak
4
+ class Publisher
5
+ include Core
6
+ include Singleton
7
+
8
+ def self.publish(queue_name, message)
9
+ instance.channel.queue(queue_name).publish(message.to_json)
10
+ end
11
+
12
+ def channel
13
+ @channel ||= connection.create_channel
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,3 @@
1
+ module Sevak
2
+ VERSION = '0.2.0'
3
+ end
File without changes
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sevak
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Deepak Kumar
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-11-16 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Consumers for chillr api
14
+ email:
15
+ - deepakkumarnd@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".ruby-version"
22
+ - ".travis.yml"
23
+ - Gemfile
24
+ - Gemfile.lock
25
+ - Guardfile
26
+ - LICENSE.txt
27
+ - README.md
28
+ - Rakefile
29
+ - bin/console
30
+ - bin/setup
31
+ - chillr_sevak.gemspec
32
+ - config/default.yml.example
33
+ - lib/sevak.rb
34
+ - lib/sevak/consumer.rb
35
+ - lib/sevak/core.rb
36
+ - lib/sevak/publisher.rb
37
+ - lib/sevak/version.rb
38
+ - tasks/.keep
39
+ homepage: ''
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.6.8
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Consumers for chillr api
63
+ test_files: []
64
+ has_rdoc: