flipp-ruby-kafka-temp-fork 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.circleci/config.yml +97 -0
- data/.dockerignore +2 -0
- data/.gitignore +41 -0
- data/.gitmodules +0 -0
- data/.rspec +1 -0
- data/.rubocop.yml +56 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +466 -0
- data/Dockerfile +21 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +207 -0
- data/Guardfile +22 -0
- data/README.md +102 -0
- data/Rakefile +13 -0
- data/bin/flipp_ruby_kafka +4 -0
- data/deploy/artifactory.sh +8 -0
- data/deploy/config.json +4 -0
- data/docker-compose.yml +89 -0
- data/docs/UPGRADE_1.0.md +39 -0
- data/flipp-ruby-kafka.gemspec +34 -0
- data/kafkateria/factories/my_schema.rb +16 -0
- data/kafkateria/factories/my_schema_with_id.rb +16 -0
- data/lib/flipp_ruby_kafka.rb +73 -0
- data/lib/flipp_ruby_kafka/flipp_datadog_metrics.rb +15 -0
- data/lib/flipp_ruby_kafka/test_helpers.rb +59 -0
- data/lib/flipp_ruby_kafka/utils/platform_schema_validation.rb +77 -0
- data/lib/flipp_ruby_kafka/utils/platform_topic_validation.rb +41 -0
- data/lib/flipp_ruby_kafka/version.rb +5 -0
- data/lib/generators/flipp_ruby_kafka/schema_validation/schema_validation_generator.rb +23 -0
- data/lib/generators/flipp_ruby_kafka/topic_validation/topic_validation_generator.rb +22 -0
- data/spec/flipp_ruby_kafka_spec.rb +8 -0
- data/spec/integration/send_kafka_spec.rb +63 -0
- data/spec/phobos.yml +73 -0
- data/spec/schemas/com/my-namespace/MySchema-key.avsc +13 -0
- data/spec/schemas/com/my-namespace/MySchema.avsc +18 -0
- data/spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc +33 -0
- data/spec/schemas/com/my-namespace/MySchemaWithId.avsc +28 -0
- data/spec/spec_helper.rb +39 -0
- data/spec/utils/platform_schema_validation_spec.rb +54 -0
- data/spec/utils/platform_topic_validation_spec.rb +50 -0
- metadata +262 -0
data/docs/UPGRADE_1.0.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Upgrading to v2.0
|
2
|
+
|
3
|
+
The following breaking changes were introduced in version 1.0:
|
4
|
+
|
5
|
+
* Lag reporting is now optional, and controlled by `config.report_lag`. To
|
6
|
+
re-enable it, you must set `config.report_lag` to true. We recommend you
|
7
|
+
only set this to true on production or staging environments and not
|
8
|
+
development or test.
|
9
|
+
* Topics that have no keys now must use `key_config none: true` instead
|
10
|
+
of `key_config plain: true`.
|
11
|
+
* `KafkaPublishFailure` has been removed - any code that relies on it must
|
12
|
+
likewise be removed, and the database table can also be dropped. You can
|
13
|
+
also remove any reference to the `payloads_for_resend` method defined
|
14
|
+
on your producers.
|
15
|
+
* Its replacement is the new `db` [publish backend](../README.md#database-backend).
|
16
|
+
Note that to use this option, you need to have [activerecord-import](https://github.com/zdennis/activerecord-import)
|
17
|
+
in your Gemfile.
|
18
|
+
* `KafkaSource` will now send messages inside a transaction rather than
|
19
|
+
after a commit. Any code (e.g. RSpecs) that relies on the previous
|
20
|
+
behavior must be modified.
|
21
|
+
* `TestHelpers` no longer automatically stub producers and consumers, to aid
|
22
|
+
in the integration testing scenario. Instead, you should add a `before(:each)`
|
23
|
+
hook that calls `stub_producers_and_consumers!` Along with this, the
|
24
|
+
`kafka_integration` metadata key that used to check for this behavior
|
25
|
+
is no longer supported or needed, and can be removed from any tests that
|
26
|
+
use it. This allows for more flexibility and explicitness
|
27
|
+
in how to determine if tests are integration tests.
|
28
|
+
* The `PlatformSchemaValidation` class has moved to the `Utils` module, so
|
29
|
+
it is now `FlippRubyKafka::Utils::PlatformSchemaValidation`.
|
30
|
+
|
31
|
+
Additional changes introduced in v2.0 (which uses Deimos under the hood):
|
32
|
+
|
33
|
+
* Removed the `sync_produce` option as it's now redundant with the
|
34
|
+
`publish_backend` option. `publish_backend` can be set to either
|
35
|
+
`:kafka` or `:kafka_async` to reproduce this option.
|
36
|
+
* Changed the name of `rake phobos:start` to `rake deimos:start`.
|
37
|
+
* Configuration is now mostly handled by flipp-ruby-kafka, including
|
38
|
+
defaults for the MS platform. See README for how configuration should
|
39
|
+
look now.
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('lib', __dir__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'flipp_ruby_kafka/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'flipp-ruby-kafka-temp-fork'
|
9
|
+
spec.version = FlippRubyKafka::VERSION
|
10
|
+
spec.authors = ['Daniel Orner']
|
11
|
+
spec.email = ['daniel.orner@wishabi.com']
|
12
|
+
spec.summary = 'Flipp Kafka libraries for Ruby.'
|
13
|
+
spec.description = 'Write a longer description. Optional.'
|
14
|
+
spec.homepage = ''
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_runtime_dependency('ddtrace', '>= 0.11')
|
22
|
+
spec.add_runtime_dependency('deimos-temp-fork', '>= 0.0.2')
|
23
|
+
spec.add_runtime_dependency('flipp-ruby-dogstatsd', '~> 1.0')
|
24
|
+
spec.add_runtime_dependency('railties', '>= 3')
|
25
|
+
|
26
|
+
spec.add_development_dependency('flipp_ruby_style')
|
27
|
+
spec.add_development_dependency('guard', '~> 2')
|
28
|
+
spec.add_development_dependency('guard-rspec', '~> 4')
|
29
|
+
spec.add_development_dependency('guard-rubocop', '~> 1')
|
30
|
+
spec.add_development_dependency('rspec', '~> 3')
|
31
|
+
spec.add_development_dependency('rspec_junit_formatter', '~>0.3')
|
32
|
+
spec.add_development_dependency('rubocop', '~> 0.58')
|
33
|
+
spec.add_development_dependency('rubocop-rspec', '~> 1.27')
|
34
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
FactoryBot.define do
|
4
|
+
factory :myschema, parent: :base do
|
5
|
+
topic { 'my_consume_topic' }
|
6
|
+
schema { 'MySchema' }
|
7
|
+
namespace { 'com.my-namespace' }
|
8
|
+
key_config { { plain: true } }
|
9
|
+
fields do
|
10
|
+
{
|
11
|
+
test_id: -> { Faker::Name.name },
|
12
|
+
some_int: -> { Faker::Number.number(5) }
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
FactoryBot.define do
|
4
|
+
factory :myschemawithid, parent: :base do
|
5
|
+
topic { 'my_consume_topic_with_id' }
|
6
|
+
schema { 'MySchemaWithId' }
|
7
|
+
namespace { 'com.my-namespace' }
|
8
|
+
key_config { { schema: 'MySchema-key' } }
|
9
|
+
fields do
|
10
|
+
{
|
11
|
+
test_id: -> { Faker::Name.name },
|
12
|
+
some_int: -> { Faker::Number.number(5) }
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'deimos'
|
4
|
+
require 'deimos/tracing/datadog'
|
5
|
+
require 'flipp-ruby-dogstatsd'
|
6
|
+
require 'rails'
|
7
|
+
|
8
|
+
# alias all the Deimos stuff
|
9
|
+
FlippRubyKafka = Deimos
|
10
|
+
|
11
|
+
require 'flipp_ruby_kafka/version'
|
12
|
+
require 'flipp_ruby_kafka/utils/platform_schema_validation'
|
13
|
+
require 'flipp_ruby_kafka/utils/platform_topic_validation'
|
14
|
+
require 'flipp_ruby_kafka/flipp_datadog_metrics'
|
15
|
+
require 'generators/flipp_ruby_kafka/topic_validation/topic_validation_generator'
|
16
|
+
require 'generators/flipp_ruby_kafka/schema_validation/schema_validation_generator'
|
17
|
+
|
18
|
+
# Parent module.
|
19
|
+
module FlippRubyKafka
|
20
|
+
after_configure do
|
21
|
+
formatter = self.config.logger.formatter
|
22
|
+
phobos_formatter = self.config.phobos_logger.formatter.clone
|
23
|
+
kafka_formatter = self.config.kafka.logger.formatter.clone
|
24
|
+
|
25
|
+
if formatter&.respond_to?(:push_global_tags) # FlippRailsLogger
|
26
|
+
self.config.phobos_logger.formatter = phobos_formatter
|
27
|
+
self.config.kafka.logger.formatter = kafka_formatter
|
28
|
+
formatter.push_global_tags('Deimos') unless formatter.current_tags.include?('Deimos')
|
29
|
+
end
|
30
|
+
if phobos_formatter&.respond_to?(:push_global_tags)
|
31
|
+
phobos_formatter.push_global_tags('Phobos') unless phobos_formatter.current_tags.include?('Phobos')
|
32
|
+
end
|
33
|
+
if kafka_formatter&.respond_to?(:push_global_tags)
|
34
|
+
kafka_formatter.push_global_tags('RubyKafka') unless kafka_formatter.current_tags.include?('RubyKafka')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
define_settings do
|
39
|
+
setting :logger, default_proc: proc { Rails.logger.clone }
|
40
|
+
setting :schema do
|
41
|
+
setting :backend, default_proc: proc { Rails.env.development? ? :avro_validation : :avro_schema_registry }
|
42
|
+
setting :path, default_proc: proc { "#{Rails.root}/app/schemas" }
|
43
|
+
setting :registry_url, ENV['KAFKA_SCHEMA_REGISTRY'] || 'http://127.0.0.1:8081'
|
44
|
+
end
|
45
|
+
setting :consumers do
|
46
|
+
setting :report_lag, default_proc: proc { !%w(test development).include?(Rails.env) }
|
47
|
+
setting(:fatal_error, proc { defined?(ActiveRecord) && !ActiveRecord::Base.connection.active? })
|
48
|
+
end
|
49
|
+
setting :kafka do
|
50
|
+
setting :seed_brokers, ENV['KAFKA_SSL_BROKERS'] || '127.0.0.1:9092'
|
51
|
+
setting :ssl do
|
52
|
+
setting :enabled, default_proc: proc { !%w(test development).include?(Rails.env) }
|
53
|
+
setting :ca_cert, '/var/certs/kafka-broker-ca-public-cert'
|
54
|
+
setting :client_cert, '/var/certs/kafka-client-public-key'
|
55
|
+
setting :client_cert_key, '/var/certs/kafka-client-private-key-decrypted'
|
56
|
+
setting :verify_hostname, false
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Base URL for Kafkateria - typically something like localhost:3000
|
61
|
+
# for local testing or kafkateria:3000 for docker-compose.
|
62
|
+
setting :kafkateria_url, 'http://127.0.0.1:3000'
|
63
|
+
end
|
64
|
+
|
65
|
+
class << self
|
66
|
+
# Configure datadog. Must be called after FlippDatadog is configured.
|
67
|
+
def configure_datadog
|
68
|
+
service_name = "#{FlippDatadog.config&.service || 'frk'}-consumer"
|
69
|
+
self.config.metrics = FlippRubyKafka::FlippDatadogMetrics.new(nil, self.config.logger)
|
70
|
+
self.config.tracer = Deimos::Tracing::Datadog.new(service_name: service_name)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'flipp-ruby-dogstatsd'
|
4
|
+
require 'deimos/metrics/datadog'
|
5
|
+
|
6
|
+
module FlippRubyKafka
|
7
|
+
# Datadog metrics provider that uses the FlippDatadog gem.
|
8
|
+
# Configuration must happen before FlippRubyKafka is configured.
|
9
|
+
class FlippDatadogMetrics < Deimos::Metrics::Datadog
|
10
|
+
# :nodoc:
|
11
|
+
def initialize(_config, _logger)
|
12
|
+
@client = FlippDatadog.client
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'deimos/test_helpers'
|
4
|
+
FlippRubyKafka = Deimos # in case this is being included directly
|
5
|
+
|
6
|
+
module FlippRubyKafka
|
7
|
+
# :nodoc:
|
8
|
+
module TestHelpers
|
9
|
+
# Use Kafkateria to clear a topic.
|
10
|
+
# @param topic [String]
|
11
|
+
def kafkateria_delete_topic(topic)
|
12
|
+
base = FlippRubyKafka.config.kafkateria_url
|
13
|
+
uri = URI("#{base}/v1/topics/delete_topic?topic=#{topic}")
|
14
|
+
request = Net::HTTP::Post.new(uri)
|
15
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
16
|
+
http.request(request)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Use Kafkateria to generate and produce messages.
|
20
|
+
# @param topic [String]
|
21
|
+
# @param num_messages [Integer]
|
22
|
+
# @param traits [Array<Symbol>]
|
23
|
+
# @param values [Hash]
|
24
|
+
def kafkateria_produce_messages(topic:, num_messages: 1, traits: [], trait_params: {}, values: {}, null_payload: false, key: nil)
|
25
|
+
base = FlippRubyKafka.config.kafkateria_url
|
26
|
+
uri = URI("#{base}//v1/messages/generate_and_publish")
|
27
|
+
req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
|
28
|
+
req.body = { topic: topic, values: values,
|
29
|
+
traits: traits, trait_params: trait_params, num_messages: num_messages, null_payload: null_payload, key: key }.to_json
|
30
|
+
response = Net::HTTP.start(uri.hostname, uri.port) do |http|
|
31
|
+
http.request(req)
|
32
|
+
end
|
33
|
+
if response.code.to_s != '200'
|
34
|
+
raise "Failed #{response.code} producing messages to #{topic}: #{response.body}"
|
35
|
+
end
|
36
|
+
|
37
|
+
JSON.parse(response.body || [])
|
38
|
+
end
|
39
|
+
|
40
|
+
# @param topic [String]
|
41
|
+
# @param num_messages [Integer]
|
42
|
+
# @return [Array<Hash>] with :key and :payload keys
|
43
|
+
def kafkateria_get_messages(topic:, num_messages: 10)
|
44
|
+
base = FlippRubyKafka.config.kafkateria_url
|
45
|
+
uri = URI("#{base}//v1/messages?topic=#{topic}&num_messages=#{num_messages}")
|
46
|
+
res = Net::HTTP.get_response(uri)
|
47
|
+
if res.code.to_s != '200'
|
48
|
+
raise "Failed #{res.code} getting messages from #{topic}: #{res.body}"
|
49
|
+
end
|
50
|
+
|
51
|
+
response = JSON.parse(res.body)
|
52
|
+
if response['payloads'].present?
|
53
|
+
response['payloads'].map(&:with_indifferent_access)
|
54
|
+
else
|
55
|
+
response
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module FlippRubyKafka
|
6
|
+
module Utils
|
7
|
+
# Generates the Microservice Platform schema validation file.
|
8
|
+
# Run this before committing schema changes (or include it in your CircleCI
|
9
|
+
# config if you don't mind having to build the same image multiple times).
|
10
|
+
# Run this using `rails runner` or in Rails console if you're using Rails.
|
11
|
+
class PlatformSchemaValidation
|
12
|
+
# @param base_path [String] Set this to Rails.root if running Rails.
|
13
|
+
def initialize(base_path: '')
|
14
|
+
@base_path ||= FlippRubyKafka.config.schema.path.gsub(%r{^#{base_path}\/}, '')
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param klass [Class < FlippRubyKafka::Producer]
|
18
|
+
# @return [Hash]
|
19
|
+
def process_producer(klass)
|
20
|
+
schema = klass.config[:schema]
|
21
|
+
topic = klass.config[:topic]
|
22
|
+
return if topic.blank?
|
23
|
+
|
24
|
+
namespace = klass.config[:namespace] || FlippRubyKafka.config.producers.schema_namespace
|
25
|
+
path = namespace.tr('.', '/')
|
26
|
+
{
|
27
|
+
'file' => File.join(@base_path, path, "#{schema}.avsc"),
|
28
|
+
'subject' => "#{topic}-value"
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param hash [Hash]
|
33
|
+
# @return [Hash]
|
34
|
+
def process_consumer(hash)
|
35
|
+
klass = hash['handler'].constantize
|
36
|
+
topic = hash['topic']
|
37
|
+
schema = klass.config[:schema]
|
38
|
+
return if schema.blank?
|
39
|
+
|
40
|
+
namespace = klass.config[:namespace] || ''
|
41
|
+
path = namespace.tr('.', '/')
|
42
|
+
{
|
43
|
+
'file' => File.join(@base_path, path, "#{schema}.avsc"),
|
44
|
+
'subject' => "#{topic}-value"
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [String]
|
49
|
+
def generate_config
|
50
|
+
@full_config = []
|
51
|
+
FlippRubyKafka::Producer.descendants.each do |klass|
|
52
|
+
next if klass.topic.blank?
|
53
|
+
|
54
|
+
config = process_producer(klass)
|
55
|
+
@full_config << config if config
|
56
|
+
end
|
57
|
+
|
58
|
+
Phobos.config['listeners'].each do |h|
|
59
|
+
config = process_consumer(h)
|
60
|
+
@full_config << config if config
|
61
|
+
end
|
62
|
+
|
63
|
+
{
|
64
|
+
environments: {
|
65
|
+
default: @full_config
|
66
|
+
}
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
# :nodoc:
|
71
|
+
def run
|
72
|
+
full_json = generate_config
|
73
|
+
File.write('schema-validation.json', JSON.pretty_generate(full_json))
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module FlippRubyKafka
|
6
|
+
module Utils
|
7
|
+
# Generates the Microservice Platform topic validation file.
|
8
|
+
# Use rake flipp_ruby_kafka:topic_validation my_service to run it from command line.
|
9
|
+
class PlatformTopicValidation
|
10
|
+
class << self
|
11
|
+
# @param service_name [String]
|
12
|
+
def save_config_to_file(service_name)
|
13
|
+
config = generate_config(service_name)
|
14
|
+
File.open("#{Rails.root}/topic-validation.json", 'w') do |f|
|
15
|
+
f.write(config.to_json)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @param service_name [String]
|
20
|
+
# @return [Hash]
|
21
|
+
def generate_config(service_name)
|
22
|
+
acls = []
|
23
|
+
Deimos.config.producer_objects.each do |k|
|
24
|
+
next if k.topic.blank?
|
25
|
+
|
26
|
+
acls.push(topic: k.topic, role: 'producer')
|
27
|
+
end
|
28
|
+
Deimos.config.consumer_objects.each do |k|
|
29
|
+
next if k.topic.blank?
|
30
|
+
|
31
|
+
acls.push(topic: k.topic, role: 'consumer')
|
32
|
+
end
|
33
|
+
{
|
34
|
+
service: service_name,
|
35
|
+
acls: acls
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
require 'flipp_ruby_kafka/utils/platform_schema_validation'
|
5
|
+
|
6
|
+
module FlippRubyKafka
|
7
|
+
module Generators
|
8
|
+
# Generate the database backend migration.
|
9
|
+
class SchemaValidationGenerator < Rails::Generators::Base
|
10
|
+
desc 'Generate schema validation config file'
|
11
|
+
|
12
|
+
# :nodoc:
|
13
|
+
def self.namespace
|
14
|
+
'flipp_ruby_kafka:schema_validation'
|
15
|
+
end
|
16
|
+
|
17
|
+
# Main method to create all the necessary files
|
18
|
+
def generate
|
19
|
+
FlippRubyKafka::Utils::PlatformSchemaValidation.new(base_path: Rails.root).run
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'rails/generators'
|
4
|
+
|
5
|
+
module FlippRubyKafka
|
6
|
+
module Generators
|
7
|
+
# Generate the database backend migration.
|
8
|
+
class TopicValidationGenerator < Rails::Generators::NamedBase
|
9
|
+
desc 'Generate topic validation config file'
|
10
|
+
|
11
|
+
# :nodoc:
|
12
|
+
def self.namespace
|
13
|
+
'flipp_ruby_kafka:topic_validation'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Main method to create all the necessary files
|
17
|
+
def generate
|
18
|
+
FlippRubyKafka::Utils::PlatformTopicValidation.save_config_to_file(name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|