Class: ReactOnRailsPro::RollingDeployAdapters::Http
- Inherits:
-
Object
- Object
- ReactOnRailsPro::RollingDeployAdapters::Http
- Defined in:
- lib/react_on_rails_pro/rolling_deploy_adapters/http.rb
Overview
Built-in HTTP rolling-deploy adapter. Pairs with ReactOnRailsPro::RollingDeploy::BundlesController on the running Rails server: the controller exposes the current deployment's bundles and the adapter (running in the next deployment's build CI) fetches them.
The promise is "zero-infra default": no S3 bucket, no IAM, no extra gem. The currently-deployed Rails server already has the bundles + companion assets sitting on disk; this adapter pulls them via authenticated HTTP.
Configuration (see docs/pro/rolling-deploy-adapters.md):
ReactOnRailsPro.configure do |config|
config.rolling_deploy_adapter = ReactOnRailsPro::RollingDeployAdapters::Http
config.rolling_deploy_token = ENV.fetch("ROLLING_DEPLOY_TOKEN")
config.rolling_deploy_previous_urls = ENV["ROLLING_DEPLOY_PREVIOUS_URLS"]
end
rolling_deploy_previous_urls accepts a single URL string, a comma-
separated string, or an Array of URL strings. Discovery unions the bundle
hashes advertised by every endpoint; fetch tries each endpoint in order and
returns the first that has the requested hash. Seeding from more than one
endpoint (e.g. staging + production) lets an image built in one environment
and promoted to another carry the promotion target's draining bundle. See
docs/pro/rolling-deploy-adapters.md#promotion-deploys-need-a-release-time-boot-seed.
Error contract matches the rolling_deploy_adapter protocol: every exception is caught and reported as a warning so a failed seed degrades to the runtime 410-retry fallback rather than failing the build. rubocop:disable Metrics/ClassLength
Constant Summary collapse
- DEFAULT_OPEN_TIMEOUT_SECONDS =
Per-request HTTP timeouts. The outer Timeout.timeout in RollingDeployCacheStager bounds the total wall-clock budget (10s for discovery, 30s for fetch); these inner timeouts let a hung server fail before the outer wrapper interrupts mid-write, which is more reliable than relying on the thread-level Timeout.timeout that may interrupt at a random execution point.
5- DEFAULT_READ_TIMEOUT_SECONDS =
25- MANIFEST_READ_TIMEOUT_SECONDS =
Manifest discovery is wrapped in a 10s outer budget by RollingDeployCacheStager.
4- DEFAULT_MAX_SIZE =
Maximum uncompressed payload accepted from /bundles/:hash. Mirrors the tarball helper default so a misbehaving or malicious server cannot exhaust disk via a zip-bomb-style response.
ReactOnRailsPro::RollingDeploy::Tarball::DEFAULT_MAX_SIZE
- COMPRESSED_BODY_CAP =
Maximum compressed bytes accepted from /bundles/:hash before extract enforces DEFAULT_MAX_SIZE on the uncompressed tarball contents. Set near 1/4 of DEFAULT_MAX_SIZE: JS bundles typically decompress 3-5x, so a 50 MB wire payload that decompresses beyond 200 MB is anomalous.
50 * 1024 * 1024
- LOG_PREFIX =
"[ReactOnRailsPro::RollingDeployAdapters::Http]"- BUNDLE_ENTRY_NAME =
Wire-format constant: must stay in sync with
ReactOnRailsPro::RollingDeploy::BundlesController::BUNDLE_ENTRY_NAME. The controller serves the bundle file under this entry name; if the two ever diverge the client will fail to locate the bundle after extracting the tarball. "bundle.js"
Class Method Summary collapse
- .fetch(bundle_hash) ⇒ Object
- .previous_bundle_hashes ⇒ Object
-
.upload(_bundle_hash, bundle:, assets:) ⇒ Object
Intentional no-op.
Class Method Details
.fetch(bundle_hash) ⇒ Object
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/react_on_rails_pro/rolling_deploy_adapters/http.rb', line 107 def fetch(bundle_hash) return nil if hash_invalid?(bundle_hash) bases = configured_previous_urls return nil if bases.empty? if token_missing? return warn_and_return("rolling_deploy_token is not configured; skipping fetch(#{bundle_hash.inspect})", nil) end # Try each endpoint in order; return the first that has the hash. A # given hash is content-addressed, so whichever endpoint serves it # returns identical bytes — first hit wins. bases.each do |base| payload = fetch_from(base, bundle_hash) return payload if payload end nil end |
.previous_bundle_hashes ⇒ Object
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/react_on_rails_pro/rolling_deploy_adapters/http.rb', line 91 def previous_bundle_hashes bases = configured_previous_urls return [] if bases.empty? if token_missing? return warn_and_return("rolling_deploy_token is not configured; skipping manifest fetch", []) end # Union across every configured endpoint. A single endpoint failing # (down, 404, malformed manifest) yields [] for that base and does not # abort discovery for the others — the point of multiple endpoints is # resilience, so one unreachable source must not blank the rest. bases.flat_map { |base| manifest_hashes(base) }.uniq end |
.upload(_bundle_hash, bundle:, assets:) ⇒ Object
Intentional no-op. The running Rails server IS the artifact store — bundle + companion assets are already on local disk where the mountable BundlesController will serve them on the next deploy's build CI. Documented in docs/pro/rolling-deploy-adapters.md.
132 133 134 |
# File 'lib/react_on_rails_pro/rolling_deploy_adapters/http.rb', line 132 def upload(_bundle_hash, bundle:, assets:) # See class doc above. end |