Class: Jets::Booter

Inherits:
Object
  • Object
show all
Defined in:
lib/jets/booter.rb

Class Method Summary collapse

Class Method Details

.app_initializersObject

All Turbines



134
135
136
137
138
# File 'lib/jets/booter.rb', line 134

def app_initializers
  Dir.glob("#{Jets.root}/config/initializers/**/*").sort.each do |path|
    load path
  end
end

.boot!Object



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/jets/booter.rb', line 6

def boot!
  return if @booted

  confirm_jets_project!
  Jets::Bundle.require

  Jets.application.setup!
  check_ruby_version!

  # Turbines are loaded after setup_autoload_paths in Jets.application.setup!  Some Turbine options are defined
  # in the project so setup must happen before internal Turbines are loaded.
  load_internal_turbines

  run_turbines(:initializers)
  # Load configs after Turbine initializers so Turbines can defined some config options and they are available in
  # user's project environment configs.
  Jets.application.configs!
  app_initializers
  run_turbines(:after_initializers)
  Jets.application.finish!

  setup_db # establish db connections in Lambda Execution Context.
  # The eager load calls connects_to in models and establish those connections in Lambda Execution Context also.
  internal_finisher
  eager_load

  # TODO: Figure out how to build middleware during Jets.boot without breaking jets new and webpacker:install
  # build_middleware_stack

  @booted = true
end

.build_middleware_stackObject

Builds and memoize stack so it only gets built on bootup



152
153
154
# File 'lib/jets/booter.rb', line 152

def build_middleware_stack
  Jets.application.build_stack
end

.check_config_ru!Object



168
169
170
171
172
173
174
175
176
177
# File 'lib/jets/booter.rb', line 168

def check_config_ru!
  config_ru = File.read("#{Jets.root}/config.ru")
  unless config_ru.include?("Jets.boot")
    puts 'The config.ru file is missing Jets.boot.  Please add Jets.boot after require "jets"'.color(:red)
    puts "This was changed as made in Jets v1.1.0."
    puts "To have Jets update the config.fu file for you, you can run:\n\n"
    puts "  jets upgrade"
    exit 1
  end
end

.check_ruby_version!Object



179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/jets/booter.rb', line 179

def check_ruby_version!
  return if ENV['JETS_RUBY_CHECK'] == '0'
  return if !Jets.config.ruby.check
  return if ruby_version_supported?

  puts <<~EOL.color(:red)
    You are using Ruby #{RUBY_VERSION}
    AWS Lambda does not support this version.
    Please use one of the supported Ruby versions: #{supported_ruby_versions.join(' ')}
  EOL

  puts <<~EOL
    If you would like to skip this check, you can set: JETS_RUBY_CHECK=0 or configure

    config/application.rb

        Jets.application.configure do
          config.ruby.check = false
        end

    Or if you want to allow additional Ruby versions, then configure:

    config/application.rb

        Jets.application.configure do
          config.ruby.supported_versions = ["2.5", "2.7", "3.2"]
        end

    Note: If AWS Lambda does not officially support the Ruby version,
    you'll need to also provide the Ruby Custom Runtime Layer.
    Related Docs: https://rubyonjets.com/docs/extras/custom-runtime/
  EOL
  exit 1
end

.confirm_jets_project!Object

Cannot call this for the jets new



157
158
159
160
161
162
# File 'lib/jets/booter.rb', line 157

def confirm_jets_project!
  unless File.exist?("#{Jets.root}/config/application.rb")
    puts "It does not look like you are running this command within a jets project.  Please confirm that you are in a jets project and try again.".color(:red)
    exit 1
  end
end

.connect_dbObject

