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-http-adapter.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_url = ENV["ROLLING_DEPLOY_PREVIOUS_URL"]
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.
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
- 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
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/react_on_rails_pro/rolling_deploy_adapters/http.rb', line 92 def fetch(bundle_hash) base = configured_previous_url return nil if base.nil? 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 dir = bundle_dir(bundle_hash) FileUtils.mkdir_p(dir) tarball_body = download_bundle_tarball(base, bundle_hash) return cleanup_and_return(dir, nil) if tarball_body.nil? extract_payload(tarball_body, dir, bundle_hash) 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
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/react_on_rails_pro/rolling_deploy_adapters/http.rb', line 62 def previous_bundle_hashes base = configured_previous_url return [] if base.nil? if token_missing? return warn_and_return("rolling_deploy_token is not configured; skipping manifest fetch", []) end response = http_get( URI("#{base}/manifest"), read_timeout: MANIFEST_READ_TIMEOUT_SECONDS ) return warn_and_return("manifest returned HTTP #{response.code}", []) unless response.is_a?(Net::HTTPSuccess) parsed = JSON.parse(response.body) # Filter manifest hashes through SAFE_HASH_PATTERN before returning # so server-supplied strings never appear verbatim in downstream # warning logs. Each hash is re-validated inside `fetch`, so this is # defense-in-depth — nothing unsafe could reach the filesystem layer # — but it keeps log lines from a misbehaving or compromised server # from echoing arbitrary content. Array(parsed["hashes"]) .map(&:to_s) .reject(&:empty?) .grep(ReactOnRailsPro::RollingDeploy::SAFE_HASH_PATTERN) rescue StandardError => e 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-http-adapter.md.
117 118 119 |
# File 'lib/react_on_rails_pro/rolling_deploy_adapters/http.rb', line 117 def upload(_bundle_hash, bundle:, assets:) # See class doc above. end |