Skip to content

Commit

Permalink
Add Spring.spawn_on_env
Browse files Browse the repository at this point in the history
Currently, it isn't possible for Spring to create multiple applications
for a given environment variable value. For example, you might want to
run an application with and without certain features enabled in the same
rails env.

Configuration must be set in config/spring_client.rb
  • Loading branch information
gmcgibbon committed Nov 22, 2023
1 parent 8b285d5 commit f19e200
Show file tree
Hide file tree
Showing 6 changed files with 35 additions and 12 deletions.
4 changes: 4 additions & 0 deletions lib/spring/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ def state!(val)
@interrupt.last.write "."
end

def spawn_env
JSON.load(ENV["SPRING_SPAWN_ENV"].dup).map { |key, value| "#{key}=#{value}" }.join(", ")
end

def app_env
ENV['RAILS_ENV']
end
Expand Down
12 changes: 9 additions & 3 deletions lib/spring/application/boot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,15 @@

Signal.trap("TERM") { app.terminate }

Spring::ProcessTitleUpdater.run { |distance|
"spring app | #{app.app_name} | started #{distance} ago | #{app.app_env} mode"
}
Spring::ProcessTitleUpdater.run do |distance|
attributes = [
app.app_name,
"started #{distance} ago",
"#{app.app_env} mode",
app.spawn_env,
]
"spring app | #{attributes.join(" | ")}"
end

app.eager_preload if ENV.delete("SPRING_PRELOAD") == "1"
app.run
9 changes: 6 additions & 3 deletions lib/spring/application_manager.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
module Spring
class ApplicationManager
attr_reader :pid, :child, :app_env, :spring_env, :status
attr_reader :pid, :child, :app_env, :spawn_env, :spring_env, :status

def initialize(app_env, spring_env)
def initialize(app_env, spawn_env, spring_env)
@app_env = app_env
@spawn_env = spawn_env
@spring_env = spring_env
@mutex = Mutex.new
@state = :running
Expand Down Expand Up @@ -100,7 +101,9 @@ def start_child(preload = false)
"RAILS_ENV" => app_env,
"RACK_ENV" => app_env,
"SPRING_ORIGINAL_ENV" => JSON.dump(Spring::ORIGINAL_ENV),
"SPRING_PRELOAD" => preload ? "1" : "0"
"SPRING_PRELOAD" => preload ? "1" : "0",
"SPRING_SPAWN_ENV" => JSON.dump(spawn_env),
**spawn_env,
},
"ruby",
*(bundler_dir != RbConfig::CONFIG["rubylibdir"] ? ["-I", bundler_dir] : []),
Expand Down
6 changes: 5 additions & 1 deletion lib/spring/client/run.rb
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ def verify_server_version

def connect_to_application(client)
server.send_io client
send_json server, "args" => args, "default_rails_env" => default_rails_env
send_json server, "args" => args, "default_rails_env" => default_rails_env, "spawn_env" => spawn_env

if IO.select([server], [], [], CONNECT_TIMEOUT)
server.gets or raise CommandNotFound
Expand Down Expand Up @@ -232,6 +232,10 @@ def send_json(socket, data)
def default_rails_env
ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
end

def spawn_env
ENV.slice(*Spring.spawn_on_env)
end
end
end
end
4 changes: 4 additions & 0 deletions lib/spring/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ def after_fork(&block)
after_fork_callbacks << block
end

def spawn_on_env
@spawn_on_env ||= []
end

def verify_environment
application_root_path
end
Expand Down
12 changes: 7 additions & 5 deletions lib/spring/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ def self.boot(options = {})
def initialize(options = {})
@foreground = options.fetch(:foreground, false)
@env = options[:env] || default_env
@applications = Hash.new { |h, k| h[k] = ApplicationManager.new(k, env) }
@applications = Hash.new do |hash, key|
hash[key] = ApplicationManager.new(*key, env)
end
@pidfile = env.pidfile_path.open('a')
@mutex = Mutex.new
end
Expand Down Expand Up @@ -57,12 +59,12 @@ def serve(client)
app_client = client.recv_io
command = JSON.load(client.read(client.gets.to_i))

args, default_rails_env = command.values_at('args', 'default_rails_env')
args, default_rails_env, spawn_env = command.values_at('args', 'default_rails_env', 'spawn_env')

if Spring.command?(args.first)
log "running command #{args.first}"
client.puts
client.puts @applications[rails_env_for(args, default_rails_env)].run(app_client)
client.puts @applications[rails_env_for(args, default_rails_env, spawn_env)].run(app_client)
else
log "command not found #{args.first}"
client.close
Expand All @@ -73,8 +75,8 @@ def serve(client)
redirect_output
end

def rails_env_for(args, default_rails_env)
Spring.command(args.first).env(args.drop(1)) || default_rails_env
def rails_env_for(args, default_rails_env, spawn_env)
[Spring.command(args.first).env(args.drop(1)) || default_rails_env, spawn_env]
end

# Boot the server into the process group of the current session.
Expand Down

0 comments on commit f19e200

Please sign in to comment.