sbmt-outbox 5.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.
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