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
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- DISCOVERY_DEADLINE_SECONDS =
10- FETCH_DEADLINE_SECONDS =
30- 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
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/react_on_rails_pro/rolling_deploy_adapters/http.rb', line 106 def fetch(bundle_hash) bases = configured_previous_urls return nil if bases.empty? return nil if hash_invalid?(bundle_hash) if token_missing? return warn_and_return( "rolling_deploy_token is not configured; skipping fetch(#{bundle_hash.inspect})", nil ) end candidates = fetch_candidates(bundle_hash, bases) return nil if candidates.empty? dir = bundle_dir(bundle_hash) result = fetch_from_candidates(bundle_hash, candidates, dir) return result if result cleanup_and_return(dir, nil) rescue StandardError => e cleanup_and_return(dir, nil) if dir warn_and_return("fetch(#{bundle_hash.inspect}) failed: #{e.class}: #{e.}", nil) end |
.previous_bundle_hashes ⇒ Object
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/react_on_rails_pro/rolling_deploy_adapters/http.rb', line 87 def previous_bundle_hashes bases = configured_previous_urls if bases.empty? @discovery_provenance = nil return [] end if token_missing? @discovery_provenance = nil return warn_and_return("rolling_deploy_token is not configured; skipping manifest fetch", []) end provenance = discover_provenance(bases) @discovery_provenance = provenance provenance.keys.select { |hash| publishable_provenance?(hash, provenance.fetch(hash)) } rescue StandardError => e @discovery_provenance = nil warn_and_return("previous_bundle_hashes failed: #{e.class}: #{e.}", []) 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.
135 136 137 |
# File 'lib/react_on_rails_pro/rolling_deploy_adapters/http.rb', line 135 def upload(_bundle_hash, bundle:, assets:) # See class doc above. end |