sidekiq_strategies 0.0.1

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: 37a73d5707ee07eeed24504034bfc7629d0d7f2f
4
+ data.tar.gz: d7e1979d4427a24ee68bb0e3115afc0f882334f4
5
+ SHA512:
6
+ metadata.gz: 103f746077d383396643f666d4c170c7b75873afb466879fa096b72d16411a601719dccf9bfa74314622f948a76bffc87978f1d585ba16f9526fe1a65fedc22b
7
+ data.tar.gz: 12d2c4d6ff59b45a61a7398636ca75e34d126ae64684bfaa363a4de131f2a1b4895ed44f68f4f14d3b455d9ae7a04270d3a370c5c4a457008fc9d40a200661cb
@@ -0,0 +1,22 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1 @@
1
+ worker-strategy-1
@@ -0,0 +1 @@
1
+ 2.1.1
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'xbp_errors', :git => 'git@github.com:blue-kite/xbp_errors.git', :branch => 'feature/worker_polling_strategy'
4
+
5
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 abrahamb
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,33 @@
1
+ Sidekiq Worker Strategies
2
+ =========================
3
+
4
+ ## Description
5
+ This project contains various types of strategies that handle communication between the accounts-cc and worker-cc.
6
+
7
+ ## Polling strategy
8
+ This strategy is a simple algorithm that basically follow these simple steps:
9
+
10
+ 1. Load account and transaction information.
11
+ 2. Establish connection with request and reply tubes.
12
+ 3. Validate if the account is in a valid state.
13
+ 4. Validate if there are available watchers (workers ready to process the job).
14
+ 5. Validate if the provider is available (pending implementation).
15
+ 6. Search for data in reply tube in case that previously a worker has processed the job.
16
+ 7. Search for an existing request job in buried state and put it back in the ready queue.
17
+ 8. Put a new request job if steps 6 and 7 are not meet and start polling on request tube to obatin a reply job.
18
+ 9. Process the reply job.
19
+
20
+ This strategy needs to be included on accounts-cc to see in the real world how it works, the only necessary files are:
21
+
22
+ 1. lib/account_handler.rb
23
+ 2. lib/beanstalk_handler.rb
24
+ 3. polling_strategy.rb
25
+
26
+ NOTES:
27
+ - models.rb and models/* are like mocks used to run this strategy stand-alone.
28
+ - lines commented with double '#' indicates that are lines that should be uncommented in accounts-cc
29
+ - lines that have 'TODO: remove' indicates that are lines that should be commented or deleted on accounts-cc
30
+
31
+ ## SPECS
32
+
33
+ Pending
@@ -0,0 +1,4 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ Dir.glob('tasks/**/*.rake').each(&method(:import))
4
+
@@ -0,0 +1,7 @@
1
+ class Airbrake
2
+
3
+ def self.notify(message)
4
+ puts "Airbrake::notify: '#{message}'"
5
+ end
6
+
7
+ end
@@ -0,0 +1,29 @@
1
+ libdir = File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
3
+
4
+ require 'bundler'
5
+ Bundler.require
6
+
7
+ require 'beaneater'
8
+ require 'oj'
9
+ require 'money'
10
+
11
+ # Publisher
12
+ require 'spool/publisher'
13
+
14
+ # Subscriers
15
+ require 'spool/subscribers/events_agent_subscriber'
16
+ require 'spool/subscribers/redis_pubsub_subscriber'
17
+
18
+ # Rails things
19
+ require 'sidekiq/sidekiq'
20
+ require 'rails/rails'
21
+ require 'airbrake/airbrake'
22
+
23
+ # Models
24
+ require 'models/account'
25
+ require 'models/provider'
26
+ require 'models/transaction'
27
+
28
+ # Strategies core
29
+ require 'sidekiq_strategies'
@@ -0,0 +1,50 @@
1
+ require 'ostruct'
2
+
3
+ class Account
4
+ attr_accessor :state, :id, :number, :service, :country, :response, :currency, :country_code
5
+
6
+ def initialize(id)
7
+ self.state = 'reserved'
8
+ self.id = id
9
+ self.number = '55748576'
10
+ self.service = OpenStruct.new
11
+ self.country = OpenStruct.new
12
+ self.service.slug = 'claro-postpay'
13
+ self.country.code = 'gt'
14
+ self.currency = "USD"
15
+ self.country_code = 'gt'
16
+ end
17
+
18
+ def self.find(account_id)
19
+ Account.new(account_id)
20
+ end
21
+
22
+ def transactions
23
+ Transaction.new
24
+ end
25
+
26
+ def send(action)
27
+ if action == 'start_query!'
28
+ self.state = 'querying'
29
+ else
30
+ self
31
+ end
32
+ end
33
+
34
+ def success
35
+ self.state = 'ready'
36
+ end
37
+
38
+ def error
39
+ self.state = 'error'
40
+ end
41
+
42
+ def queue_for_retry
43
+ self.state = 'awaiting_retry'
44
+ end
45
+
46
+ def queue_for_wait_at_worker
47
+ self.state = 'waiting_at_worker'
48
+ end
49
+
50
+ end
@@ -0,0 +1,11 @@
1
+ class Provider
2
+
3
+ def queue
4
+ "pronet"
5
+ end
6
+
7
+ def queue_options
8
+ {provider: 'claro_postpay'}
9
+ end
10
+
11
+ end
@@ -0,0 +1,22 @@
1
+ require 'ostruct'
2
+
3
+ class Transaction
4
+ attr_accessor :retry_count, :fields, :provider, :response, :amount, :exception_type, :exception_message, :fields, :beanstalkd_jid, :response_code, :response_message, :sidekiq_jid, :id
5
+
6
+ def initialize(id=nil)
7
+ self.retry_count = 0
8
+ self.provider = Provider.new
9
+ self.fields = {reference: "", end_user_id: "", priority: "normal", code:"", end_user_ip_address: "192.168.0.1", monitor_as_url: "http://10.33.33.22:3000/v1/services/gt/claro-postpay/accounts/1", account_number: "55748576", total_cents: ""}
10
+ self.beanstalkd_jid = nil
11
+ self.id = id
12
+ end
13
+
14
+ def find(account_id)
15
+ Transaction.new(account_id)
16
+ end
17
+
18
+ def save!(args = {})
19
+ puts "save transaction!"
20
+ end
21
+
22
+ end
@@ -0,0 +1,19 @@
1
+ module Rails
2
+
3
+ def self.application
4
+ self
5
+ end
6
+
7
+ def self.routes
8
+ self
9
+ end
10
+
11
+ def self.url_helpers
12
+ self
13
+ end
14
+
15
+ def v1_account_url(params)
16
+ "http://api.bluekite.com/v1/services/#{params[:cc]}/#{params[:slug]}/accounts/#{params[:id]}"
17
+ end
18
+
19
+ end
@@ -0,0 +1,14 @@
1
+ class Sidekiq
2
+
3
+ def self.logger
4
+ self
5
+ end
6
+
7
+ def self.warn(message)
8
+ puts "Sidekiq::warn: #{message}"
9
+ end
10
+
11
+ def self.info(message)
12
+ puts "Sidekiq::info: #{message}"
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ require "sidekiq_strategies/version"
2
+ require 'sidekiq_strategies/base'
3
+ require 'sidekiq_strategies/beanstalkd_handler'
4
+ require 'sidekiq_strategies/helper'
5
+ require 'sidekiq_strategies/account_handler'
6
+ require 'sidekiq_strategies/polling_strategy'
7
+
8
+ module SidekiqStrategies
9
+
10
+ end
@@ -0,0 +1,151 @@
1
+ module SidekiqStrategies
2
+
3
+ class AccountHandler
4
+ attr_accessor :account, :transaction, :action, :priority
5
+
6
+ def initialize(account_id, transaction_id, action, priority, publisher)
7
+ self.action = action
8
+ self.priority = priority
9
+ load_account(account_id)
10
+ load_transaction(transaction_id)
11
+ self.class.send(:include, publisher)
12
+ end
13
+
14
+ def save_sidekiq_jid(jid)
15
+ self.transaction.sidekiq_jid = jid
16
+ self.transaction.save!
17
+ end
18
+
19
+ def save_beanstalkd_jid(jid)
20
+ self.transaction.beanstalkd_jid = jid
21
+ self.transaction.save!
22
+ end
23
+
24
+ def success
25
+ previous_account_state = self.account.state
26
+ self.account.success
27
+ publish(:state_changed , self.account, previous_account_state, self.account.state)
28
+ end
29
+
30
+ def error
31
+ previous_account_state = self.account.state
32
+ self.account.error
33
+ publish(:state_changed , self.account, previous_account_state, self.account.state)
34
+ end
35
+
36
+ def start_action
37
+ previous_account_state = self.account.state
38
+ self.account.send "start_#{self.action}!"
39
+ publish(:state_changed , self.account, previous_account_state, self.account.state)
40
+ end
41
+
42
+ def queue_for_retry
43
+ previous_account_state = self.account.state
44
+ self.transaction.retry_count += 1
45
+ self.account.queue_for_retry
46
+ self.transaction.save!(validate: false)
47
+ publish(:state_changed , self.account, previous_account_state, self.account.state)
48
+ end
49
+
50
+ def queue_for_wait_at_worker
51
+ previous_account_state = self.account.state
52
+ self.account.queue_for_wait_at_worker
53
+ publish(:state_changed , self.account, previous_account_state, self.account.state)
54
+ end
55
+
56
+ def save_success_response(body)
57
+ self.transaction.response = body
58
+ self.transaction.amount = body[:amount_due]
59
+
60
+ action_response = self.send("#{action_name}_response")
61
+ self.account.send(self.action).response = action_response
62
+ self.transaction.save!(validate: false)
63
+ end
64
+
65
+ def save_exception(exception)
66
+ parsed_exception = parse_exception(exception)
67
+
68
+ self.transaction.response = parsed_exception
69
+ self.transaction.response_code = parsed_exception[:code]
70
+ self.transaction.response_message = parsed_exception[:message]
71
+
72
+ self.transaction.exception_message = parsed_exception[:message]
73
+ self.transaction.exception_type = parsed_exception[:type]
74
+
75
+ self.transaction.save!(validate: false)
76
+ end
77
+
78
+ def action_name
79
+ action_name = self.action
80
+ action_name = 'pay' if action_name == 'payment'
81
+ action_name = 'revert' if action_name == 'reversion'
82
+
83
+ action_name
84
+ end
85
+
86
+ private
87
+
88
+ def load_account(account_id)
89
+ self.account = Account.find(account_id)
90
+ end
91
+
92
+ def load_transaction(transaction_id)
93
+ self.transaction = account.transactions.find(transaction_id)
94
+ end
95
+
96
+ def query_response
97
+ body = self.transaction.response
98
+
99
+ # public fields
100
+ response = {
101
+ name: ( body[:name] || body["name"] ),
102
+ address: ( body[:address] || body["address"] ),
103
+ amount_cents: self.transaction.amount,
104
+ amount: Money.new(self.transaction.amount, self.account.currency).format }
105
+
106
+ # private fields
107
+ keys = body.keys.select { |k| k.to_s =~ /^_/ }
108
+ keys.each do |k|
109
+ response[k] = body[k]
110
+ end
111
+
112
+ response
113
+ end
114
+
115
+ def payment_response
116
+ {
117
+ reference: self.transaction.reference
118
+ }
119
+ end
120
+
121
+ def authorization_response
122
+ {
123
+ validity: (self.transaction.response[:validity] || self.transaction.response["validity"]),
124
+ message: (self.transaction.response[:message] || self.transaction.response["message"])
125
+ }
126
+ end
127
+
128
+ def reversion_response
129
+ {}
130
+ end
131
+
132
+ def parse_exception(exception)
133
+ unless exception.kind_of?(StandardError)
134
+ ex = exception
135
+ else
136
+ ex = {
137
+ type: exception.class.to_s,
138
+ code: exception.code,
139
+ message: exception.message,
140
+ partner_code: ( exception.partner_code rescue 1000 ),
141
+ partner_message: ( exception.partner_message rescue exception.to_s ),
142
+ http_code: 500,
143
+ retry_action: ( exception.retry_action rescue false )
144
+ }
145
+ end
146
+ ex
147
+ end
148
+
149
+ end
150
+
151
+ end
@@ -0,0 +1,19 @@
1
+ module SidekiqStrategies
2
+
3
+ class Base
4
+
5
+ def initialize(acc_handler, bns_handler, logger, airbrake_notifier)
6
+ raise 'Error, no implementation'
7
+ end
8
+
9
+ def retries_exhausted(msg)
10
+ raise 'Error, no implementation'
11
+ end
12
+
13
+ def perform(sidekiq_jid)
14
+ raise 'Error, no implementation'
15
+ end
16
+
17
+ end
18
+
19
+ end