hoodoo 1.19.0 → 2.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 +4 -4
- data/lib/hoodoo/active/active_model/uuid_validator.rb +0 -1
- data/lib/hoodoo/active/active_record/dated.rb +2 -2
- data/lib/hoodoo/active/active_record/support.rb +2 -1
- data/lib/hoodoo/active/active_record/uuid.rb +2 -2
- data/lib/hoodoo/active/active_record/writer.rb +1 -1
- data/lib/hoodoo/generator.rb +52 -12
- data/lib/hoodoo/monkey/patch/datadog_traced_amqp.rb +11 -6
- data/lib/hoodoo/monkey/patch/newrelic_middleware_analytics.rb +17 -10
- data/lib/hoodoo/monkey/patch/newrelic_traced_amqp.rb +71 -33
- data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +13 -8
- data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +8 -3
- data/lib/hoodoo/services/middleware/interaction.rb +1 -1
- data/lib/hoodoo/services/middleware/middleware.rb +52 -41
- data/lib/hoodoo/version.rb +2 -2
- data/spec/active/active_record/creator_spec.rb +1 -1
- data/spec/active/active_record/dated_spec.rb +7 -7
- data/spec/active/active_record/finder_spec.rb +953 -839
- data/spec/active/active_record/manually_dated_spec.rb +1 -1
- data/spec/active/active_record/search_helper_spec.rb +1 -1
- data/spec/active/active_record/secure_spec.rb +2 -2
- data/spec/active/active_record/support_spec.rb +3 -3
- data/spec/monkey/patch/datadog_traced_amqp_spec.rb +10 -2
- data/spec/monkey/patch/newrelic_traced_amqp_spec.rb +54 -21
- data/spec/new_relic/agent/logger.rb +24 -0
- data/spec/new_relic/agent/transaction.rb +32 -0
- data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +48 -2
- data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +4 -4
- data/spec/services/middleware/middleware_multi_local_spec.rb +41 -13
- data/spec/services/middleware/middleware_multi_remote_spec.rb +93 -67
- data/spec/services/middleware/middleware_spec.rb +80 -7
- data/spec/services/services/interface_spec.rb +2 -2
- data/spec/transient_store/transient_store/mocks/redis_spec.rb +8 -6
- metadata +30 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dc0db0a009b321df89a2eb2e8a879c76bc875bb9
|
4
|
+
data.tar.gz: 29c85538f05080287181a67d3292b72f950f1872
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8519c31178c7439fc57888851eac50409e71c8225dfc0fd5421da540e370ab01ef92423f3a5753195efea9ca01f4954ee68d33d09fc083470a6ac5eade962f70
|
7
|
+
data.tar.gz: 45d7b58441e42e224624123c74f15f812880a074ea07648628f49741a3a3ba918456632b456a6b617b73d65935884ec16ad30e92176e19cc939af93fcc3437c0
|
@@ -243,7 +243,7 @@ module Hoodoo
|
|
243
243
|
# Rationalise and convert the date time to UTC.
|
244
244
|
|
245
245
|
date_time = Hoodoo::Utilities.rationalise_datetime( date_time ).utc
|
246
|
-
safe_date_time = self.
|
246
|
+
safe_date_time = self.connection.quoted_date( date_time )
|
247
247
|
|
248
248
|
# Create strings that specify the required attributes escaped and
|
249
249
|
# joined by commas for use in a SQL query, for both main and history
|
@@ -269,7 +269,7 @@ module Hoodoo
|
|
269
269
|
SELECT #{ safe_history_name_string },"effective_start","effective_end"
|
270
270
|
FROM #{ dating_table_name }
|
271
271
|
) AS u
|
272
|
-
WHERE "effective_start" <= #{ safe_date_time } AND ("effective_end" > #{ safe_date_time } OR "effective_end" IS NULL)
|
272
|
+
WHERE "effective_start" <= '#{ safe_date_time }' AND ("effective_end" > '#{ safe_date_time }' OR "effective_end" IS NULL)
|
273
273
|
) AS #{ self.table_name }
|
274
274
|
}
|
275
275
|
|
@@ -70,7 +70,8 @@ module Hoodoo
|
|
70
70
|
#
|
71
71
|
mapping = {
|
72
72
|
'created_after' => Hoodoo::ActiveRecord::Finder::SearchHelper.cs_gt( :created_at ),
|
73
|
-
'created_before' => Hoodoo::ActiveRecord::Finder::SearchHelper.cs_lt( :created_at )
|
73
|
+
'created_before' => Hoodoo::ActiveRecord::Finder::SearchHelper.cs_lt( :created_at ),
|
74
|
+
'created_by' => Hoodoo::ActiveRecord::Finder::SearchHelper.cs_match( :created_by )
|
74
75
|
}
|
75
76
|
|
76
77
|
if mapping.keys.length != ( mapping.keys | Hoodoo::Services::Middleware::FRAMEWORK_QUERY_DATA.keys ).length
|
@@ -38,7 +38,7 @@ module Hoodoo
|
|
38
38
|
# # ...
|
39
39
|
# end
|
40
40
|
#
|
41
|
-
# +model+:: The ActiveRecord::Base descendant
|
41
|
+
# +model+:: The ActiveRecord::Base descendant that is including
|
42
42
|
# this module.
|
43
43
|
#
|
44
44
|
def self.included( model )
|
@@ -62,7 +62,7 @@ module Hoodoo
|
|
62
62
|
#
|
63
63
|
# change_column :model_table_name, :id, :string, :limit => 32
|
64
64
|
#
|
65
|
-
# +model+:: The ActiveRecord::Base descendant
|
65
|
+
# +model+:: The ActiveRecord::Base descendant that is including
|
66
66
|
# this module.
|
67
67
|
#
|
68
68
|
def self.instantiate( model )
|
data/lib/hoodoo/generator.rb
CHANGED
@@ -10,6 +10,7 @@
|
|
10
10
|
|
11
11
|
require 'singleton'
|
12
12
|
require 'fileutils'
|
13
|
+
require 'pathname'
|
13
14
|
|
14
15
|
module Hoodoo
|
15
16
|
|
@@ -45,25 +46,33 @@ module Hoodoo
|
|
45
46
|
|
46
47
|
name = args.first
|
47
48
|
|
48
|
-
return show_usage
|
49
|
+
return show_usage if name == '-h' || name == '--help' || name.nil? || name.empty?
|
50
|
+
return show_version if name == '-v' || name == '--version'
|
49
51
|
|
50
52
|
return usage_and_warning( "SERVICE_NAME must match #{ NAME_REGEX.inspect }" ) if naughty_name?( name )
|
51
53
|
return usage_and_warning( "'#{ name }' already exists" ) if File.exist?( "./#{ name }" )
|
52
54
|
|
53
|
-
|
55
|
+
path = args[ 2 ] if args[ 1 ] == '--path'
|
56
|
+
git = args[ 2 ] if args[ 1 ] == '--from'
|
54
57
|
git ||= 'git@github.com:LoyaltyNZ/service_shell.git'
|
55
58
|
|
56
|
-
return create_service( name, git )
|
59
|
+
return create_service( name, git, path )
|
57
60
|
end
|
58
61
|
|
59
62
|
private
|
60
63
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
64
|
+
# Name of new service, mandatory GitHub repo path of the shell to start
|
65
|
+
# with, or override local filesystem path to copy from (pass "nil" to
|
66
|
+
# not do that).
|
67
|
+
#
|
68
|
+
def create_service( name, git, path )
|
69
|
+
ok = create_dir( name )
|
70
|
+
ok = clone_service_shell( name, git ) if ok && path.nil?
|
71
|
+
ok = copy_service_shell( name, path ) if ok && ! path.nil?
|
72
|
+
ok = remove_dot_git( name, git ) if ok
|
73
|
+
ok = replace_strings( name ) if ok
|
74
|
+
|
75
|
+
if ok
|
67
76
|
puts "Success! ./#{name} created."
|
68
77
|
Kernel::exit( KERNEL_EXIT_SUCCESS )
|
69
78
|
else
|
@@ -81,6 +90,14 @@ module Hoodoo
|
|
81
90
|
$?.to_i == 0
|
82
91
|
end
|
83
92
|
|
93
|
+
def copy_service_shell( name, path )
|
94
|
+
source_path = Pathname.new( path ).to_s << '/.'
|
95
|
+
dest_path = File.join( '.', name )
|
96
|
+
|
97
|
+
FileUtils.cp_r( source_path, dest_path, verbose: true )
|
98
|
+
$?.to_i == 0
|
99
|
+
end
|
100
|
+
|
84
101
|
def remove_dot_git( name, git )
|
85
102
|
git_folder = "./#{ name }/.git"
|
86
103
|
git_config = "#{ git_folder }/config"
|
@@ -123,9 +140,32 @@ module Hoodoo
|
|
123
140
|
end
|
124
141
|
|
125
142
|
def show_usage
|
126
|
-
puts
|
127
|
-
puts "
|
128
|
-
puts
|
143
|
+
puts
|
144
|
+
puts "Creates a service shell at the PWD, customised with the given service name."
|
145
|
+
puts
|
146
|
+
puts " hoodoo <service-name> [--from <git-repository> | --path <full-pathname>]"
|
147
|
+
puts
|
148
|
+
puts "For example:"
|
149
|
+
puts
|
150
|
+
puts " hoodoo service_cron"
|
151
|
+
puts " hoodoo service_person --from git@github.com:YOURNAME/service_shell_fork.git"
|
152
|
+
puts " hoodoo service_product --path /path/to/local/service/shell/container"
|
153
|
+
puts
|
154
|
+
puts "See also:"
|
155
|
+
puts
|
156
|
+
puts " hoodoo --help shows this help"
|
157
|
+
puts " hoodoo --version shows the require-able gem version"
|
158
|
+
puts
|
159
|
+
|
160
|
+
Kernel::exit( KERNEL_EXIT_FAILURE )
|
161
|
+
end
|
162
|
+
|
163
|
+
def show_version
|
164
|
+
require 'hoodoo/version'
|
165
|
+
|
166
|
+
puts
|
167
|
+
puts "Accessible Hoodoo gem is #{ Hoodoo::VERSION } (#{ Hoodoo::DATE })"
|
168
|
+
puts
|
129
169
|
|
130
170
|
Kernel::exit( KERNEL_EXIT_FAILURE )
|
131
171
|
end
|
@@ -37,22 +37,27 @@ module Hoodoo
|
|
37
37
|
# the response. It calls the original implementation via +super+.
|
38
38
|
#
|
39
39
|
# +http_message+:: Hash describing the message to send.
|
40
|
-
#
|
41
40
|
# +full_uri+:: URI being sent to. This is somewhat meaningless
|
42
|
-
# when using AMQP but
|
41
|
+
# when using AMQP but useful for analytics data.
|
43
42
|
#
|
44
43
|
def monkey_send_request( http_message, full_uri )
|
45
44
|
amqp_response = nil
|
46
45
|
|
47
46
|
Datadog.tracer.trace( 'alchemy.request' ) do |span|
|
48
|
-
span.service
|
47
|
+
span.service = 'alchemy'
|
49
48
|
span.span_type = 'alchemy'
|
50
|
-
span.resource
|
49
|
+
span.resource = http_message[ 'verb' ]
|
51
50
|
span.set_tag( 'target.path', http_message[ 'path'] )
|
52
51
|
|
53
|
-
# Add Datadog trace IDs to the HTTP message
|
52
|
+
# Add Datadog trace IDs to the HTTP message. For compatibility
|
53
|
+
# with Hoodoo V1 services using a fork of DDTrace, we send both
|
54
|
+
# old headers ("X-DDTrace...") and new ("X-DataDog-...")
|
55
|
+
|
56
|
+
http_message[ 'headers' ][ 'X_DATADOG_TRACE_ID' ] = span.trace_id.to_s
|
57
|
+
http_message[ 'headers' ][ 'X_DATADOG_PARENT_ID' ] = span.span_id.to_s
|
58
|
+
|
54
59
|
http_message[ 'headers' ][ 'X_DDTRACE_PARENT_TRACE_ID' ] = span.trace_id.to_s
|
55
|
-
http_message[ 'headers' ][ 'X_DDTRACE_PARENT_SPAN_ID'
|
60
|
+
http_message[ 'headers' ][ 'X_DDTRACE_PARENT_SPAN_ID' ] = span.span_id.to_s
|
56
61
|
|
57
62
|
amqp_response = super( http_message, full_uri )
|
58
63
|
end
|
@@ -13,7 +13,10 @@
|
|
13
13
|
########################################################################
|
14
14
|
|
15
15
|
begin
|
16
|
+
|
16
17
|
# Raises LoadError if NewRelic is absent
|
18
|
+
#
|
19
|
+
require 'newrelic_rpm'
|
17
20
|
require 'new_relic/agent/method_tracer'
|
18
21
|
|
19
22
|
# Add a method tracer on the dispatch method so that the time spent
|
@@ -29,6 +32,7 @@ begin
|
|
29
32
|
end
|
30
33
|
end
|
31
34
|
end
|
35
|
+
|
32
36
|
rescue LoadError; end
|
33
37
|
|
34
38
|
module Hoodoo
|
@@ -55,18 +59,19 @@ module Hoodoo
|
|
55
59
|
# Add custom attributes to the NewRelic transaction. The original
|
56
60
|
# implementation is called via +super+.
|
57
61
|
#
|
58
|
-
# +interaction+:: Hoodoo::Services::Interaction
|
59
|
-
# inbound request. The
|
60
|
-
# +rack_request+ and +session+
|
61
|
-
# latter being optional). If
|
62
|
-
# +requested_action+ are
|
63
|
-
# _might_ be logged according
|
64
|
-
# in the interface; if these
|
65
|
-
# data is _not_ logged.
|
62
|
+
# +interaction+:: Hoodoo::Services::Middleware::Interaction
|
63
|
+
# instance describing the inbound request. The
|
64
|
+
# +interaction_id+, +rack_request+ and +session+
|
65
|
+
# data is used (the latter being optional). If
|
66
|
+
# +target_interface+ and +requested_action+ are
|
67
|
+
# available, body data _might_ be logged according
|
68
|
+
# to secure log settings in the interface; if these
|
69
|
+
# values are unset, body data is _not_ logged.
|
66
70
|
#
|
67
71
|
def monkey_log_inbound_request( interaction )
|
68
72
|
|
69
73
|
# Add custom attributes to the NewRelic transaction.
|
74
|
+
#
|
70
75
|
::NewRelic::Agent.add_custom_attributes(
|
71
76
|
{
|
72
77
|
:target_action => interaction.requested_action,
|
@@ -75,6 +80,7 @@ module Hoodoo
|
|
75
80
|
)
|
76
81
|
|
77
82
|
# Call the original logging method.
|
83
|
+
#
|
78
84
|
super( interaction )
|
79
85
|
|
80
86
|
end
|
@@ -85,16 +91,17 @@ module Hoodoo
|
|
85
91
|
if defined?( Hoodoo::Services ) &&
|
86
92
|
defined?( Hoodoo::Services::Middleware )
|
87
93
|
|
88
|
-
|
94
|
+
Hoodoo::Monkey.register(
|
89
95
|
target_unit: Hoodoo::Services::Middleware,
|
90
96
|
extension_module: Hoodoo::Monkey::Patch::NewRelicMiddlewareAnalytics
|
91
97
|
)
|
92
98
|
|
93
|
-
|
99
|
+
Hoodoo::Monkey.enable( extension_module: Hoodoo::Monkey::Patch::NewRelicMiddlewareAnalytics )
|
94
100
|
end
|
95
101
|
|
96
102
|
rescue LoadError
|
97
103
|
# No NewRelic => do nothing
|
104
|
+
|
98
105
|
end
|
99
106
|
|
100
107
|
end # module Patch
|
@@ -16,7 +16,11 @@ module Hoodoo
|
|
16
16
|
module Patch
|
17
17
|
|
18
18
|
begin
|
19
|
-
|
19
|
+
|
20
|
+
# Raises LoadError if NewRelic is absent
|
21
|
+
#
|
22
|
+
require 'newrelic_rpm'
|
23
|
+
require 'new_relic/agent/transaction'
|
20
24
|
|
21
25
|
# Wrap Hoodoo::Client::Endpoint::AMQP using NewRelic transaction
|
22
26
|
# tracing so that over-queue inter-resource calls get connected
|
@@ -36,36 +40,47 @@ module Hoodoo
|
|
36
40
|
# This adds headers to the request and extracts header data from
|
37
41
|
# the response. It calls the original implementation via +super+.
|
38
42
|
#
|
39
|
-
# +http_message+:: Hash describing the message to send.
|
43
|
+
# +http_message+:: Hash describing the message to send. See e.g.
|
44
|
+
# Hoodoo::Client::Endpoint::AMQP#do_amqp. Note
|
45
|
+
# that the header names inside this Hash are the
|
46
|
+
# mixed case, HTTP specification style ones like
|
47
|
+
# <tt>X-Interaction-ID</tt> and _not_ the Rack
|
48
|
+
# names like <tt>HTTP_X_INTERACTION_ID</tt>.
|
40
49
|
#
|
41
50
|
# +full_uri+:: URI being sent to. This is somewhat meaningless
|
42
51
|
# when using AMQP but NewRelic requires it.
|
43
52
|
#
|
44
53
|
def monkey_send_request( http_message, full_uri )
|
45
|
-
amqp_response
|
46
|
-
|
54
|
+
amqp_response = nil
|
55
|
+
wrapped_request = AlchemyFluxHTTPRequestWrapper.new(
|
47
56
|
http_message,
|
48
57
|
full_uri
|
49
58
|
)
|
50
59
|
|
51
|
-
::NewRelic::Agent::
|
60
|
+
segment = ::NewRelic::Agent::Transaction.start_external_request_segment(
|
61
|
+
wrapped_request.type,
|
62
|
+
wrapped_request.uri,
|
63
|
+
wrapped_request.method
|
64
|
+
)
|
65
|
+
|
66
|
+
begin
|
67
|
+
segment.add_request_headers( wrapped_request )
|
68
|
+
|
69
|
+
amqp_response = super( http_message, full_uri )
|
52
70
|
|
53
|
-
#
|
54
|
-
#
|
71
|
+
# The outer block extracts required information from the
|
72
|
+
# object returned by this block. Need to wrap it match the
|
73
|
+
# expected interface.
|
55
74
|
#
|
56
|
-
|
75
|
+
wrapped_response = AlchemyFluxHTTPResponseWrapper.new(
|
76
|
+
amqp_response
|
77
|
+
)
|
57
78
|
|
58
|
-
|
79
|
+
segment.read_response_headers( wrapped_response )
|
59
80
|
|
60
|
-
|
61
|
-
|
62
|
-
# expected interface.
|
63
|
-
#
|
64
|
-
::Hoodoo::Monkey::Patch::NewRelicTracedAMQP::AMQPNewRelicResponseWrapper.new(
|
65
|
-
amqp_response
|
66
|
-
)
|
81
|
+
ensure
|
82
|
+
segment.finish()
|
67
83
|
|
68
|
-
end
|
69
84
|
end
|
70
85
|
|
71
86
|
return amqp_response
|
@@ -75,12 +90,18 @@ module Hoodoo
|
|
75
90
|
# Wrapper class for an AMQP request which conforms to the API that
|
76
91
|
# NewRelic expects.
|
77
92
|
#
|
78
|
-
class
|
93
|
+
class AlchemyFluxHTTPRequestWrapper
|
79
94
|
|
80
95
|
# Wrap the Alchemy Flux +http_message+ aimed at the specified
|
81
96
|
# +full_uri+.
|
82
97
|
#
|
83
|
-
# +http_message+:: Hash describing the
|
98
|
+
# +http_message+:: Hash describing the message to send. See e.g.
|
99
|
+
# Hoodoo::Client::Endpoint::AMQP#do_amqp. Note
|
100
|
+
# that the header names inside this Hash are the
|
101
|
+
# mixed case, HTTP specification style ones like
|
102
|
+
# <tt>X-Interaction-ID</tt> and _not_ the Rack
|
103
|
+
# names like <tt>HTTP_X_INTERACTION_ID</tt>.
|
104
|
+
#
|
84
105
|
# +full_uri+:: Full target URI, as a String.
|
85
106
|
#
|
86
107
|
def initialize( http_message, full_uri )
|
@@ -91,13 +112,28 @@ module Hoodoo
|
|
91
112
|
# String describing what kind of request this is.
|
92
113
|
#
|
93
114
|
def type
|
94
|
-
|
115
|
+
'AlchemyFlux'
|
116
|
+
end
|
117
|
+
|
118
|
+
# String descrbing this request's intended host, according to the
|
119
|
+
# +Host+ header. May return +nil+ if none is found.
|
120
|
+
#
|
121
|
+
# See also: #host.
|
122
|
+
#
|
123
|
+
def host_from_header
|
124
|
+
begin
|
125
|
+
@http_message[ 'headers' ][ 'host' ] || @http_message[ 'headers' ][ 'Host' ]
|
126
|
+
rescue
|
127
|
+
nil
|
128
|
+
end
|
95
129
|
end
|
96
130
|
|
97
131
|
# String describing this request's intended host.
|
98
132
|
#
|
133
|
+
# See also: #host_from_header.
|
134
|
+
#
|
99
135
|
def host
|
100
|
-
@http_message[ 'host' ]
|
136
|
+
self.host_from_header() || @http_message[ 'host' ]
|
101
137
|
end
|
102
138
|
|
103
139
|
# String describing this request's HTTP verb (GET, POST and
|
@@ -127,10 +163,10 @@ module Hoodoo
|
|
127
163
|
@http_message[ 'headers' ][ key ] = value
|
128
164
|
end
|
129
165
|
|
130
|
-
#
|
166
|
+
# URI object describing the full request URI.
|
131
167
|
#
|
132
168
|
def uri
|
133
|
-
@full_uri
|
169
|
+
URI.parse( @full_uri.to_s )
|
134
170
|
end
|
135
171
|
|
136
172
|
end
|
@@ -138,29 +174,30 @@ module Hoodoo
|
|
138
174
|
# Wrapper class for an AMQP request which conforms to the API that
|
139
175
|
# NewRelic expects.
|
140
176
|
#
|
141
|
-
class
|
177
|
+
class AlchemyFluxHTTPResponseWrapper
|
142
178
|
|
143
179
|
# The +response_hash+ to be wrapped.
|
144
180
|
#
|
145
181
|
# +response_hash+:: Hash describing the response returned from
|
146
|
-
# Alchemy Flux.
|
182
|
+
# Alchemy Flux. See that gem for details.
|
147
183
|
#
|
148
184
|
def initialize( response_hash )
|
149
185
|
@response_hash = response_hash
|
150
186
|
end
|
151
187
|
|
152
|
-
#
|
153
|
-
#
|
154
|
-
# key like normal.
|
188
|
+
# Look up a key in the headers Hash first, but if absent try the
|
189
|
+
# top-level response Hash instead.
|
155
190
|
#
|
156
191
|
# +key+:: Hash key to look up.
|
157
192
|
#
|
158
193
|
def []( key )
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
194
|
+
@response_hash[ 'headers' ][ key ] || @response_hash[ key ]
|
195
|
+
end
|
196
|
+
|
197
|
+
# Return the HTTP headers for this response as a Hash.
|
198
|
+
#
|
199
|
+
def to_hash
|
200
|
+
@response_hash[ 'headers' ].dup()
|
164
201
|
end
|
165
202
|
end
|
166
203
|
end
|
@@ -185,6 +222,7 @@ module Hoodoo
|
|
185
222
|
|
186
223
|
rescue LoadError
|
187
224
|
# No NewRelic => do nothing
|
225
|
+
|
188
226
|
end
|
189
227
|
|
190
228
|
end # module Patch
|