Module: Hyperion::StaticPreload

Defined in:
lib/hyperion/static_preload.rb

Overview

2.10-E — Boot-time static-asset preload.

‘StaticPreload.run` walks each operator-supplied directory tree and populates `Hyperion::Http::PageCache` from the regular files inside. When `immutable: true` (the default for the operator-facing surfaces — the whole point of preload is “I promise these don’t change without a restart”) every cached entry is marked immutable so the page cache never re-stats the file on subsequent serves.

The Server boot path invokes this once per worker after ‘listen` configures the listener but BEFORE the accept loop spins up — so the very first request lands on a warm cache, not a cold cache miss.

Rails-shaped apps get auto-detect for free: when the operator hasn’t configured ‘preload_static` (and didn’t pass ‘–no-preload-static`), `Config#resolved_preload_static_dirs` synthesises a list from `Rails.configuration.assets.paths.first(N)` (cap 8). Hyperion never `require`s rails — `detect_rails_paths` defensively probes `defined?(::Rails) && ::Rails.respond_to?(:configuration)` so the gem stays Rails-agnostic.

Constant Summary collapse

RAILS_AUTO_DETECT_CAP =

Default cap on auto-detected Rails asset paths. 8 covers a typical Rails 7+ app (jsbundling/cssbundling/propshaft + a few engine paths) without iterating every gem-installed asset path the host ever depends on. Operators wanting a different cap can pass it explicitly to ‘detect_rails_paths(cap:)`.

8

Class Method Summary collapse

Class Method Details

.detect_rails_paths(cap: RAILS_AUTO_DETECT_CAP) ⇒ Object

Detect the first ‘cap` Rails asset paths. Returns `[]` when Rails is not loaded, when the configuration surface is missing any expected method, or when `assets.paths` is not an Array. NEVER `require ’rails’‘ — auto-detect must work for the operator who has Rails in their bundle but for a generic Rack app Hyperion is supposed to stay neutral about.



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/hyperion/static_preload.rb', line 80

def detect_rails_paths(cap: RAILS_AUTO_DETECT_CAP)
  return [] unless rails_available?

  config = ::Rails.configuration
  return [] unless config.respond_to?(:assets)

  assets = config.assets
  return [] unless assets.respond_to?(:paths)

  paths = assets.paths
  return [] unless paths.is_a?(Array) && !paths.empty?

  paths.first(cap).map(&:to_s)
rescue StandardError
  # Auto-detect is a convenience; never let a Rails internals
  # surface change crash boot. Worst case the operator gets the
  # 1.x cold-cache behavior.
  []
end

.run(entries, logger: Hyperion.logger) ⇒ Object

Walk each ‘entry` and populate the page cache. `entries` is an Array of `immutable:` Hashes. Returns the total file count cached across all dirs.

‘logger` defaults to `Hyperion.logger` so callers in production don’t have to thread one through; the spec suite passes an in-memory ‘Hyperion::Logger` so it can assert on the summary log line without disturbing the global Runtime logger.



45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/hyperion/static_preload.rb', line 45

def run(entries, logger: Hyperion.logger)
  return 0 if entries.nil? || entries.empty?
  return 0 unless Hyperion::Http::PageCache.available?

  total = 0
  entries.each do |entry|
    path      = entry[:path]
    immutable = entry.fetch(:immutable, true)

    unless File.directory?(path)
      logger.warn { { message: 'static preload skipped', dir: path, reason: 'not a directory' } }
      next
    end

    stats = preload_dir(path, immutable: immutable)
    total += stats[:files]
    logger.info do
      {
        message: 'static preload complete',
        dir: path,
        files: stats[:files],
        bytes: stats[:bytes],
        ms: stats[:ms]
      }
    end
  end
  total
end