hawkei 1.0.0
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 +4 -0
- data/.rspec +1 -0
- data/.rubocop.yml +48 -0
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/.travis.yml +11 -0
- data/Gemfile +12 -0
- data/LICENCE +21 -0
- data/Makefile +9 -0
- data/README.md +17 -0
- data/Rakefile +4 -0
- data/hawkei.gemspec +28 -0
- data/lib/hawkei/api_operation/delete.rb +38 -0
- data/lib/hawkei/api_operation/save.rb +57 -0
- data/lib/hawkei/api_resource.rb +130 -0
- data/lib/hawkei/batch.rb +18 -0
- data/lib/hawkei/config.rb +123 -0
- data/lib/hawkei/errors.rb +41 -0
- data/lib/hawkei/formated_logger.rb +45 -0
- data/lib/hawkei/hawkei_object.rb +179 -0
- data/lib/hawkei/library_name.rb +3 -0
- data/lib/hawkei/message.rb +79 -0
- data/lib/hawkei/plugins/rack/middleware.rb +139 -0
- data/lib/hawkei/plugins/rails/data.rb +19 -0
- data/lib/hawkei/plugins/rails/middleware_data.rb +28 -0
- data/lib/hawkei/plugins/rails/railtie.rb +23 -0
- data/lib/hawkei/plugins/sidekiq/client_middleware.rb +19 -0
- data/lib/hawkei/plugins/sidekiq/load.rb +14 -0
- data/lib/hawkei/plugins/sidekiq/server_middleware.rb +48 -0
- data/lib/hawkei/plugins.rb +17 -0
- data/lib/hawkei/processor/async.rb +50 -0
- data/lib/hawkei/processor/batch.rb +84 -0
- data/lib/hawkei/processor/worker.rb +113 -0
- data/lib/hawkei/request.rb +134 -0
- data/lib/hawkei/store.rb +49 -0
- data/lib/hawkei/util.rb +180 -0
- data/lib/hawkei/version.rb +3 -0
- data/lib/hawkei/watcher.rb +15 -0
- data/lib/hawkei.rb +170 -0
- data/spec/lib/hawkei/api_resource_spec.rb +109 -0
- data/spec/lib/hawkei/batch_spec.rb +14 -0
- data/spec/lib/hawkei/config_spec.rb +36 -0
- data/spec/lib/hawkei/formated_logger_spec.rb +99 -0
- data/spec/lib/hawkei/hawkei_object_spec.rb +123 -0
- data/spec/lib/hawkei/message_spec.rb +178 -0
- data/spec/lib/hawkei/plugins/rack/middleware_spec.rb +88 -0
- data/spec/lib/hawkei/plugins/rails/data_spec.rb +22 -0
- data/spec/lib/hawkei/plugins/rails/middleware_data_spec.rb +46 -0
- data/spec/lib/hawkei/plugins/sidekiq/client_middleware_spec.rb +15 -0
- data/spec/lib/hawkei/plugins/sidekiq/server_middleware_spec.rb +58 -0
- data/spec/lib/hawkei/processor/async_spec.rb +36 -0
- data/spec/lib/hawkei/processor/batch_spec.rb +51 -0
- data/spec/lib/hawkei/processor/worker_spec.rb +100 -0
- data/spec/lib/hawkei/store_spec.rb +82 -0
- data/spec/lib/hawkei/util_spec.rb +132 -0
- data/spec/lib/hawkei/watcher_spec.rb +25 -0
- data/spec/lib/hawkei_spec.rb +175 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/support/rack_app.rb +12 -0
- metadata +206 -0
@@ -0,0 +1,179 @@
|
|
1
|
+
module Hawkei
|
2
|
+
##
|
3
|
+
# == Hawkei \Object
|
4
|
+
#
|
5
|
+
# Define the API objects
|
6
|
+
class HawkeiObject
|
7
|
+
##
|
8
|
+
# @return [Hash] JSON parsed response
|
9
|
+
attr_reader :raw
|
10
|
+
|
11
|
+
##
|
12
|
+
# @return [Hash] JSON parsed response
|
13
|
+
attr_reader :data
|
14
|
+
|
15
|
+
attr_reader :errors
|
16
|
+
|
17
|
+
attr_reader :successful
|
18
|
+
alias successful? successful
|
19
|
+
|
20
|
+
class << self
|
21
|
+
|
22
|
+
##
|
23
|
+
# Initialize from the API response
|
24
|
+
#
|
25
|
+
# @return [Hawkei::HawkeiObject]
|
26
|
+
def initialize_from(response, object = new)
|
27
|
+
object.load_response_api(response.is_a?(Hash) ? response : Util.safe_json_parse(response))
|
28
|
+
object.update_attributes(Hawkei::Util.except_keys(object.raw, :data))
|
29
|
+
if object.raw[:object] == 'list'
|
30
|
+
object.raw[:data].each do |response_object|
|
31
|
+
data = object.type_from_string_object(response_object[:object]).initialize_from(response_object)
|
32
|
+
|
33
|
+
object.add_data(data)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
object
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# Update the object based on the response from the API
|
44
|
+
# Remove and new accessor
|
45
|
+
#
|
46
|
+
# @param [Hash] response
|
47
|
+
#
|
48
|
+
# @return [Hawkei::HawkeiObject]
|
49
|
+
def update_from(response)
|
50
|
+
self.class.initialize_from(response, self)
|
51
|
+
|
52
|
+
(@values.keys - raw.keys).each { |key| remove_accessor(key) }
|
53
|
+
|
54
|
+
self
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# Initialize and create accessor for values
|
59
|
+
#
|
60
|
+
# @params [Hash] values
|
61
|
+
def initialize(values = {})
|
62
|
+
@data = []
|
63
|
+
@values = {}
|
64
|
+
|
65
|
+
update_attributes(values)
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# get attribute value
|
70
|
+
def [](key)
|
71
|
+
@values[key.to_sym]
|
72
|
+
end
|
73
|
+
|
74
|
+
##
|
75
|
+
# set attribute value
|
76
|
+
def []=(key, value)
|
77
|
+
send(:"#{key}=", value)
|
78
|
+
end
|
79
|
+
|
80
|
+
##
|
81
|
+
# @return [Array] all the keys
|
82
|
+
def keys
|
83
|
+
@values.keys
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# @return [Hash] values to hash
|
88
|
+
def to_hash
|
89
|
+
@values
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# @return [JSON] values to JSON
|
94
|
+
def to_json(_object = nil)
|
95
|
+
JSON.generate(@values)
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Update the attribute and add accessor for new attributes
|
100
|
+
#
|
101
|
+
# @param [Hash] values
|
102
|
+
def update_attributes(attributes)
|
103
|
+
attributes.each do |(key, value)|
|
104
|
+
add_accessor(key, value)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# Load the root components for the API response
|
110
|
+
#
|
111
|
+
# @param [Hash] values
|
112
|
+
def load_response_api(response)
|
113
|
+
@raw = Hawkei::Util.deep_underscore_key(response)
|
114
|
+
@successful = true
|
115
|
+
end
|
116
|
+
|
117
|
+
##
|
118
|
+
# Add data for sub-object
|
119
|
+
#
|
120
|
+
# @param [Object] data
|
121
|
+
def add_data(data)
|
122
|
+
@data << data
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Create an object from a string
|
127
|
+
#
|
128
|
+
# @param [String] object to be build
|
129
|
+
#
|
130
|
+
# @return [Object]
|
131
|
+
def type_from_string_object(string_object)
|
132
|
+
klass_name = Hawkei::Util.camelize(string_object.to_s)
|
133
|
+
|
134
|
+
Object.const_get("Hawkei::#{klass_name}")
|
135
|
+
end
|
136
|
+
|
137
|
+
def inspect
|
138
|
+
id_string = respond_to?(:id) && !id.nil? ? " id=#{id}" : ''
|
139
|
+
"#<#{self.class}:0x#{object_id.to_s(16)}#{id_string}> JSON: " + JSON.pretty_generate(@values)
|
140
|
+
end
|
141
|
+
|
142
|
+
def method_missing(name, *args)
|
143
|
+
super unless name.to_s.end_with?('=')
|
144
|
+
|
145
|
+
attribute = name.to_s[0...-1].to_sym
|
146
|
+
value = args.first
|
147
|
+
|
148
|
+
add_accessor(attribute, value)
|
149
|
+
end
|
150
|
+
|
151
|
+
private
|
152
|
+
|
153
|
+
def add_accessors(keys, payload = raw)
|
154
|
+
keys.each do |key|
|
155
|
+
add_accessor(key, payload[key])
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def add_accessor(name, value)
|
160
|
+
@values[name] = value
|
161
|
+
|
162
|
+
define_singleton_method(name) { @values[name] }
|
163
|
+
define_singleton_method(:"#{name}=") do |v|
|
164
|
+
@values[name] = v
|
165
|
+
end
|
166
|
+
|
167
|
+
define_singleton_method(:"#{name}?") { value } if [FalseClass, TrueClass].include?(value.class)
|
168
|
+
end
|
169
|
+
|
170
|
+
def remove_accessor(name)
|
171
|
+
@values.delete(name)
|
172
|
+
|
173
|
+
singleton_class.class_eval { remove_method name.to_sym } if singleton_methods.include?(name.to_sym)
|
174
|
+
singleton_class.class_eval { remove_method "#{name}=".to_sym } if singleton_methods.include?("#{name}=".to_sym)
|
175
|
+
singleton_class.class_eval { remove_method "#{name}?".to_sym } if singleton_methods.include?("#{name}?".to_sym)
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Hawkei
|
2
|
+
##
|
3
|
+
# == Hawkei \Message
|
4
|
+
#
|
5
|
+
# Return the base message for an event
|
6
|
+
class Message
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def base
|
10
|
+
Util.deep_compact(
|
11
|
+
message_id: SecureRandom.uuid,
|
12
|
+
timestamp: Time.now.utc.iso8601(3),
|
13
|
+
session_tracker_id: session_tracker_id,
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def extended
|
18
|
+
Util.deep_compact(
|
19
|
+
library: library,
|
20
|
+
server: server,
|
21
|
+
request: Hawkei::Store.get(:request),
|
22
|
+
worker: Hawkei::Store.get(:worker),
|
23
|
+
environment: Hawkei::Store.get(:environment) || Hawkei.configurations.environment_name,
|
24
|
+
metadata: metadata
|
25
|
+
).merge(base)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def session_tracker_id
|
31
|
+
return Hawkei::Store.get(:session_tracker_id) if Hawkei::Store.exist?(:session_tracker_id)
|
32
|
+
|
33
|
+
Hawkei::Store.set(:session_tracker_id, SecureRandom.uuid)
|
34
|
+
end
|
35
|
+
|
36
|
+
def library
|
37
|
+
{
|
38
|
+
name: Hawkei::LIBRARY_NAME,
|
39
|
+
language: 'ruby',
|
40
|
+
version: Hawkei::VERSION,
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
def server
|
45
|
+
{
|
46
|
+
host: Socket.gethostname,
|
47
|
+
pid: Process.pid,
|
48
|
+
software: Hawkei::Store.get(:server_software) || program_name,
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def program_name
|
53
|
+
name = $PROGRAM_NAME
|
54
|
+
|
55
|
+
name.split('/').last
|
56
|
+
rescue StandardError => _e
|
57
|
+
name
|
58
|
+
end
|
59
|
+
|
60
|
+
def metadata
|
61
|
+
return nil if Hawkei.configurations.metadata.nil?
|
62
|
+
|
63
|
+
Hawkei.configurations.metadata.each_with_object({}) do |(key, value), hash|
|
64
|
+
if value.is_a?(Proc)
|
65
|
+
begin
|
66
|
+
hash[key] = value.call
|
67
|
+
rescue StandardError => _e
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
next
|
71
|
+
end
|
72
|
+
|
73
|
+
hash[key] = value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Hawkei
|
4
|
+
module Plugins
|
5
|
+
module Rack
|
6
|
+
##
|
7
|
+
# Hawkei \Plugins \Rack \Middleware
|
8
|
+
#
|
9
|
+
# Middleware for Rack
|
10
|
+
#
|
11
|
+
class Middleware
|
12
|
+
|
13
|
+
def initialize(app)
|
14
|
+
@app = app
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(env)
|
18
|
+
request = ::Rack::Request.new(env)
|
19
|
+
|
20
|
+
store_tracker(request)
|
21
|
+
store_request_data(request, env)
|
22
|
+
|
23
|
+
Hawkei::Plugins::Rails::MiddlewareData.store_data(request) if defined?(::Rails)
|
24
|
+
status, headers, body = @app.call(env)
|
25
|
+
|
26
|
+
write_cookie_session_tracker_id!(headers)
|
27
|
+
[status, headers, body]
|
28
|
+
ensure
|
29
|
+
Hawkei::Store.clear! unless env['hawkei_test']
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def session_tracker_id_name
|
35
|
+
'_hawkei_stid'.freeze
|
36
|
+
end
|
37
|
+
|
38
|
+
def store_tracker(request)
|
39
|
+
Hawkei::Store.set(
|
40
|
+
:session_tracker_id,
|
41
|
+
request.cookies[session_tracker_id_name] || SecureRandom.uuid
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def store_request_data(request, env)
|
46
|
+
Hawkei::Store.set(
|
47
|
+
:request,
|
48
|
+
url: obfuscate_uri(request.url),
|
49
|
+
ssl: request.ssl?,
|
50
|
+
host: request.host,
|
51
|
+
port: request.port,
|
52
|
+
path: request.path,
|
53
|
+
referrer: obfuscate_uri(request.referrer),
|
54
|
+
method: request.request_method,
|
55
|
+
xhr: request.xhr?,
|
56
|
+
user_agent: request.user_agent,
|
57
|
+
ip: request.ip,
|
58
|
+
get_params: obfuscation_get_params(request, 'GET'),
|
59
|
+
post_params: obfuscation_get_params(request, 'POST'),
|
60
|
+
headers: obfuscate_headers(env)
|
61
|
+
)
|
62
|
+
|
63
|
+
Hawkei::Store.bulk_set(
|
64
|
+
server_software: request.env['SERVER_SOFTWARE']
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
def write_cookie_session_tracker_id!(headers)
|
69
|
+
::Rack::Utils.set_cookie_header!(
|
70
|
+
headers || {},
|
71
|
+
session_tracker_id_name,
|
72
|
+
Util.deep_compact(
|
73
|
+
value: Hawkei::Store.get(:session_tracker_id),
|
74
|
+
path: '/',
|
75
|
+
domain: Hawkei.configurations.domain,
|
76
|
+
http_only: false,
|
77
|
+
max_age: (10 * 365 * 24 * 60 * 60),
|
78
|
+
)
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
82
|
+
def obfuscate_uri(url)
|
83
|
+
uri = URI.parse(url)
|
84
|
+
|
85
|
+
params =
|
86
|
+
Util.deep_obfuscate_value(
|
87
|
+
::Rack::Utils.parse_query(uri.query),
|
88
|
+
Hawkei.configurations.obfuscated_fields,
|
89
|
+
'HIDDEN'
|
90
|
+
)
|
91
|
+
|
92
|
+
return url if params.empty?
|
93
|
+
|
94
|
+
uri.merge(
|
95
|
+
"?#{::Rack::Utils.build_query(params)}"
|
96
|
+
).to_s
|
97
|
+
rescue StandardError => _e
|
98
|
+
''
|
99
|
+
end
|
100
|
+
|
101
|
+
def obfuscation_get_params(request, type)
|
102
|
+
Util.deep_obfuscate_value(
|
103
|
+
request.send(type),
|
104
|
+
Hawkei.configurations.obfuscated_fields
|
105
|
+
)
|
106
|
+
rescue StandardError => _e
|
107
|
+
{}
|
108
|
+
end
|
109
|
+
|
110
|
+
def https_request?(env)
|
111
|
+
env['HTTPS'] == 'on' ||
|
112
|
+
env['HTTP_X_FORWARDED_SSL'] == 'on' ||
|
113
|
+
env['HTTP_X_FORWARDED_PROTO'].to_s.split(',').first == 'https' ||
|
114
|
+
env['rack.url_scheme'] == 'https'
|
115
|
+
end
|
116
|
+
|
117
|
+
def obfuscate_headers(env)
|
118
|
+
skip_headers = %w[HTTP_COOKIE]
|
119
|
+
|
120
|
+
headers = env.keys.grep(/^HTTP_|^CONTENT_/).each_with_object({}) do |key, hash|
|
121
|
+
next if skip_headers.include?(key)
|
122
|
+
|
123
|
+
name = key.gsub(/^HTTP_/, '').split('_').map(&:capitalize).join('-')
|
124
|
+
|
125
|
+
hash[name] = env[key]
|
126
|
+
end
|
127
|
+
|
128
|
+
Util.deep_obfuscate_value(
|
129
|
+
headers,
|
130
|
+
Hawkei.configurations.obfuscated_fields
|
131
|
+
)
|
132
|
+
rescue StandardError => _e
|
133
|
+
{}
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Hawkei
|
2
|
+
module Plugins
|
3
|
+
module Rails
|
4
|
+
class MiddlewareData
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
def store_data(request = nil)
|
9
|
+
store_request_data(request) if request
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def store_request_data(request)
|
15
|
+
object = Hawkei::Store.get(:request) || {}
|
16
|
+
|
17
|
+
Hawkei::Store.set(
|
18
|
+
:request,
|
19
|
+
object.merge(id: request.env['action_dispatch.request_id'])
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Hawkei
|
2
|
+
module Plugins
|
3
|
+
module Rails
|
4
|
+
class Railtie < ::Rails::Railtie
|
5
|
+
|
6
|
+
initializer 'hawkei.middleware' do |app|
|
7
|
+
app.config.middleware.use(Hawkei::Plugins::Rack::Middleware)
|
8
|
+
|
9
|
+
if ActiveSupport.const_defined?(:Reloader) && ActiveSupport::Reloader.respond_to?(:to_complete)
|
10
|
+
ActiveSupport::Reloader.to_complete do
|
11
|
+
Hawkei::Store.clear!
|
12
|
+
end
|
13
|
+
elsif ActionDispatch.const_defined?(:Reloader) && ActionDispatch::Reloader.respond_to?(:to_cleanup)
|
14
|
+
ActionDispatch::Reloader.to_cleanup do
|
15
|
+
Hawkei::Store.clear!
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Hawkei
|
2
|
+
module Plugins
|
3
|
+
module Sidekiq
|
4
|
+
##
|
5
|
+
# Hawkei \Plugins \Sidekiq \Client \Middleware
|
6
|
+
#
|
7
|
+
# Client middleware for sidekiq
|
8
|
+
#
|
9
|
+
class ClientMiddleware
|
10
|
+
|
11
|
+
def call(_worker_class, job, _queue, _redis_pool)
|
12
|
+
job['_hawkei_stid'] = Hawkei::Store.store[:session_tracker_id]
|
13
|
+
yield
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'hawkei/plugins/sidekiq/client_middleware'
|
2
|
+
require 'hawkei/plugins/sidekiq/server_middleware'
|
3
|
+
|
4
|
+
Sidekiq.configure_client do |config|
|
5
|
+
config.client_middleware do |chain|
|
6
|
+
chain.add Hawkei::Plugins::Sidekiq::ClientMiddleware
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
Sidekiq.configure_server do |config|
|
11
|
+
config.server_middleware do |chain|
|
12
|
+
chain.add Hawkei::Plugins::Sidekiq::ServerMiddleware
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Hawkei
|
2
|
+
module Plugins
|
3
|
+
module Sidekiq
|
4
|
+
##
|
5
|
+
# Hawkei \Plugins \Sidekiq \Server \Middleware
|
6
|
+
#
|
7
|
+
# Server middleware for sidekiq
|
8
|
+
#
|
9
|
+
class ServerMiddleware
|
10
|
+
|
11
|
+
def call(_worker, job, _queue)
|
12
|
+
Hawkei::Store.set(:session_tracker_id, job['_hawkei_stid'] || SecureRandom.uuid)
|
13
|
+
Hawkei::Store.set(:server_software, "Sidekiq #{::Sidekiq::VERSION}")
|
14
|
+
store_worker_data(job)
|
15
|
+
yield
|
16
|
+
ensure
|
17
|
+
Hawkei::Store.clear!
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def store_worker_data(job)
|
23
|
+
Hawkei::Store.set(
|
24
|
+
:worker,
|
25
|
+
name: 'sidekiq',
|
26
|
+
version: ::Sidekiq::VERSION,
|
27
|
+
queue: job['queue'],
|
28
|
+
class: job['class'],
|
29
|
+
id: job['jid'],
|
30
|
+
created_at: convert_to_iso8601(job['created_at']),
|
31
|
+
process_at: convert_to_iso8601(job['enqueued_at']),
|
32
|
+
args: job['args'],
|
33
|
+
retried: job['retry_count'].is_a?(Integer),
|
34
|
+
retry_number: job['retry_count'],
|
35
|
+
failed_at: convert_to_iso8601(job['failed_at'])
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def convert_to_iso8601(int_time)
|
40
|
+
Time.at(int_time).utc.iso8601(3)
|
41
|
+
rescue StandardError => _e
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
##
|
2
|
+
# Rack & Rails
|
3
|
+
#
|
4
|
+
if defined?(Rack)
|
5
|
+
require 'hawkei/plugins/rack/middleware'
|
6
|
+
|
7
|
+
if defined?(Rails)
|
8
|
+
require 'hawkei/plugins/rails/railtie'
|
9
|
+
require 'hawkei/plugins/rails/middleware_data'
|
10
|
+
require 'hawkei/plugins/rails/data'
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Sidekiq
|
16
|
+
#
|
17
|
+
require 'hawkei/plugins/sidekiq/load' if defined?(Sidekiq)
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Hawkei
|
2
|
+
module Processor
|
3
|
+
class Async
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@queue = Queue.new
|
7
|
+
@state_worker = Concurrent::AtomicBoolean.new(true)
|
8
|
+
@worker = Worker.new(@queue, @state_worker)
|
9
|
+
|
10
|
+
at_exit do
|
11
|
+
shutdown_worker if worker_running?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def enqueue(attributes)
|
16
|
+
ensure_worker_running
|
17
|
+
|
18
|
+
@queue << attributes
|
19
|
+
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def shutdown_worker
|
26
|
+
@state_worker.make_false
|
27
|
+
@queue << Hawkei::Processor::Worker::SHUTDOWN_MESSAGE
|
28
|
+
@worker_thread.wait
|
29
|
+
|
30
|
+
executor.shutdown
|
31
|
+
executor.wait_for_termination
|
32
|
+
end
|
33
|
+
|
34
|
+
def executor
|
35
|
+
@executor ||= Concurrent.global_io_executor
|
36
|
+
end
|
37
|
+
|
38
|
+
def ensure_worker_running
|
39
|
+
return if worker_running?
|
40
|
+
|
41
|
+
@worker_thread = Concurrent::Future.execute { @worker.run }
|
42
|
+
end
|
43
|
+
|
44
|
+
def worker_running?
|
45
|
+
@worker_thread && @worker_thread.incomplete?
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Hawkei
|
2
|
+
module Processor
|
3
|
+
class Batch
|
4
|
+
|
5
|
+
attr_reader :messages
|
6
|
+
|
7
|
+
MAX_BYTES = 204_800 # 200Kb
|
8
|
+
MAX_MESSAGES = 100
|
9
|
+
MAX_MESSAGE_BYTES = 32_768 # 32Kb
|
10
|
+
|
11
|
+
DEFAULT_RETRY_TIME = 60
|
12
|
+
|
13
|
+
MAX_RETRY = 10
|
14
|
+
RETRY_MAP = {
|
15
|
+
1 => 2,
|
16
|
+
2 => 5,
|
17
|
+
3 => 10,
|
18
|
+
4 => 20,
|
19
|
+
5 => 30,
|
20
|
+
6 => 30,
|
21
|
+
7 => 30,
|
22
|
+
8 => 30,
|
23
|
+
9 => 30,
|
24
|
+
10 => 30,
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@retry_count = 0
|
29
|
+
@total_bytes = 0
|
30
|
+
@messages = []
|
31
|
+
end
|
32
|
+
|
33
|
+
def <<(message)
|
34
|
+
message_json_size = message.to_json.bytesize
|
35
|
+
|
36
|
+
if max_message_reached?(message_json_size)
|
37
|
+
Hawkei.configurations.logger.error('Message is too big to be send')
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
|
41
|
+
@total_bytes += message_json_size
|
42
|
+
|
43
|
+
@messages << message
|
44
|
+
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
def empty?
|
49
|
+
@messages.size.zero?
|
50
|
+
end
|
51
|
+
|
52
|
+
def full?
|
53
|
+
max_messages_reached? || max_size_reached?
|
54
|
+
end
|
55
|
+
|
56
|
+
def next_retry
|
57
|
+
RETRY_MAP[@retry_count] || DEFAULT_RETRY_TIME
|
58
|
+
end
|
59
|
+
|
60
|
+
def update_retry
|
61
|
+
@retry_count += 1
|
62
|
+
end
|
63
|
+
|
64
|
+
def can_retry?
|
65
|
+
@retry_count < MAX_RETRY
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
def max_messages_reached?
|
71
|
+
@messages.length >= MAX_MESSAGES
|
72
|
+
end
|
73
|
+
|
74
|
+
def max_size_reached?
|
75
|
+
@total_bytes >= MAX_BYTES
|
76
|
+
end
|
77
|
+
|
78
|
+
def max_message_reached?(message_json_size)
|
79
|
+
message_json_size > MAX_MESSAGE_BYTES
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|