Class: Siding::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/siding/server.rb

Constant Summary collapse

BOOTSTRAP =
<<~RUBY
  begin
    Process.setsid
  rescue SystemCallError
    begin
      Process.setpgrp
    rescue SystemCallError
      nil
    end
  end
  require ARGV.shift
  Siding::Server.start(app_root: ARGV.shift, digest: ARGV.shift)
RUBY
DRAIN_INTERVAL =
0.05
SELECT_INTERVAL =
1.0
DEFAULT_IDLE_TIMEOUT =
900.0

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(project_key:, runtime:, logger: nil, env: ENV) ⇒ Server

Returns a new instance of Server.



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

def initialize(project_key:, runtime:, logger: nil, env: ENV)
  @project_key = project_key
  @runtime = runtime
  @logger = logger || Logger.new(log_path: runtime.log_path)
  @env = env
  @events = Staleness::Events.new(path: runtime.events_path)
  @workers = {}
  @workers_mutex = Mutex.new
  @shutting_down = false
  @withdrawn = false
  @served = 0
  @idle_timeout = self.class.idle_timeout_from(env)
  touch
end

Instance Attribute Details

#eventsObject (readonly)

Returns the value of attribute events.



76
77
78
# File 'lib/siding/server.rb', line 76

def events
  @events
end

#loggerObject (readonly)

Returns the value of attribute logger.



76
77
78
# File 'lib/siding/server.rb', line 76

def logger
  @logger
end

#manifestObject (readonly)

Returns the value of attribute manifest.



76
77
78
# File 'lib/siding/server.rb', line 76

def manifest
  @manifest
end

#project_keyObject (readonly)

Returns the value of attribute project_key.



76
77
78
# File 'lib/siding/server.rb', line 76

def project_key
  @project_key
end

#restarterObject (readonly)

Returns the value of attribute restarter.



76
77
78
# File 'lib/siding/server.rb', line 76

def restarter
  @restarter
end

#runtimeObject (readonly)

Returns the value of attribute runtime.



76
77
78
# File 'lib/siding/server.rb', line 76

def runtime
  @runtime
end

Class Method Details

.idle_timeout_from(env) ⇒ Object



93
94
95
96
# File 'lib/siding/server.rb', line 93

def self.idle_timeout_from(env)
  timeout = env["SIDING_IDLE_TIMEOUT"].to_f
  timeout.positive? ? timeout : DEFAULT_IDLE_TIMEOUT
end

.spawn(project_key:, runtime:, env:) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/siding/server.rb', line 37

def spawn(project_key:, runtime:, env:)
  log = File.open(runtime.boot_log_path, File::WRONLY | File::CREAT | File::TRUNC, 0o600)
  begin
    Process.spawn(
      spawn_env(project_key, env),
      RbConfig.ruby, "-e", BOOTSTRAP, "--",
      __FILE__, project_key.app_root, project_key.digest,
      chdir: project_key.app_root,
      in: File::NULL, out: log, err: log
    )
  ensure
    log.close
  end
end

.spawn_env(project_key, env) ⇒ Object



52
53
54
55
56
57
58
59
# File 'lib/siding/server.rb', line 52

def spawn_env(project_key, env)
  vars = { "SIDING_SERVER" => "1" }
  gemfile = File.join(project_key.app_root, "Gemfile")
  vars["BUNDLE_GEMFILE"] = gemfile if File.file?(gemfile)
  vars["RAILS_ENV"] = project_key.app_env
  vars["RACK_ENV"] = project_key.app_env
  vars
end

.start(app_root:, digest:) ⇒ Object



61
62
63
64
65
66
67
68
69
# File 'lib/siding/server.rb', line 61

def start(app_root:, digest:)
  key = ProjectKey.for(app_root)
  if key.digest != digest
    warn("siding: project key mismatch (client #{digest}, server #{key.digest})")
    exit 1
  end

  new(project_key: key, runtime: Runtime.for(key)).run
end

Instance Method Details

#busy?Boolean

Returns:

  • (Boolean)


119
120
121
# File 'lib/siding/server.rb', line 119

def busy?
  @shutting_down || @workers_mutex.synchronize { !@workers.empty? }
end

#retireObject



123
124
125
126
127
# File 'lib/siding/server.rb', line 123

def retire
  logger.debug("standing down; a replacement has taken over #{project_key.label}")
  @shutting_down = true
  wake
end

#runObject



98
99
100
101
102
103
104
105
106
107
108
# File 'lib/siding/server.rb', line 98

def run
  boot_application
  listen
  publish
  install_signal_handlers
  start_restarter
  accept_loop
ensure
  drain_workers
  shutdown
end

#start_restarterObject



110
111
112
113
114
115
116
117
# File 'lib/siding/server.rb', line 110

def start_restarter
  @restarter = Restarter.new(manifest: manifest, project_key: project_key, runtime: runtime,
                             logger: logger,
                             busy: -> { busy? },
                             superseded: -> { !published_by_us? },
                             on_superseded: -> { retire })
  @restarter.start
end