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.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +22 -0
- data/README.md +33 -0
- data/Rakefile +4 -0
- data/lib/airbrake/airbrake.rb +7 -0
- data/lib/dependencies.rb +29 -0
- data/lib/models/account.rb +50 -0
- data/lib/models/provider.rb +11 -0
- data/lib/models/transaction.rb +22 -0
- data/lib/rails/rails.rb +19 -0
- data/lib/sidekiq/sidekiq.rb +14 -0
- data/lib/sidekiq_strategies.rb +10 -0
- data/lib/sidekiq_strategies/account_handler.rb +151 -0
- data/lib/sidekiq_strategies/base.rb +19 -0
- data/lib/sidekiq_strategies/beanstalkd_handler.rb +32 -0
- data/lib/sidekiq_strategies/helper.rb +50 -0
- data/lib/sidekiq_strategies/polling_strategy.rb +252 -0
- data/lib/sidekiq_strategies/version.rb +3 -0
- data/lib/spool/publisher.rb +15 -0
- data/lib/spool/subscribers/events_agent_subscriber.rb +11 -0
- data/lib/spool/subscribers/redis_pubsub_subscriber.rb +11 -0
- data/lib/strategy_runner.rb +26 -0
- data/sidekiq_strategies.gemspec +27 -0
- data/spec/spec_helper.rb +66 -0
- data/spec/strategies/account_handler_spec.rb +182 -0
- data/spec/strategies/beanstalkd_handler_spec.rb +50 -0
- data/spec/strategies/helper_spec.rb +61 -0
- data/spec/strategies/polling_strategy_spec.rb +206 -0
- data/spec/support/seed_helpers.rb +83 -0
- data/tasks/rspec.rake +3 -0
- metadata +169 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
@@ -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
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
worker-strategy-1
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.1.1
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -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.
|
data/README.md
ADDED
@@ -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
|
data/Rakefile
ADDED
data/lib/dependencies.rb
ADDED
@@ -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,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
|
data/lib/rails/rails.rb
ADDED
@@ -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,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
|