flipp-ruby-kafka-temp-fork 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/.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
|