21700: Install Bundler system-wide in Rails postinst
[arvados.git] / services / api / config / initializers / reload_config.rb
1 # Copyright (C) The Arvados Authors. All rights reserved.
2 #
3 # SPDX-License-Identifier: AGPL-3.0
4
5 def start_reload_thread
6   Thread.new do
7     lockfile = Rails.root.join('tmp', 'reload_config.lock')
8     File.open(lockfile, File::WRONLY|File::CREAT, 0600) do |f|
9       # Note we don't use LOCK_NB here. If we did, each time passenger
10       # kills the lock-holder process, we would be left with nobody
11       # checking for updates until passenger starts a new worker,
12       # which could be a long time.
13       Rails.logger.debug("reload_config: waiting for lock on #{lockfile}")
14       f.flock(File::LOCK_EX)
15
16       t_lastload = Rails.configuration.SourceTimestamp
17       hash_lastload = Rails.configuration.SourceSHA256
18       conffile = ENV['ARVADOS_CONFIG'] || "/etc/arvados/config.yml"
19       Rails.logger.info("reload_config: polling for updated mtime on #{conffile} with threshold #{t_lastload}")
20       while true
21         sleep 1
22         t = File.mtime(conffile)
23         # If the file is newer than 5s, re-read it even if the
24         # timestamp matches the previously loaded file. This enables
25         # us to detect changes even if the filesystem's timestamp
26         # precision cannot represent multiple updates per second.
27         if t.to_f != t_lastload.to_f || Time.now.to_f - t.to_f < 5
28           Open3.popen2("arvados-server", "config-dump", "-skip-legacy") do |stdin, stdout, status_thread|
29             confs = YAML.safe_load(stdout)
30             hash = confs["SourceSHA256"]
31           rescue => e
32             Rails.logger.info("reload_config: config file updated but could not be loaded: #{e}")
33             t_lastload = t
34             next
35           end
36           if hash == hash_lastload
37             # If we reloaded a new or updated file, but the content is
38             # identical, keep polling instead of restarting.
39             t_lastload = t
40             next
41           end
42
43           restartfile = Rails.root.join('tmp', 'restart.txt')
44           touchtime = Time.now
45           Rails.logger.info("reload_config: mtime on #{conffile} changed to #{t}, touching #{restartfile} to #{touchtime}")
46           begin
47             File.utime(touchtime, touchtime, restartfile)
48           rescue
49             # remove + re-create works even if the existing file is
50             # owned by root, provided the tempdir is writable.
51             File.unlink(restartfile) rescue nil
52             File.open(restartfile, 'w') {}
53           end
54           # Even if passenger doesn't notice that we hit restart.txt
55           # and kill our process, there's no point waiting around to
56           # hit it again.
57           break
58         end
59       end
60     end
61   end
62 end
63
64 if !File.owned?(Rails.root.join('tmp'))
65   Rails.logger.debug("reload_config: not owner of #{Rails.root}/tmp, skipping")
66 elsif ENV["ARVADOS_CONFIG"] == "none"
67   Rails.logger.debug("reload_config: no config in use, skipping")
68 elsif defined?(PhusionPassenger)
69   PhusionPassenger.on_event(:starting_worker_process) do |forked|
70     start_reload_thread
71   end
72 else
73   start_reload_thread
74 end