sidekiq_strategies 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.
@@ -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