Invited spring to the party 🎉 Taking development speed to the next level 🚀- Enable via ENV 'ENABLE_SPRING'.

This commit is contained in:
Thorsten Eckel 2018-10-01 22:00:26 +02:00
parent e4d7dc449f
commit 6718d2eb7c
10 changed files with 128 additions and 44 deletions

View file

@ -120,6 +120,11 @@ gem 'viewpoint'
# in production environments by default. # in production environments by default.
group :development, :test do group :development, :test do
# app boottime improvement
gem 'spring'
gem 'spring-commands-rspec'
gem 'spring-commands-testunit'
# debugging # debugging
gem 'byebug' gem 'byebug'
gem 'pry-rails' gem 'pry-rails'

View file

@ -415,6 +415,12 @@ GEM
simplecov (>= 0.4.1) simplecov (>= 0.4.1)
slack-notifier (2.3.1) slack-notifier (2.3.1)
slop (3.6.0) slop (3.6.0)
spring (2.0.2)
activesupport (>= 4.2)
spring-commands-rspec (1.0.4)
spring (>= 0.9.1)
spring-commands-testunit (1.0.1)
spring (>= 0.9.1)
sprockets (3.7.2) sprockets (3.7.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
@ -558,6 +564,9 @@ DEPENDENCIES
simplecov simplecov
simplecov-rcov simplecov-rcov
slack-notifier slack-notifier
spring
spring-commands-rspec
spring-commands-testunit
sprockets sprockets
sqlite3 sqlite3
tcr tcr

View file

@ -1,4 +1,9 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
APP_PATH = File.expand_path('../../config/application', __FILE__) APP_PATH = File.expand_path('../../config/application', __FILE__)
require_relative '../config/boot' require_relative '../config/boot'
require 'rails/commands' require 'rails/commands'

View file

@ -1,4 +1,9 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
begin
load File.expand_path('../spring', __FILE__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
require_relative '../config/boot' require_relative '../config/boot'
require 'rake' require 'rake'
Rake.application.run Rake.application.run

View file

@ -1,3 +1,8 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
begin
load File.expand_path('spring', __dir__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
require 'bundler/setup' require 'bundler/setup'
load Gem.bin_path('rspec-core', 'rspec') load Gem.bin_path('rspec-core', 'rspec')

View file

@ -3,13 +3,15 @@
# This file loads spring without using Bundler, in order to be fast. # This file loads spring without using Bundler, in order to be fast.
# It gets overwritten when you run the `spring binstub` command. # It gets overwritten when you run the `spring binstub` command.
unless defined?(Spring) if ENV['ENABLE_SPRING'] && !defined?(Spring)
require 'rubygems' require 'rubygems'
require 'bundler' require 'bundler'
if (match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m)) lockfile = Bundler::LockfileParser.new(Bundler.default_lockfile.read)
Gem.paths = { 'GEM_PATH' => [Bundler.bundle_path.to_s, *Gem.path].uniq.join(Gem.path_separator) } spring = lockfile.specs.detect { |spec| spec.name == "spring" }
gem 'spring', match[1] if spring
Gem.use_paths Gem.dir, Bundler.bundle_path.to_s, *Gem.path
gem 'spring', spring.version
require 'spring/binstub' require 'spring/binstub'
end end
end end

37
config/spring.rb Normal file
View file

@ -0,0 +1,37 @@
module Spring
module Commands
class SchedulerRb
def call
load ::Rails.root.join('script/scheduler.rb')
end
end
Spring.register_command 'scheduler.rb', Spring::Commands::SchedulerRb.new
end
end
module Spring
module Commands
class WebsocketServerRb
def call
load ::Rails.root.join('script/websocket-server.rb')
end
end
Spring.register_command 'websocket-server.rb', Spring::Commands::WebsocketServerRb.new
end
end
module Spring
module Commands
class RailsServer < Rails
def command_name
'server'
end
end
Spring.register_command 'rails_server', RailsServer.new
end
end

15
config/spring_client.rb Normal file
View file

@ -0,0 +1,15 @@
module Spring
module Client
class Rails < Command
DEFAULT_COMMANDS = COMMANDS.dup
DEFAULT_ALIASES = ALIASES.dup
remove_const('COMMANDS')
remove_const('ALIASES')
const_set('COMMANDS', DEFAULT_COMMANDS + %w[server])
const_set('ALIASES', DEFAULT_ALIASES.merge('s' => 'server'))
end
end
end

View file

@ -1,27 +1,18 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
begin
load File.expand_path('../bin/spring', __dir__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
$LOAD_PATH << './lib'
require 'rubygems'
# load rails env
dir = File.expand_path(File.join(File.dirname(__FILE__), '..')) dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
Dir.chdir dir Dir.chdir dir
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
require 'rails/all'
require 'bundler' require 'bundler'
require File.join(dir, 'config', 'environment')
require 'daemons' require 'daemons'
def before_fork def before_fork
# clear all connections before for, reconnect later ActiveRecord::Base.connection.reconnect!
# issue #1405 - Scheduler not running because of Bad file descriptor in PGConsumeInput()
# https://github.com/zammad/zammad/issues/1405
# see also https://bitbucket.org/ged/ruby-pg/issues/260/frequent-crashes-with-multithreading
ActiveRecord::Base.clear_all_connections!
# remember open file handles # remember open file handles
@files_to_reopen = [] @files_to_reopen = []
ObjectSpace.each_object(File) do |file| ObjectSpace.each_object(File) do |file|
@ -38,6 +29,15 @@ def after_fork(dir)
file.sync = true file.sync = true
end end
# Spring redirects STDOUT and STDERR to /dev/null
# before we get here. This causes the `reopen` lines
# below to fail because the handles are already
# opened for write
if defined?(Spring)
$stdout.close
$stderr.close
end
$stdout.reopen("#{dir}/log/scheduler_out.log", 'w') $stdout.reopen("#{dir}/log/scheduler_out.log", 'w')
$stderr.reopen("#{dir}/log/scheduler_err.log", 'w') $stderr.reopen("#{dir}/log/scheduler_err.log", 'w')
end end
@ -45,29 +45,22 @@ end
before_fork before_fork
daemon_options = { daemon_options = {
multiple: false, multiple: false,
dir_mode: :normal, dir_mode: :normal,
dir: File.join(dir, 'tmp', 'pids'), dir: File.join(dir, 'tmp', 'pids'),
backtrace: true backtrace: true
} }
name = 'scheduler' Daemons.run_proc('scheduler', daemon_options) do
Daemons.run_proc(name, daemon_options) do
if ARGV.include?('--')
ARGV.slice! 0..ARGV.index('--')
else
ARGV.clear
end
after_fork(dir) after_fork(dir)
Rails.logger.info 'Scheduler started.' require File.join(dir, 'config', 'environment')
Rails.logger.info 'Scheduler started.'
at_exit do at_exit do
Rails.logger.info 'Scheduler stopped.' Rails.logger.info 'Scheduler stopped.'
end end
require 'scheduler'
Scheduler.threads Scheduler.threads
end end

View file

@ -1,27 +1,26 @@
#!/usr/bin/env ruby #!/usr/bin/env ruby
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/ # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
begin
load File.expand_path('../bin/spring', __dir__)
rescue LoadError => e
raise unless e.message.include?('spring')
end
$LOAD_PATH << './lib' dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
require 'rubygems'
# load rails env
dir = File.expand_path('..', __dir__)
Dir.chdir dir Dir.chdir dir
RAILS_ENV = ENV['RAILS_ENV'] || 'development'
require 'rails/all'
require 'bundler' require 'bundler'
require File.join(dir, 'config', 'environment') require File.join(dir, 'config', 'environment')
require 'eventmachine' require 'eventmachine'
require 'em-websocket' require 'em-websocket'
require 'json' require 'json'
require 'fileutils' require 'fileutils'
require 'optparse' require 'optparse'
require 'daemons' require 'daemons'
require 'sessions'
def before_fork def before_fork
# remember open file handles # remember open file handles
@files_to_reopen = [] @files_to_reopen = []
ObjectSpace.each_object(File) do |file| ObjectSpace.each_object(File) do |file|
@ -38,8 +37,17 @@ def after_fork(dir)
file.sync = true file.sync = true
end end
$stdout.reopen( "#{dir}/log/websocket-server_out.log", 'w').sync = true # Spring redirects STDOUT and STDERR to /dev/null
$stderr.reopen( "#{dir}/log/websocket-server_err.log", 'w').sync = true # before we get here. This causes the `reopen` lines
# below to fail because the handles are already
# opened for write
if defined?(Spring)
$stdout.close
$stderr.close
end
$stdout.reopen("#{dir}/log/websocket-server_out.log", 'w').sync = true
$stderr.reopen("#{dir}/log/websocket-server_err.log", 'w').sync = true
end end
before_fork before_fork
@ -53,7 +61,7 @@ before_fork
d: false, d: false,
k: '/path/to/server.key', k: '/path/to/server.key',
c: '/path/to/server.crt', c: '/path/to/server.crt',
i: Dir.pwd.to_s + '/tmp/pids/websocket.pid' i: "#{dir}/tmp/pids/websocket.pid"
} }
tls_options = {} tls_options = {}
@ -111,7 +119,7 @@ if ARGV[0] == 'start' && @options[:d]
Daemons.daemonize( Daemons.daemonize(
app_name: File.basename(@options[:i], '.pid'), app_name: File.basename(@options[:i], '.pid'),
dir_mode: :normal, dir_mode: :normal,
dir: File.dirname(@options[:i]) dir: File.dirname(@options[:i])
) )
after_fork(dir) after_fork(dir)