sbmt-outbox 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +440 -0
  3. data/Rakefile +3 -0
  4. data/app/interactors/sbmt/outbox/base_create_item.rb +55 -0
  5. data/app/interactors/sbmt/outbox/create_inbox_item.rb +10 -0
  6. data/app/interactors/sbmt/outbox/create_outbox_item.rb +10 -0
  7. data/app/interactors/sbmt/outbox/dry_interactor.rb +16 -0
  8. data/app/interactors/sbmt/outbox/partition_strategies/hash_partitioning.rb +20 -0
  9. data/app/interactors/sbmt/outbox/partition_strategies/number_partitioning.rb +26 -0
  10. data/app/interactors/sbmt/outbox/process_item.rb +269 -0
  11. data/app/interactors/sbmt/outbox/retry_strategies/compacted_log.rb +41 -0
  12. data/app/interactors/sbmt/outbox/retry_strategies/exponential_backoff.rb +34 -0
  13. data/app/jobs/sbmt/outbox/base_delete_stale_items_job.rb +78 -0
  14. data/app/jobs/sbmt/outbox/delete_stale_inbox_items_job.rb +15 -0
  15. data/app/jobs/sbmt/outbox/delete_stale_outbox_items_job.rb +15 -0
  16. data/app/models/sbmt/outbox/base_item.rb +165 -0
  17. data/app/models/sbmt/outbox/base_item_config.rb +106 -0
  18. data/app/models/sbmt/outbox/inbox_item.rb +38 -0
  19. data/app/models/sbmt/outbox/inbox_item_config.rb +13 -0
  20. data/app/models/sbmt/outbox/outbox_item.rb +52 -0
  21. data/app/models/sbmt/outbox/outbox_item_config.rb +13 -0
  22. data/config/initializers/schked.rb +9 -0
  23. data/config/initializers/yabeda.rb +71 -0
  24. data/config/schedule.rb +9 -0
  25. data/exe/outbox +16 -0
  26. data/lib/generators/helpers/config.rb +46 -0
  27. data/lib/generators/helpers/initializer.rb +41 -0
  28. data/lib/generators/helpers/items.rb +17 -0
  29. data/lib/generators/helpers/migration.rb +73 -0
  30. data/lib/generators/helpers/paas.rb +17 -0
  31. data/lib/generators/helpers/values.rb +49 -0
  32. data/lib/generators/helpers.rb +8 -0
  33. data/lib/generators/outbox/install/USAGE +10 -0
  34. data/lib/generators/outbox/install/install_generator.rb +33 -0
  35. data/lib/generators/outbox/install/templates/Outboxfile +3 -0
  36. data/lib/generators/outbox/install/templates/outbox.rb +32 -0
  37. data/lib/generators/outbox/install/templates/outbox.yml +51 -0
  38. data/lib/generators/outbox/item/USAGE +12 -0
  39. data/lib/generators/outbox/item/item_generator.rb +94 -0
  40. data/lib/generators/outbox/item/templates/inbox_item.rb.tt +7 -0
  41. data/lib/generators/outbox/item/templates/outbox_item.rb.tt +16 -0
  42. data/lib/generators/outbox/transport/USAGE +19 -0
  43. data/lib/generators/outbox/transport/templates/inbox_transport.yml.erb +9 -0
  44. data/lib/generators/outbox/transport/templates/outbox_transport.yml.erb +10 -0
  45. data/lib/generators/outbox/transport/transport_generator.rb +60 -0
  46. data/lib/generators/outbox.rb +23 -0
  47. data/lib/sbmt/outbox/ascii_art.rb +62 -0
  48. data/lib/sbmt/outbox/cli.rb +100 -0
  49. data/lib/sbmt/outbox/database_switcher.rb +15 -0
  50. data/lib/sbmt/outbox/engine.rb +45 -0
  51. data/lib/sbmt/outbox/error_tracker.rb +26 -0
  52. data/lib/sbmt/outbox/errors.rb +14 -0
  53. data/lib/sbmt/outbox/instrumentation/open_telemetry_loader.rb +34 -0
  54. data/lib/sbmt/outbox/logger.rb +35 -0
  55. data/lib/sbmt/outbox/middleware/builder.rb +23 -0
  56. data/lib/sbmt/outbox/middleware/open_telemetry/tracing_create_item_middleware.rb +42 -0
  57. data/lib/sbmt/outbox/middleware/open_telemetry/tracing_item_process_middleware.rb +49 -0
  58. data/lib/sbmt/outbox/middleware/runner.rb +29 -0
  59. data/lib/sbmt/outbox/middleware/sentry/tracing_batch_process_middleware.rb +48 -0
  60. data/lib/sbmt/outbox/middleware/sentry/tracing_item_process_middleware.rb +65 -0
  61. data/lib/sbmt/outbox/middleware/sentry/transaction.rb +28 -0
  62. data/lib/sbmt/outbox/probes/probe.rb +38 -0
  63. data/lib/sbmt/outbox/redis_client_factory.rb +36 -0
  64. data/lib/sbmt/outbox/tasks/delete_failed_items.rake +17 -0
  65. data/lib/sbmt/outbox/tasks/retry_failed_items.rake +20 -0
  66. data/lib/sbmt/outbox/thread_pool.rb +108 -0
  67. data/lib/sbmt/outbox/throttler.rb +52 -0
  68. data/lib/sbmt/outbox/version.rb +7 -0
  69. data/lib/sbmt/outbox/worker.rb +233 -0
  70. data/lib/sbmt/outbox.rb +136 -0
  71. data/lib/sbmt-outbox.rb +3 -0
  72. metadata +594 -0
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sbmt
4
+ module Outbox
5
+ class BaseItemConfig
6
+ DEFAULT_BUCKET_SIZE = 16
7
+ DEFAULT_PARTITION_STRATEGY = :number
8
+
9
+ def initialize(box_name)
10
+ self.box_name = box_name
11
+
12
+ validate!
13
+ end
14
+
15
+ def owner
16
+ return @owner if defined? @owner
17
+
18
+ @owner = options[:owner].presence || Outbox.yaml_config[:owner].presence
19
+ end
20
+
21
+ def bucket_size
22
+ @bucket_size ||= (options[:bucket_size] || Outbox.yaml_config.fetch(:bucket_size, DEFAULT_BUCKET_SIZE)).to_i
23
+ end
24
+
25
+ def partition_size
26
+ @partition_size ||= (options[:partition_size] || 1).to_i
27
+ end
28
+
29
+ def retention
30
+ @retention ||= ActiveSupport::Duration.parse(options[:retention] || "P1W")
31
+ end
32
+
33
+ def max_retries
34
+ @max_retries ||= (options[:max_retries] || 0).to_i
35
+ end
36
+
37
+ def minimal_retry_interval
38
+ @minimal_retry_interval ||= (options[:minimal_retry_interval] || 10).to_i
39
+ end
40
+
41
+ def maximal_retry_interval
42
+ @maximal_retry_interval ||= (options[:maximal_retry_interval] || 600).to_i
43
+ end
44
+
45
+ def multiplier_retry_interval
46
+ @multiplier_retry_interval ||= (options[:multiplier_retry_interval] || 2).to_i
47
+ end
48
+
49
+ def retry_strategies
50
+ @retry_strategies ||= Array.wrap(options[:retry_strategies]).map do |str_name|
51
+ "Sbmt::Outbox::RetryStrategies::#{str_name.camelize}".constantize
52
+ end
53
+ end
54
+
55
+ def partition_strategy
56
+ return @partition_strategy if defined?(@partition_strategy)
57
+
58
+ str_name = options.fetch(:partition_strategy, DEFAULT_PARTITION_STRATEGY)
59
+ @partition_strategy = "Sbmt::Outbox::PartitionStrategies::#{str_name.camelize}Partitioning".constantize
60
+ end
61
+
62
+ def transports
63
+ return @transports if defined?(@transports)
64
+
65
+ values = options.fetch(:transports, [])
66
+
67
+ if values.is_a?(Hash)
68
+ values = values.each_with_object([]) do |(key, params), memo|
69
+ memo << params.merge!(class: key)
70
+ end
71
+ end
72
+
73
+ @transports = values.each_with_object({}) do |params, memo|
74
+ params = params.symbolize_keys
75
+ event_name = params.delete(:event_name) || :_all_
76
+ memo[event_name] ||= []
77
+ namespace = params.delete(:class)&.camelize
78
+ raise ArgumentError, "Transport name cannot be blank" if namespace.blank?
79
+
80
+ factory = "#{namespace}::OutboxTransportFactory".safe_constantize
81
+ memo[event_name] << if factory
82
+ factory.build(**params.symbolize_keys)
83
+ else
84
+ namespace.constantize.new(**params.symbolize_keys)
85
+ end
86
+ end
87
+ end
88
+
89
+ private
90
+
91
+ attr_accessor :box_name
92
+
93
+ def options
94
+ @options ||= lookup_config || {}
95
+ end
96
+
97
+ def lookup_config
98
+ raise NotImplementedError
99
+ end
100
+
101
+ def validate!
102
+ raise ConfigError, "Bucket size should be greater or equal to partition size" if partition_size > bucket_size
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sbmt
4
+ module Outbox
5
+ class InboxItem < BaseItem
6
+ self.abstract_class = true
7
+
8
+ class << self
9
+ alias_method :inbox_name, :box_name
10
+
11
+ def box_type
12
+ :inbox
13
+ end
14
+
15
+ def lookup_config
16
+ Sbmt::Outbox::InboxItemConfig
17
+ end
18
+ end
19
+
20
+ delegate :inbox_name, :config, to: "self.class"
21
+
22
+ private
23
+
24
+ def default_options
25
+ {}
26
+ end
27
+
28
+ def default_log_details
29
+ {
30
+ uuid: uuid,
31
+ status: status,
32
+ created_at: created_at.to_datetime.rfc3339(6),
33
+ errors_count: errors_count
34
+ }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sbmt
4
+ module Outbox
5
+ class InboxItemConfig < BaseItemConfig
6
+ private
7
+
8
+ def lookup_config
9
+ Outbox.yaml_config.dig(:inbox_items, box_name)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sbmt
4
+ module Outbox
5
+ class OutboxItem < BaseItem
6
+ self.abstract_class = true
7
+
8
+ IDEMPOTENCY_HEADER_NAME = "Idempotency-Key"
9
+ SEQUENCE_HEADER_NAME = "Sequence-ID"
10
+ EVENT_TIME_HEADER_NAME = "Created-At"
11
+ OUTBOX_HEADER_NAME = "Outbox-Name"
12
+ DISPATCH_TIME_HEADER_NAME = "Dispatched-At"
13
+
14
+ class << self
15
+ alias_method :outbox_name, :box_name
16
+
17
+ def box_type
18
+ :outbox
19
+ end
20
+
21
+ def lookup_config
22
+ Sbmt::Outbox::OutboxItemConfig
23
+ end
24
+ end
25
+
26
+ delegate :outbox_name, :config, to: "self.class"
27
+
28
+ private
29
+
30
+ def default_options
31
+ {
32
+ headers: {
33
+ OUTBOX_HEADER_NAME => outbox_name,
34
+ IDEMPOTENCY_HEADER_NAME => uuid,
35
+ SEQUENCE_HEADER_NAME => id.to_s,
36
+ EVENT_TIME_HEADER_NAME => created_at&.to_datetime&.rfc3339(6),
37
+ DISPATCH_TIME_HEADER_NAME => Time.current.to_datetime.rfc3339(6)
38
+ }
39
+ }
40
+ end
41
+
42
+ def default_log_details
43
+ {
44
+ uuid: uuid,
45
+ status: status,
46
+ created_at: created_at.to_datetime.rfc3339(6),
47
+ errors_count: errors_count
48
+ }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Sbmt
4
+ module Outbox
5
+ class OutboxItemConfig < BaseItemConfig
6
+ private
7
+
8
+ def lookup_config
9
+ Outbox.yaml_config.dig(:outbox_items, box_name) || Outbox.yaml_config.dig(:items, box_name)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "schked"
5
+
6
+ Schked.config.paths << Sbmt::Outbox::Engine.root.join("config", "schedule.rb")
7
+ rescue LoadError
8
+ # optional dependency
9
+ end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ Yabeda.configure do
4
+ # error_counter retry_counter sent_counter fetch_error_counter discarded_counter
5
+ group :outbox do
6
+ counter :created_counter,
7
+ tags: %i[type name partition owner],
8
+ comment: "The total number of created messages"
9
+
10
+ counter :sent_counter,
11
+ tags: %i[type name partition owner],
12
+ comment: "The total number of processed messages"
13
+
14
+ counter :error_counter,
15
+ tags: %i[type name partition owner],
16
+ comment: "Errors (excepting retries) that occurred while processing messages"
17
+
18
+ counter :retry_counter,
19
+ tags: %i[type name partition owner],
20
+ comment: "Retries that occurred while processing messages"
21
+
22
+ counter :discarded_counter,
23
+ tags: %i[type name partition owner],
24
+ comment: "The total number of discarded messages"
25
+
26
+ counter :fetch_error_counter,
27
+ tags: %i[type name partition owner],
28
+ comment: "Errors that occurred while fetching messages"
29
+
30
+ gauge :last_stored_event_id,
31
+ tags: %i[type name partition owner],
32
+ comment: "The ID of the last stored event"
33
+
34
+ gauge :last_sent_event_id,
35
+ tags: %i[type name partition owner],
36
+ comment: "The ID of the last sent event. " \
37
+ "If the message order is not preserved, the value may be inaccurate"
38
+
39
+ histogram :process_latency,
40
+ tags: %i[type name partition owner],
41
+ unit: :seconds,
42
+ buckets: [1, 2.5, 5, 10, 15, 30, 45, 60, 90, 120, 180, 240, 300, 600, 1200].freeze,
43
+ comment: "A histogram outbox process latency"
44
+ end
45
+
46
+ group :box_worker do
47
+ counter :job_counter,
48
+ tags: %i[type name partition worker_number state],
49
+ comment: "The total number of processed jobs"
50
+
51
+ counter :job_timeout_counter,
52
+ tags: %i[type name partition_key worker_number],
53
+ comment: "Requeue of a job that occurred while processing the batch"
54
+
55
+ counter :job_items_counter,
56
+ tags: %i[type name partition worker_number],
57
+ comment: "The total number of processed items in jobs"
58
+
59
+ histogram :job_execution_runtime,
60
+ comment: "A histogram of the job execution time",
61
+ unit: :seconds,
62
+ tags: %i[type name partition worker_number],
63
+ buckets: [0.5, 1, 2.5, 5, 10, 15, 30, 45, 60, 90, 120, 180, 240, 300, 600]
64
+
65
+ histogram :item_execution_runtime,
66
+ comment: "A histogram of the item execution time",
67
+ unit: :seconds,
68
+ tags: %i[type name partition worker_number],
69
+ buckets: [0.5, 1, 2.5, 5, 10, 15, 20, 30, 45, 60, 90, 120, 180, 240, 300]
70
+ end
71
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ every "10m", as: "Sbmt::Outbox::DeleteStaleOutboxItemsJob", overlap: false, timeout: "60s" do
4
+ Sbmt::Outbox::DeleteStaleOutboxItemsJob.enqueue
5
+ end
6
+
7
+ every "10m", as: "Sbmt::Outbox::DeleteStaleInboxItemsJob", overlap: false, timeout: "60s" do
8
+ Sbmt::Outbox::DeleteStaleInboxItemsJob.enqueue
9
+ end
data/exe/outbox ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/local/bin/ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "sbmt/outbox/cli"
6
+
7
+ # rubocop:disable Lint/RescueException
8
+ begin
9
+ Sbmt::Outbox::CLI.start(ARGV)
10
+ rescue Exception => e
11
+ warn "Outbox exited with error"
12
+ warn(e.message) if e.respond_to?(:message)
13
+ warn(e.backtrace.join("\n")) if e.respond_to?(:backtrace) && e.backtrace.respond_to?(:join)
14
+ exit 1
15
+ end
16
+ # rubocop:enable Lint/RescueException
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outbox
4
+ module Generators
5
+ module Helpers
6
+ module Config
7
+ CONFIG_PATH = "config/outbox.yml"
8
+
9
+ private
10
+
11
+ def config_exists?
12
+ File.exist?(CONFIG_PATH)
13
+ end
14
+
15
+ def check_config!
16
+ return if config_exists?
17
+
18
+ if yes?("Seems like `config/outbox.yml` doesn't exist. Would you like to generate it?")
19
+ generate "outbox:install"
20
+ else
21
+ raise Rails::Generators::Error, "Something went wrong: `config/outbox.yml` is missing. " \
22
+ "Please generate one by running `bin/rails g outbox:install` " \
23
+ "or add it manually."
24
+ end
25
+ end
26
+
27
+ def add_item_to_config(config_block_name, item_template_data)
28
+ template_data_with_parent = <<~RUBY
29
+ #{config_block_name}:
30
+ #{optimize_indentation(item_template_data, 2)}
31
+ RUBY
32
+
33
+ data, after = if File.binread(CONFIG_PATH).match?(/^\s*#{config_block_name}:/)
34
+ # if config already contains non-empty/non-commented-out inbox_items/outbox_items block
35
+ [optimize_indentation(item_template_data, 4), /^\s*#{config_block_name}:\s*\n/]
36
+ else
37
+ # there is no config for our items
38
+ # so we just set it up initially
39
+ [optimize_indentation(template_data_with_parent, 2), /^default:.+?\n/]
40
+ end
41
+ inject_into_file CONFIG_PATH, data, after: after
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outbox
4
+ module Generators
5
+ module Helpers
6
+ module Initializer
7
+ OUTBOX_INITIALIZER_PATH = "config/initializers/outbox.rb"
8
+
9
+ private
10
+
11
+ def add_item_to_initializer(attr_name)
12
+ template_data_with_push = <<~RUBY
13
+ "#{namespaced_item_class_name}",
14
+ RUBY
15
+
16
+ template_data_with_append = <<~RUBY
17
+ #{attr_name} << "#{namespaced_item_class_name}"
18
+ RUBY
19
+
20
+ initial_template_data = <<~RUBY
21
+ #{attr_name}.push(
22
+ "#{namespaced_item_class_name}"
23
+ )
24
+
25
+ RUBY
26
+
27
+ content = File.binread(OUTBOX_INITIALIZER_PATH)
28
+ data, after = if content.match?(/^\s*#{attr_name}\.push/)
29
+ [optimize_indentation(template_data_with_push, 4), /^\s*#{attr_name}\.push\(\n/]
30
+ elsif content.match?(/^\s*#{attr_name}\s+<</)
31
+ [optimize_indentation(template_data_with_append, 2), /^\s*#{attr_name}\s+<< ".+?\n/]
32
+ else
33
+ # there is no config for items, so set it up initially
34
+ [optimize_indentation(initial_template_data, 2), /^Rails.application.config.outbox.tap do.+?\n/]
35
+ end
36
+ inject_into_file OUTBOX_INITIALIZER_PATH, data, after: after
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outbox
4
+ module Generators
5
+ module Helpers
6
+ module Items
7
+ def namespaced_item_class_name
8
+ file_path.camelize
9
+ end
10
+
11
+ def item_path
12
+ file_path
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outbox
4
+ module Generators
5
+ module Helpers
6
+ module Migration
7
+ private
8
+
9
+ def create_migration_file(migration_class_name, migration_table_name)
10
+ return false if find_existing_migration(migration_class_name.tableize)
11
+
12
+ result = generate "rails:migration", migration_class_name, "--no-timestamps"
13
+ return unless result
14
+
15
+ migration_filepath = find_existing_migration(migration_class_name.tableize)
16
+ return unless migration_filepath
17
+
18
+ patch_migration_with_template_data(migration_filepath, migration_table_name)
19
+ end
20
+
21
+ def find_existing_migration(name)
22
+ base_path = "db/migrate"
23
+ found_files = Dir.glob("*_#{name}.rb", base: base_path)
24
+ return if found_files.size != 1
25
+
26
+ "#{base_path}/#{found_files[0]}"
27
+ end
28
+
29
+ def patch_migration_with_template_data(migration_filepath, table_name)
30
+ data_to_replace = /^\s*create_table :#{table_name}.+?end\n/m
31
+
32
+ template_data = <<~RUBY
33
+ create_table :#{table_name} do |t|
34
+ t.uuid :uuid, null: false
35
+ t.string :event_key, null: false
36
+ t.integer :bucket, null: false
37
+ t.integer :status, null: false, default: 0
38
+ t.jsonb :options
39
+ t.binary :payload, null: false # when using mysql the column type should be mediumblob
40
+ t.integer :errors_count, null: false, default: 0
41
+ t.text :error_log
42
+ t.timestamp :processed_at
43
+ t.timestamps null: false
44
+ end
45
+
46
+ add_index :#{table_name}, :uuid, unique: true
47
+ add_index :#{table_name}, [:status, :bucket]
48
+ add_index :#{table_name}, :event_key
49
+ add_index :#{table_name}, :created_at
50
+ RUBY
51
+
52
+ gsub_file(migration_filepath, data_to_replace, optimize_indentation(template_data, 4))
53
+ end
54
+
55
+ def create_inbox_model_file(path)
56
+ template "inbox_item.rb", File.join("app/models", "#{path}.rb")
57
+ end
58
+
59
+ def create_outbox_model_file(path)
60
+ template "outbox_item.rb", File.join("app/models", "#{path}.rb")
61
+ end
62
+
63
+ def migration_class_name
64
+ "Create" + namespaced_item_class_name.gsub("::", "").pluralize
65
+ end
66
+
67
+ def migration_table_name
68
+ namespaced_item_class_name.tableize.tr("/", "_")
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outbox
4
+ module Generators
5
+ module Helpers
6
+ module Paas
7
+ APP_MANIFEST_PATH = "configs/app.toml"
8
+
9
+ private
10
+
11
+ def paas_app?
12
+ File.exist?(APP_MANIFEST_PATH)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Outbox
4
+ module Generators
5
+ module Helpers
6
+ module Values
7
+ VALUES_PATH = "configs/values.yaml"
8
+
9
+ private
10
+
11
+ def add_item_to_values(deployment_name, item_path)
12
+ template_data = <<~RUBY
13
+ #{deployment_name}:
14
+ replicas:
15
+ _default: 1
16
+ prod: 2
17
+ command:
18
+ - /bin/sh
19
+ - -c
20
+ - exec bundle exec outbox start --box #{item_path} --concurrency 4
21
+ readinessProbe:
22
+ httpGet:
23
+ path: /readiness/outbox
24
+ port: SET-UP-YOUR-HEALTHCHECK-PORT-HERE
25
+ livenessProbe:
26
+ httpGet:
27
+ path: /liveness/outbox
28
+ port: SET-UP-YOUR-HEALTHCHECK-PORT-HERE
29
+ resources:
30
+ prod:
31
+ requests:
32
+ cpu: "500m"
33
+ memory: "512Mi"
34
+ limits:
35
+ cpu: "1"
36
+ memory: "1Gi"
37
+
38
+ RUBY
39
+
40
+ inject_into_file VALUES_PATH, optimize_indentation(template_data, 2), after: /^deployments:\s*\n/
41
+ end
42
+
43
+ def dasherize_item(item_path)
44
+ item_path.tr("/", "-").dasherize
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "helpers/config"
4
+ require_relative "helpers/initializer"
5
+ require_relative "helpers/items"
6
+ require_relative "helpers/migration"
7
+ require_relative "helpers/paas"
8
+ require_relative "helpers/values"
@@ -0,0 +1,10 @@
1
+ Description:
2
+ Generates initial environment for Outbox
3
+
4
+ Example:
5
+ bin/rails generate install
6
+
7
+ This will create:
8
+ Outboxfile
9
+ config/initializers/outbox.rb
10
+ config/outbox.yml
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "generators/outbox"
4
+
5
+ module Outbox
6
+ module Generators
7
+ class InstallGenerator < Base
8
+ source_root File.expand_path("templates", __dir__)
9
+
10
+ class_option :skip_outboxfile, type: :boolean, default: false, desc: "Skip creating Outboxfile"
11
+ class_option :skip_initializer, type: :boolean, default: false, desc: "Skip creating config/initializers/outbox.rb"
12
+ class_option :skip_config, type: :boolean, default: false, desc: "Skip creating config/outbox.yml"
13
+
14
+ def create_outboxfile
15
+ return if options[:skip_outboxfile]
16
+
17
+ copy_file "Outboxfile", "Outboxfile"
18
+ end
19
+
20
+ def create_initializer
21
+ return if options[:skip_initializer]
22
+
23
+ copy_file "outbox.rb", OUTBOX_INITIALIZER_PATH
24
+ end
25
+
26
+ def create_config
27
+ return if options[:skip_config]
28
+
29
+ copy_file "outbox.yml", CONFIG_PATH
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "config/environment"
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ Rails.application.config.outbox.tap do |config|
4
+ # setup custom ErrorTracker
5
+ # config.error_tracker = "ErrorTracker"
6
+
7
+ # customize redis
8
+ # config.redis = {url: ENV.fetch("REDIS_URL", "redis://127.0.0.1:6379")}
9
+
10
+ # setup custom batch process middlewares
11
+ # config.batch_process_middlewares << "MyBatchProcessMiddleware"
12
+
13
+ # setup custom item process middlewares
14
+ # config.item_process_middlewares << "MyItemProcessMiddleware"
15
+
16
+ # config.process_items.tap do |x|
17
+ # # maximum processing time of the batch, after which the batch will be considered hung and processing will be aborted
18
+ # x[:general_timeout] = 180
19
+ # # maximum patch processing time, after which the processing of the patch will be aborted in the current thread,
20
+ # # and the next thread that picks up the batch will start processing from the same place
21
+ # x[:cutoff_timeout] = 60
22
+ # # batch size
23
+ # x[:batch_size] = 200
24
+ # end
25
+
26
+ # config.worker.tap do |worker|
27
+ # # number of batches that one thread will process per rate interval
28
+ # worker[:rate_limit] = 10
29
+ # # rate interval in seconds
30
+ # worker[:rate_interval] = 60
31
+ # end
32
+ end