Eager connect to database, so connections are established in the Lambda Execution Context and get reused. Interestingly, the connections info is stored in the shared state but the connection doesnt show up on ‘show processlist` until after a query. Have confirmed that the connection is reused and the connection count stays the same.



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/jets/booter.rb', line 97

def connect_db
  if ActiveRecord::Base.legacy_connection_handling
    primary_hash_config = ActiveRecord::Base.configurations.configs_for(env_name: Jets.env).find { |hash_config|
      hash_config.name == "primary"
    }

    primary_config = primary_hash_config.configuration_hash # configuration_hash is a normal Ruby Hash

    ActiveRecord::Base.establish_connection(primary_config)
  else
    configs = ActiveRecord::Base.configurations.configs_for(env_name: Jets.env, include_replicas: true)

    databases = { }
    databases[:writing] = :primary if configs.any? { |config| config.name == "primary" }
    databases[:reading] = :primary_replica if configs.any? { |config| config.name == "primary_replica" }

    ActiveRecord::Base.connects_to database: databases
  end
end

.eager_loadObject



57
58
59
60
# File 'lib/jets/booter.rb', line 57

def eager_load
  preload_extensions
  Jets::Autoloaders.main.eager_load # Eager load project code. Rather have user find out early than later on AWS Lambda.
end

.internal_finisherObject

Runs right before eager_load



39
40
41
# File 'lib/jets/booter.rb', line 39

def internal_finisher
  load_shared_extensions
end

.load_internal_turbinesObject



117
118
119
120
121
# File 'lib/jets/booter.rb', line 117

def load_internal_turbines
  Jets::Autoloaders.once.on_setup do
    Jets::Mailer # only one right now
  end
end

.load_shared_extensionsObject

Shared extensions are added near the end because they require the Jets app load paths to first. We eager load the extensions and then use the loaded modules to extend Jets::Stack directly. Originally used an included hook but thats too early before app/shared/extensions is in the load_path.



46
47
48
49
50
51
52
53
54
55
# File 'lib/jets/booter.rb', line 46

def load_shared_extensions
  base_path = "#{Jets.root}/app/shared/extensions"
  Dir.glob("#{base_path}/**/*.rb").each do |path|
    next unless File.file?(path)

    class_name = path.sub("#{base_path}/", '').sub(/\.rb/,'').camelize
    mod = class_name.constantize # autoload
    Jets::Stack.extend(mod)
  end
end

.messageObject



164
165
166
# File 'lib/jets/booter.rb', line 164

def message
  "Jets booting up in #{Jets.env.color(:green)} mode!"
end

.preload_extensionsObject



62
63
64
65
66
67
68
69
70
71
# File 'lib/jets/booter.rb', line 62

def preload_extensions
  base_path = "#{Jets.root}/app/extensions"
  Dir.glob("#{base_path}/**/*.rb").each do |path|
    next unless File.file?(path)

    class_name = path.sub("#{base_path}/", '').sub(/\.rb/,'').camelize
    klass = class_name.constantize # autoload
    Jets::Lambda::Functions.extend(klass)
  end
end

.ruby_version_supported?Boolean

Returns:

  • (Boolean)


214
215
216
217
218
219
# File 'lib/jets/booter.rb', line 214

def ruby_version_supported?
  md = RUBY_VERSION.match(/(\d+)\.(\d+)\.\d+/)
  major, minor = md[1], md[2]
  detected_ruby = [major, minor].join('.')
  supported_ruby_versions.include?(detected_ruby)
end

.run_turbines(name) ⇒ Object

run_turbines(:initializers) run_turbines(:after_initializers)



142
143
144
145
146
147
148
149
# File 'lib/jets/booter.rb', line 142

def run_turbines(name)
  Jets::Turbine.subclasses.each do |subclass|
    hooks = subclass.send(name) || []
    hooks.each do |label, block|
      block.call(Jets.application)
    end
  end
end

.setup_dbObject

Using ActiveRecord outside of Rails, so we need to set up the db connection ourself.

Only connects to database for ActiveRecord and when config/database.yml exists. Dynomite handles connecting to the clients lazily.



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/jets/booter.rb', line 77

def setup_db
  return unless File.exist?("#{Jets.root}/config/database.yml")

  db_configs = Jets.application.config.database
  # DatabaseTasks.database_configuration for db:create db:migrate tasks
  # Documented in DatabaseTasks that this is the right way to set it when
  # using ActiveRecord rake tasks outside of Rails.
  ActiveRecord::Tasks::DatabaseTasks.database_configuration = db_configs

  if db_configs.configs_for(env_name: Jets.env).blank?
    abort("ERROR: config/database.yml exists but no environment section configured for #{Jets.env}")
  end
  ActiveRecord::Base.configurations = db_configs
  connect_db
end

.supported_ruby_versionsObject



221
222
223
# File 'lib/jets/booter.rb', line 221

def supported_ruby_versions
  Jets.config.ruby.supported_versions
end

.turbine_initializersObject

All Turbines



124
125
126
127
128
129
130
131
# File 'lib/jets/booter.rb', line 124

def turbine_initializers
  Jets::Turbine.subclasses.each do |subclass|
    initializers = subclass.initializers || []
    initializers.each do |label, block|
      block.call(Jets.application)
    end
  end
end