container_broker 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +98 -0
- data/Rakefile +8 -0
- data/app/controllers/application_controller.rb +5 -0
- data/app/controllers/healthcheck_controller.rb +21 -0
- data/app/controllers/nodes_controller.rb +70 -0
- data/app/controllers/nodes_healthcheck_controller.rb +28 -0
- data/app/controllers/status_controller.rb +48 -0
- data/app/controllers/tasks_controller.rb +83 -0
- data/app/controllers/tasks_healthcheck_controller.rb +28 -0
- data/app/jobs/add_task_tags_job.rb +13 -0
- data/app/jobs/adjust_node_slots_job.rb +27 -0
- data/app/jobs/application_job.rb +9 -0
- data/app/jobs/collect_load_metrics_job.rb +9 -0
- data/app/jobs/container_broker_base_job.rb +32 -0
- data/app/jobs/migrate_tasks_from_dead_node_job.rb +32 -0
- data/app/jobs/monitor_unresponsive_node_job.rb +21 -0
- data/app/jobs/monitor_unresponsive_nodes_job.rb +9 -0
- data/app/jobs/release_slot_job.rb +47 -0
- data/app/jobs/remove_runner_job.rb +11 -0
- data/app/jobs/remove_unused_tags_job.rb +25 -0
- data/app/jobs/request_id_from_task.rb +7 -0
- data/app/jobs/run_task_job.rb +64 -0
- data/app/jobs/run_tasks_for_all_execution_types_job.rb +11 -0
- data/app/jobs/run_tasks_job.rb +42 -0
- data/app/jobs/timeout_failed_tasks_job.rb +31 -0
- data/app/jobs/update_all_nodes_status_job.rb +9 -0
- data/app/jobs/update_node_status_job.rb +24 -0
- data/app/jobs/update_task_status_job.rb +71 -0
- data/app/models/mongoid_serializable_model.rb +14 -0
- data/app/models/node.rb +101 -0
- data/app/models/slot.rb +42 -0
- data/app/models/task.rb +148 -0
- data/app/models/task_tag.rb +11 -0
- data/app/observers/observable.rb +23 -0
- data/app/observers/task_observer.rb +11 -0
- data/app/serializers/node_healthcheck_serializer.rb +5 -0
- data/app/serializers/node_serializer.rb +5 -0
- data/app/serializers/status_panel_node_serializer.rb +9 -0
- data/app/serializers/status_panel_slot_serializer.rb +5 -0
- data/app/serializers/status_panel_task_serializer.rb +16 -0
- data/app/serializers/task_healthcheck_serializer.rb +5 -0
- data/app/serializers/task_serializer.rb +7 -0
- data/app/services/adjust_execution_type_slots.rb +51 -0
- data/app/services/check_for_slot_removal.rb +28 -0
- data/app/services/collect_load_metrics.rb +40 -0
- data/app/services/delete_node.rb +25 -0
- data/app/services/friendly_name_nodes.rb +10 -0
- data/app/services/friendly_name_slots.rb +15 -0
- data/app/services/kill_node_runners.rb +17 -0
- data/app/services/kill_task_container.rb +29 -0
- data/app/services/kubernetes_client.rb +136 -0
- data/app/services/least_used_node.rb +44 -0
- data/app/services/lock_manager.rb +74 -0
- data/app/services/lock_slot.rb +37 -0
- data/app/services/lock_task.rb +45 -0
- data/app/services/metrics.rb +43 -0
- data/app/services/migrate_runner.rb +26 -0
- data/app/services/node_task_acceptance.rb +18 -0
- data/app/services/node_usage_percentage_per_execution_type.rb +22 -0
- data/app/services/reschedule_tasks_for_missing_runners.rb +70 -0
- data/app/services/runners.rb +4 -0
- data/app/services/runners/docker/create_connection.rb +18 -0
- data/app/services/runners/docker/create_execution_info.rb +87 -0
- data/app/services/runners/docker/fetch_execution_info.rb +17 -0
- data/app/services/runners/docker/fetch_logs.rb +18 -0
- data/app/services/runners/docker/fetch_task_container.rb +15 -0
- data/app/services/runners/docker/filer.rb +19 -0
- data/app/services/runners/docker/kill_slot_runner.rb +19 -0
- data/app/services/runners/docker/node_availability.rb +11 -0
- data/app/services/runners/docker/remove_runner.rb +18 -0
- data/app/services/runners/docker/run_task.rb +63 -0
- data/app/services/runners/docker/update_node_status.rb +62 -0
- data/app/services/runners/execution_info.rb +49 -0
- data/app/services/runners/invalid_config.rb +5 -0
- data/app/services/runners/invalid_runner.rb +5 -0
- data/app/services/runners/kubernetes/create_client.rb +29 -0
- data/app/services/runners/kubernetes/create_execution_info.rb +103 -0
- data/app/services/runners/kubernetes/fetch_execution_info.rb +15 -0
- data/app/services/runners/kubernetes/fetch_logs.rb +17 -0
- data/app/services/runners/kubernetes/filer.rb +41 -0
- data/app/services/runners/kubernetes/kill_slot_runner.rb +11 -0
- data/app/services/runners/kubernetes/node_availability.rb +11 -0
- data/app/services/runners/kubernetes/remove_runner.rb +19 -0
- data/app/services/runners/kubernetes/run_task.rb +54 -0
- data/app/services/runners/kubernetes/update_node_status.rb +64 -0
- data/app/services/runners/runner_id_not_found_error.rb +5 -0
- data/app/services/runners/services_factory.rb +38 -0
- data/app/services/runners/update_node_status_helper.rb +43 -0
- data/app/services/slots_usage_percentage.rb +18 -0
- data/config/application.rb +34 -0
- data/config/boot.rb +5 -0
- data/config/environment.rb +7 -0
- data/config/environments/test.rb +44 -0
- data/config/initializers/application_controller_renderer.rb +10 -0
- data/config/initializers/backtrace_silencers.rb +9 -0
- data/config/initializers/config.rb +51 -0
- data/config/initializers/cookies_serializer.rb +7 -0
- data/config/initializers/docker_config.rb +3 -0
- data/config/initializers/filter_parameter_logging.rb +6 -0
- data/config/initializers/idempotent_request.rb +12 -0
- data/config/initializers/inflections.rb +18 -0
- data/config/initializers/mime_types.rb +6 -0
- data/config/initializers/mongoid.rb +3 -0
- data/config/initializers/new_framework_defaults_6_0.rb +47 -0
- data/config/initializers/raven.rb +10 -0
- data/config/initializers/sidekiq.rb +24 -0
- data/config/initializers/wrap_parameters.rb +16 -0
- data/config/locales/en.yml +33 -0
- data/config/mongoid.yml +10 -0
- data/config/routes.rb +43 -0
- data/config/secrets.yml +35 -0
- data/config/settings.yml +34 -0
- data/config/settings/test.yml +27 -0
- data/config/sidekiq_scheduler.yml +18 -0
- data/config/spring.rb +8 -0
- data/lib/constants.rb +12 -0
- data/lib/container_broker.rb +30 -0
- data/lib/container_broker/engine.rb +6 -0
- data/lib/container_broker/version.rb +5 -0
- data/lib/current_thread_request_id.rb +19 -0
- data/lib/idempotent_request/callback.rb +25 -0
- data/lib/idempotent_request/policy.rb +15 -0
- data/lib/redis_url_parser.rb +25 -0
- data/lib/tasks/task.rake +34 -0
- metadata +590 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Runners
|
4
|
+
module Kubernetes
|
5
|
+
class RemoveRunner
|
6
|
+
def perform(node:, runner_id:)
|
7
|
+
Rails.logger.debug("Deleting pod")
|
8
|
+
begin
|
9
|
+
CreateClient.new.perform(node: node).force_delete_pod(pod_name: runner_id)
|
10
|
+
Rails.logger.debug("Pod #{runner_id} removed")
|
11
|
+
rescue KubernetesClient::PodNotFoundError
|
12
|
+
Rails.logger.debug("Pod #{runner_id} already removed")
|
13
|
+
rescue KubernetesClient::NetworkError => e
|
14
|
+
node.register_error(e.message)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Runners
|
4
|
+
module Kubernetes
|
5
|
+
class RunTask
|
6
|
+
NFS_NAME = "nfs"
|
7
|
+
|
8
|
+
def perform(task:, slot:, runner_id:)
|
9
|
+
create_pod(task: task, node: slot.node, runner_id: runner_id)
|
10
|
+
rescue KubernetesClient::NetworkError => e then
|
11
|
+
raise Node::NodeConnectionError, "#{e.class}: #{e.message}"
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def create_pod(task:, node:, runner_id:)
|
17
|
+
CreateClient.new.perform(node: node).create_pod(
|
18
|
+
pod_name: runner_id,
|
19
|
+
image: task.image,
|
20
|
+
cmd: task.cmd,
|
21
|
+
internal_mounts: internal_mounts(task: task),
|
22
|
+
external_mounts: external_mounts(task: task),
|
23
|
+
node_selector: node.runner_config["node_selector"]
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
def filer(task:)
|
28
|
+
Filer.new.perform(task_storage_mounts: task.storage_mounts)
|
29
|
+
end
|
30
|
+
|
31
|
+
def internal_mounts(task:)
|
32
|
+
filer(task: task)[:internal]
|
33
|
+
end
|
34
|
+
|
35
|
+
def external_mounts(task:)
|
36
|
+
filer(task: task)[:external]
|
37
|
+
end
|
38
|
+
|
39
|
+
def add_metric(task)
|
40
|
+
Metrics.new("tasks").count(
|
41
|
+
task_id: task.id,
|
42
|
+
name: task&.name,
|
43
|
+
type: task&.execution_type,
|
44
|
+
slot: task&.slot&.name,
|
45
|
+
node: task&.slot&.node&.name,
|
46
|
+
started_at: task.started_at,
|
47
|
+
duration: task.milliseconds_waiting,
|
48
|
+
error: task.error,
|
49
|
+
status: task.status
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Runners
|
4
|
+
module Kubernetes
|
5
|
+
class UpdateNodeStatus
|
6
|
+
include UpdateNodeStatusHelper
|
7
|
+
|
8
|
+
attr_reader :node
|
9
|
+
|
10
|
+
def perform(node:)
|
11
|
+
@node = node
|
12
|
+
|
13
|
+
# Other tasks can be started at this time. Because of this it's necessary to load the tasks first and then the containers
|
14
|
+
started_tasks = Task.started.where(:slot.in => node.slots.pluck(:id)).to_a
|
15
|
+
|
16
|
+
node.update!(runner_capacity_reached: pending_schedule_pods?)
|
17
|
+
|
18
|
+
execution_infos.each do |execution_info|
|
19
|
+
runner_id = execution_info.id
|
20
|
+
slot = node.slots.find_by(runner_id: runner_id)
|
21
|
+
|
22
|
+
if slot
|
23
|
+
if execution_info.terminated?
|
24
|
+
Rails.logger.debug("Pod #{runner_id} Complete")
|
25
|
+
check_slot_release(slot: slot, runner_id: runner_id)
|
26
|
+
else
|
27
|
+
slot.current_task&.update!(error: execution_info.error) if execution_info.error
|
28
|
+
Rails.logger.debug("Pod is not terminated (it is #{execution_info.status}). Ignoring.")
|
29
|
+
end
|
30
|
+
else
|
31
|
+
remove_unknown_runner(node: node, runner_id: runner_id)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
RescheduleTasksForMissingRunners
|
36
|
+
.new(runner_ids: pods.keys, started_tasks: started_tasks)
|
37
|
+
.perform
|
38
|
+
|
39
|
+
node.register_success
|
40
|
+
|
41
|
+
send_metrics(node: node, execution_infos: execution_infos)
|
42
|
+
rescue KubernetesClient::NetworkError => e
|
43
|
+
Rails.logger.debug("Error #{e.class}: #{e}")
|
44
|
+
node.register_error(e.message)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def pods
|
50
|
+
@pods ||= CreateClient.new.perform(node: node)
|
51
|
+
.fetch_pods
|
52
|
+
.tap { |pods| Rails.logger.debug("Fetched #{pods.count} pods") }
|
53
|
+
end
|
54
|
+
|
55
|
+
def execution_infos
|
56
|
+
@execution_infos ||= pods.values.map { |pod| CreateExecutionInfo.new.perform(pod: pod) }
|
57
|
+
end
|
58
|
+
|
59
|
+
def pending_schedule_pods?
|
60
|
+
execution_infos.any?(&:schedule_pending?)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Runners
|
4
|
+
class ServicesFactory
|
5
|
+
class ServiceNotFoundForRunner < StandardError; end
|
6
|
+
|
7
|
+
SERVICES = {
|
8
|
+
kubernetes: {
|
9
|
+
update_node_status: Runners::Kubernetes::UpdateNodeStatus,
|
10
|
+
node_availability: Runners::Kubernetes::NodeAvailability,
|
11
|
+
run_task: Runners::Kubernetes::RunTask,
|
12
|
+
kill_slot_runner: Runners::Kubernetes::KillSlotRunner,
|
13
|
+
remove_runner: Runners::Kubernetes::RemoveRunner,
|
14
|
+
fetch_logs: Runners::Kubernetes::FetchLogs,
|
15
|
+
fetch_execution_info: Runners::Kubernetes::FetchExecutionInfo,
|
16
|
+
filer: Runners::Kubernetes::Filer
|
17
|
+
},
|
18
|
+
docker: {
|
19
|
+
update_node_status: Runners::Docker::UpdateNodeStatus,
|
20
|
+
node_availability: Runners::Docker::NodeAvailability,
|
21
|
+
run_task: Runners::Docker::RunTask,
|
22
|
+
kill_slot_runner: Runners::Docker::KillSlotRunner,
|
23
|
+
remove_runner: Runners::Docker::RemoveRunner,
|
24
|
+
fetch_logs: Runners::Docker::FetchLogs,
|
25
|
+
fetch_execution_info: Runners::Docker::FetchExecutionInfo,
|
26
|
+
filer: Runners::Docker::Filer
|
27
|
+
}
|
28
|
+
}.freeze
|
29
|
+
|
30
|
+
def self.fabricate(runner:, service:)
|
31
|
+
service_class = SERVICES.dig(runner.to_sym, service)
|
32
|
+
|
33
|
+
raise ServiceNotFoundForRunner, "No service #{service} found for #{runner}" unless service_class
|
34
|
+
|
35
|
+
service_class.new
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Runners
|
4
|
+
module UpdateNodeStatusHelper
|
5
|
+
def check_slot_release(slot:, runner_id:)
|
6
|
+
if slot.running?
|
7
|
+
slot.releasing!
|
8
|
+
Rails.logger.debug("Slot was running. Marked as releasing. Slot: #{slot}. Current task: #{slot.current_task}")
|
9
|
+
ReleaseSlotJob.perform_later(slot: MongoidSerializableModel.new(slot), runner_id: runner_id)
|
10
|
+
else
|
11
|
+
Rails.logger.debug("Slot was not running (it was #{slot.status}). Ignoring.")
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def remove_unknown_runner(node:, runner_id:)
|
16
|
+
Rails.logger.debug("Slot not found for container #{runner_id}")
|
17
|
+
|
18
|
+
if Settings.ignore_containers.none? { |ignored_name| runner_id.start_with?(ignored_name) }
|
19
|
+
# It is needed to select the container using just any of its names
|
20
|
+
RemoveRunnerJob.perform_later(node: node, runner_id: runner_id)
|
21
|
+
else
|
22
|
+
Rails.logger.debug("Container #{runner_id} is ignored for removal")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def send_metrics(node:, execution_infos:)
|
27
|
+
runners_count = execution_infos
|
28
|
+
.group_by(&:status)
|
29
|
+
.transform_keys { |k| "#{k}_runners".to_sym }
|
30
|
+
.transform_values(&:count)
|
31
|
+
|
32
|
+
data = {
|
33
|
+
hostname: node.hostname,
|
34
|
+
runner_type: node.runner_provider,
|
35
|
+
capacity_reached: node.runner_capacity_reached,
|
36
|
+
schedule_pending: execution_infos.count(&:schedule_pending?),
|
37
|
+
total_runners: execution_infos.count
|
38
|
+
}
|
39
|
+
|
40
|
+
Metrics.new("runners").count(data.merge(runners_count))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SlotsUsagePercentage
|
4
|
+
def initialize(slots)
|
5
|
+
@slots = slots
|
6
|
+
end
|
7
|
+
|
8
|
+
def perform
|
9
|
+
(((@slots.size - available_slots.size).to_f / @slots.size) * 100)
|
10
|
+
.round(2)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def available_slots
|
16
|
+
@slots.select(&:available?)
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "boot"
|
4
|
+
|
5
|
+
require "action_controller/railtie"
|
6
|
+
# require "action_view/railtie"
|
7
|
+
# require "action_mailer/railtie"
|
8
|
+
require "active_job/railtie"
|
9
|
+
# require "action_cable/engine"
|
10
|
+
# require "rails/test_unit/railtie"
|
11
|
+
# require "sprockets/railtie"
|
12
|
+
|
13
|
+
# Require the gems listed in Gemfile, including any gems
|
14
|
+
# you've limited to :test, :development, or :production.
|
15
|
+
Bundler.require(*Rails.groups)
|
16
|
+
|
17
|
+
module ContainerBroker
|
18
|
+
class Application < Rails::Application
|
19
|
+
# Initialize configuration defaults for originally generated Rails version.
|
20
|
+
config.load_defaults 5.1
|
21
|
+
|
22
|
+
config.api_only = true
|
23
|
+
|
24
|
+
# Settings in config/environments/* take precedence over those specified here.
|
25
|
+
# Application configuration should go into files in config/initializers
|
26
|
+
# -- all .rb files in that directory are automatically loaded.
|
27
|
+
|
28
|
+
config.eager_load_paths << Rails.root.join("lib")
|
29
|
+
|
30
|
+
config.log_tags = [
|
31
|
+
->(request) { " request_id=#{request.request_id} " }
|
32
|
+
]
|
33
|
+
end
|
34
|
+
end
|
data/config/boot.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Rails.application.configure do
|
4
|
+
# Settings specified here will take precedence over those in config/application.rb.
|
5
|
+
|
6
|
+
# The test environment is used exclusively to run your application's
|
7
|
+
# test suite. You never need to work with it otherwise. Remember that
|
8
|
+
# your test database is "scratch space" for the test suite and is wiped
|
9
|
+
# and recreated between test runs. Don't rely on the data there!
|
10
|
+
config.cache_classes = true
|
11
|
+
|
12
|
+
# Do not eager load code on boot. This avoids loading your whole application
|
13
|
+
# just for the purpose of running a single test. If you are using a tool that
|
14
|
+
# preloads Rails for running tests, you may have to set it to true.
|
15
|
+
config.eager_load = false
|
16
|
+
|
17
|
+
# Configure public file server for tests with Cache-Control for performance.
|
18
|
+
config.public_file_server.enabled = true
|
19
|
+
config.public_file_server.headers = {
|
20
|
+
"Cache-Control" => "public, max-age=#{1.hour.seconds.to_i}"
|
21
|
+
}
|
22
|
+
|
23
|
+
# Show full error reports and disable caching.
|
24
|
+
config.consider_all_requests_local = true
|
25
|
+
config.action_controller.perform_caching = false
|
26
|
+
|
27
|
+
# Raise exceptions instead of rendering exception templates.
|
28
|
+
config.action_dispatch.show_exceptions = false
|
29
|
+
|
30
|
+
# Disable request forgery protection in test environment.
|
31
|
+
config.action_controller.allow_forgery_protection = false
|
32
|
+
# config.action_mailer.perform_caching = false
|
33
|
+
|
34
|
+
# Tell Action Mailer not to deliver emails to the real world.
|
35
|
+
# The :test delivery method accumulates sent emails in the
|
36
|
+
# ActionMailer::Base.deliveries array.
|
37
|
+
# config.action_mailer.delivery_method = :test
|
38
|
+
|
39
|
+
# Print deprecation notices to the stderr.
|
40
|
+
config.active_support.deprecation = :stderr
|
41
|
+
|
42
|
+
# Raises error for missing translations
|
43
|
+
# config.action_view.raise_on_missing_translations = true
|
44
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Be sure to restart your server when you modify this file.
|
4
|
+
|
5
|
+
# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces.
|
6
|
+
# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ }
|
7
|
+
|
8
|
+
# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code.
|
9
|
+
# Rails.backtrace_cleaner.remove_silencers!
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Config.setup do |config|
|
4
|
+
# Name of the constant exposing loaded settings
|
5
|
+
config.const_name = "Settings"
|
6
|
+
|
7
|
+
# Ability to remove elements of the array set in earlier loaded settings file. For example value: '--'.
|
8
|
+
#
|
9
|
+
# config.knockout_prefix = nil
|
10
|
+
|
11
|
+
# Overwrite an existing value when merging a `nil` value.
|
12
|
+
# When set to `false`, the existing value is retained after merge.
|
13
|
+
#
|
14
|
+
# config.merge_nil_values = true
|
15
|
+
|
16
|
+
# Overwrite arrays found in previously loaded settings file. When set to `false`, arrays will be merged.
|
17
|
+
#
|
18
|
+
# config.overwrite_arrays = true
|
19
|
+
|
20
|
+
# Load environment variables from the `ENV` object and override any settings defined in files.
|
21
|
+
#
|
22
|
+
# config.use_env = false
|
23
|
+
|
24
|
+
# Define ENV variable prefix deciding which variables to load into config.
|
25
|
+
#
|
26
|
+
# config.env_prefix = 'Settings'
|
27
|
+
|
28
|
+
# What string to use as level separator for settings loaded from ENV variables. Default value of '.' works well
|
29
|
+
# with Heroku, but you might want to change it for example for '__' to easy override settings from command line, where
|
30
|
+
# using dots in variable names might not be allowed (eg. Bash).
|
31
|
+
#
|
32
|
+
# config.env_separator = '.'
|
33
|
+
|
34
|
+
# Ability to process variables names:
|
35
|
+
# * nil - no change
|
36
|
+
# * :downcase - convert to lower case
|
37
|
+
#
|
38
|
+
# config.env_converter = :downcase
|
39
|
+
|
40
|
+
# Parse numeric values as integers instead of strings.
|
41
|
+
#
|
42
|
+
# config.env_parse_values = true
|
43
|
+
|
44
|
+
# Validate presence and type of specific config values. Check https://github.com/dry-rb/dry-validation for details.
|
45
|
+
#
|
46
|
+
# config.schema do
|
47
|
+
# required(:name).filled
|
48
|
+
# required(:age).maybe(:int?)
|
49
|
+
# required(:email).filled(format?: EMAIL_REGEX)
|
50
|
+
# end
|
51
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Be sure to restart your server when you modify this file.
|
4
|
+
|
5
|
+
# Specify a serializer for the signed and encrypted cookie jars.
|
6
|
+
# Valid options are :json, :marshal, and :hybrid.
|
7
|
+
Rails.application.config.action_dispatch.cookies_serializer = :json
|