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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +97 -0
  3. data/.dockerignore +2 -0
  4. data/.gitignore +41 -0
  5. data/.gitmodules +0 -0
  6. data/.rspec +1 -0
  7. data/.rubocop.yml +56 -0
  8. data/.ruby-gemset +1 -0
  9. data/.ruby-version +1 -0
  10. data/CHANGELOG.md +466 -0
  11. data/Dockerfile +21 -0
  12. data/Gemfile +6 -0
  13. data/Gemfile.lock +207 -0
  14. data/Guardfile +22 -0
  15. data/README.md +102 -0
  16. data/Rakefile +13 -0
  17. data/bin/flipp_ruby_kafka +4 -0
  18. data/deploy/artifactory.sh +8 -0
  19. data/deploy/config.json +4 -0
  20. data/docker-compose.yml +89 -0
  21. data/docs/UPGRADE_1.0.md +39 -0
  22. data/flipp-ruby-kafka.gemspec +34 -0
  23. data/kafkateria/factories/my_schema.rb +16 -0
  24. data/kafkateria/factories/my_schema_with_id.rb +16 -0
  25. data/lib/flipp_ruby_kafka.rb +73 -0
  26. data/lib/flipp_ruby_kafka/flipp_datadog_metrics.rb +15 -0
  27. data/lib/flipp_ruby_kafka/test_helpers.rb +59 -0
  28. data/lib/flipp_ruby_kafka/utils/platform_schema_validation.rb +77 -0
  29. data/lib/flipp_ruby_kafka/utils/platform_topic_validation.rb +41 -0
  30. data/lib/flipp_ruby_kafka/version.rb +5 -0
  31. data/lib/generators/flipp_ruby_kafka/schema_validation/schema_validation_generator.rb +23 -0
  32. data/lib/generators/flipp_ruby_kafka/topic_validation/topic_validation_generator.rb +22 -0
  33. data/spec/flipp_ruby_kafka_spec.rb +8 -0
  34. data/spec/integration/send_kafka_spec.rb +63 -0
  35. data/spec/phobos.yml +73 -0
  36. data/spec/schemas/com/my-namespace/MySchema-key.avsc +13 -0
  37. data/spec/schemas/com/my-namespace/MySchema.avsc +18 -0
  38. data/spec/schemas/com/my-namespace/MySchemaWithDateTimes.avsc +33 -0
  39. data/spec/schemas/com/my-namespace/MySchemaWithId.avsc +28 -0
  40. data/spec/spec_helper.rb +39 -0
  41. data/spec/utils/platform_schema_validation_spec.rb +54 -0
  42. data/spec/utils/platform_topic_validation_spec.rb +50 -0
  43. metadata +262 -0
@@ -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,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FlippRubyKafka
4
+ VERSION = '0.0.1'
5
+ 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
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe FlippRubyKafka do
4
+
5
+ it 'should have a version number' do
6
+ expect(FlippRubyKafka::VERSION).not_to be_nil
7
+ end
8
+ end