From d4d4c918d9a79f8dacb5319fc55da330ba10d1db Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Tue, 8 Sep 2026 11:17:46 -0400 Subject: [PATCH 1/4] Upgrade hotcell to 0.4.0 A killed worker left its tool's scratch files at the top of the cell's `/tmp`, outside the slot tree that is removed when a request ends, so the scratch volume filled over time. A worker now points `TMPDIR` at the request's home, and the supervisor empties the scratch at boot. That boot sweep is why the dev cell in `saas/Procfile.dev` now gets a `TMPDIR` of its own: unset, it would sweep the developer's `/tmp`. The release's ImageMagick changes do not reach this cell, which loads only the vips, ffprobe, mutool and ffmpeg operations and installs no ImageMagick, so the `MAGICK_*_LIMIT` variables stay unset. ref: https://github.com/basecamp/hotcell/blob/v0.4.0/CHANGELOG.md --- Gemfile.saas | 6 +++--- Gemfile.saas.lock | 20 ++++++++++---------- saas/Procfile.dev | 3 ++- saas/config/deploy.yml | 2 +- saas/hotcell/Gemfile | 4 ++-- saas/hotcell/Gemfile.lock | 32 ++++++++++++++++---------------- 6 files changed, 34 insertions(+), 33 deletions(-) diff --git a/Gemfile.saas b/Gemfile.saas index 7cf23b264c..58ab45c7a8 100644 --- a/Gemfile.saas +++ b/Gemfile.saas @@ -11,9 +11,9 @@ gem "console1984", bc: "console1984" gem "audits1984", bc: "audits1984" # Attachment processing in an unprivileged sibling container -gem "hotcell-client", "~> 0.3.1" -gem "activestorage-hotcell-client", "~> 0.3.1" -gem "mini_magick", require: false # activestorage-hotcell-client 0.3.1 loads the ImageMagick transformer even when unused +gem "hotcell-client", "~> 0.4.0" +gem "activestorage-hotcell-client", "~> 0.4.0" +gem "mini_magick", require: false # activestorage-hotcell-client loads the ImageMagick transformer even when unused # Native push notifications (iOS/Android) gem "action_push_native" diff --git a/Gemfile.saas.lock b/Gemfile.saas.lock index 900a3d950e..9999ad09a3 100644 --- a/Gemfile.saas.lock +++ b/Gemfile.saas.lock @@ -224,9 +224,9 @@ GEM activemodel (>= 7.0) activemodel-serializers-xml (~> 1.0) activesupport (>= 7.0) - activestorage-hotcell-client (0.3.1) + activestorage-hotcell-client (0.4.0) activestorage (>= 8.2.0.alpha) - hotcell-client (= 0.3.1) + hotcell-client (= 0.4.0) addressable (2.9.0) public_suffix (>= 2.0.2, < 8.0) ansi (1.6.0) @@ -343,10 +343,10 @@ GEM herb (0.10.3-x86_64-darwin) herb (0.10.3-x86_64-linux-gnu) herb (0.10.3-x86_64-linux-musl) - hotcell-client (0.3.1) + hotcell-client (0.4.0) activesupport (>= 7.1) - hotcell-core (= 0.3.1) - hotcell-core (0.3.1) + hotcell-core (= 0.4.0) + hotcell-core (0.4.0) http-2 (1.1.1) httpx (1.7.1) http-2 (>= 1.0.0) @@ -739,7 +739,7 @@ DEPENDENCIES action_push_native actionpack-xml_parser activeresource - activestorage-hotcell-client (~> 0.3.1) + activestorage-hotcell-client (~> 0.4.0) audits1984! autotuner aws-sdk-s3 @@ -755,7 +755,7 @@ DEPENDENCIES fizzy-saas! geared_pagination (~> 1.2) gvltools - hotcell-client (~> 0.3.1) + hotcell-client (~> 0.4.0) image_processing (~> 2.0) importmap-rails jbuilder @@ -825,7 +825,7 @@ CHECKSUMS activerecord (8.2.0.alpha) activeresource (6.2.0) sha256=818ca60d3cd1ff7bbb7277f41250ad4d61a7cdbe30fbf52b2145e1b66ed13900 activestorage (8.2.0.alpha) - activestorage-hotcell-client (0.3.1) sha256=57c62cf0825eddcb47970ffce4bae4d05ca1b63740a21b67f676313cc66a4cd7 + activestorage-hotcell-client (0.4.0) sha256=873a3c02d6c565bb2a7c5c5c2dfcb6370f98d05204d82a8a4adce52944f2a7b2 activesupport (8.2.0.alpha) addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af ansi (1.6.0) sha256=ac9ea0c0ea8d32fb4e271348e609963ac78882f34b73836c2a02b3622e666658 @@ -895,8 +895,8 @@ CHECKSUMS herb (0.10.3-x86_64-darwin) sha256=e02e43b3bb1977f4fd08f3330b5f2aa3292ca2d572a8bd59688eca8b79725f46 herb (0.10.3-x86_64-linux-gnu) sha256=cbb49b66f2bdc92d17109d1ea9452e88ba6a8ae52e9ddd5279deff83dcc4c66d herb (0.10.3-x86_64-linux-musl) sha256=c84482d6b57f13c2e1a0fa029649efb0e5fdc876a3fd564bae09cf42bd4d5ae1 - hotcell-client (0.3.1) sha256=bd1760634b532c660f1c37051eda20da2e0a4b0f8bfca239e04f5df1b4a32aff - hotcell-core (0.3.1) sha256=c72bc2b6d151a8bf22600eb2ad202b72baf6c5c454077684d63547db176c77ed + hotcell-client (0.4.0) sha256=baab7c5815ba7b8a9454f4f25fab3a1b188f71f1aa37b9b2df9946d089eba52b + hotcell-core (0.4.0) sha256=37ee907dbdfcea529be9c10b37c378b20cfb5fdccd3a06c7cd8c7d365104a9ee http-2 (1.1.1) sha256=1141a5a03c2f4e6b8d2fa62394de581e1ff6387711cd7ed577212e9d95562bba httpx (1.7.1) sha256=ae380461539203c92f3ee65c13b22dfccb0d975156426869f57820505cacdf56 i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5 diff --git a/saas/Procfile.dev b/saas/Procfile.dev index 2d7e7266a6..14b72897f3 100644 --- a/saas/Procfile.dev +++ b/saas/Procfile.dev @@ -1,4 +1,5 @@ # SaaS development: the app plus a hotcell cell beside it. This file lives here rather than in the root # Procfile.dev because the cell is SaaS-only and the open-source checkout must never boot one. web: bin/rails server -b 0.0.0.0 -p ${PORT:-3006} -cell: env -u RUBYOPT -u RUBYLIB -u BUNDLER_SETUP -u BUNDLER_VERSION -u BUNDLE_BIN_PATH -u BUNDLE_LOCKFILE BUNDLE_GEMFILE=$PWD/saas/hotcell/Gemfile HOTCELL_DIR=$PWD/tmp/hotcell/active_storage HOTCELL_CONFIG=$PWD/saas/hotcell/config.rb HOTCELL_OPERATIONS=$PWD/saas/hotcell/operations bundle exec hotcell +# TMPDIR is set because the supervisor sweeps the scratch at boot, and unset it would sweep /tmp. +cell: mkdir -p $PWD/tmp/hotcell/tmp && env -u RUBYOPT -u RUBYLIB -u BUNDLER_SETUP -u BUNDLER_VERSION -u BUNDLE_BIN_PATH -u BUNDLE_LOCKFILE BUNDLE_GEMFILE=$PWD/saas/hotcell/Gemfile HOTCELL_DIR=$PWD/tmp/hotcell/active_storage TMPDIR=$PWD/tmp/hotcell/tmp HOTCELL_CONFIG=$PWD/saas/hotcell/config.rb HOTCELL_OPERATIONS=$PWD/saas/hotcell/operations bundle exec hotcell diff --git a/saas/config/deploy.yml b/saas/config/deploy.yml index c94da0ffdb..fa6d13ed38 100644 --- a/saas/config/deploy.yml +++ b/saas/config/deploy.yml @@ -74,7 +74,7 @@ accessories: # would make what a host runs depend on when it last rebooted. saas/hotcell/bin/build writes this line; # saas/hotcell/bin/push publishes the tag. Until push has run the pull fails loudly, which is the right # way for an unbuilt image to fail. - image: registry.37signals.com/basecamp/fizzy-hotcell:d5cf91821660 + image: registry.37signals.com/basecamp/fizzy-hotcell:684eb866cdda roles: [ web, jobs ] # a descriptor cannot cross machines, so a cell lives on its caller's host # An accessory's own key, not one of the options below. Kamal always emits a --network of its own, # defaulting to `kamal`, so the same setting under `options:` is a second --network flag and Docker diff --git a/saas/hotcell/Gemfile b/saas/hotcell/Gemfile index 7cdc4e5c00..c9202b313f 100644 --- a/saas/hotcell/Gemfile +++ b/saas/hotcell/Gemfile @@ -9,5 +9,5 @@ source "https://rubygems.org" -gem "hotcell-server", "~> 0.3.1" -gem "activestorage-hotcell-server", "~> 0.3.1" +gem "hotcell-server", "~> 0.4.0" +gem "activestorage-hotcell-server", "~> 0.4.0" diff --git a/saas/hotcell/Gemfile.lock b/saas/hotcell/Gemfile.lock index 8b8c84d03d..c81a87b7f2 100644 --- a/saas/hotcell/Gemfile.lock +++ b/saas/hotcell/Gemfile.lock @@ -1,10 +1,10 @@ GEM remote: https://rubygems.org/ specs: - activestorage-hotcell-server (0.3.1) - hotcell-server (= 0.3.1) - image_processing (>= 2.0) - mini_magick (>= 5.2.0) + activestorage-hotcell-server (0.4.0) + hotcell-server (= 0.4.0) + image_processing (>= 2.1.0) + mini_magick (>= 5.4.0) ruby-vips (>= 2.2.1) ffi (1.17.4) ffi (1.17.4-aarch64-linux-gnu) @@ -17,12 +17,12 @@ GEM ffi (1.17.4-x86_64-darwin) ffi (1.17.4-x86_64-linux-gnu) ffi (1.17.4-x86_64-linux-musl) - hotcell-core (0.3.1) - hotcell-server (0.3.1) - hotcell-core (= 0.3.1) - image_processing (2.0.3) + hotcell-core (0.4.0) + hotcell-server (0.4.0) + hotcell-core (= 0.4.0) + image_processing (2.1.0) logger (1.7.0) - mini_magick (5.3.3) + mini_magick (5.4.0) logger ruby-vips (2.3.0) ffi (~> 1.12) @@ -42,11 +42,11 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES - activestorage-hotcell-server (~> 0.3.1) - hotcell-server (~> 0.3.1) + activestorage-hotcell-server (~> 0.4.0) + hotcell-server (~> 0.4.0) CHECKSUMS - activestorage-hotcell-server (0.3.1) sha256=660839dc4ef34b7b5cc0b4b8733bc5b90b6667a469eee72ff2c07a41c7703935 + activestorage-hotcell-server (0.4.0) sha256=cd2eee5cb3fb03761b4527a03d67b91e0c798f73463d1522c98f45d5334ba601 bundler (4.0.18) sha256=02d9a17429de1847b4e0c9f27a9ee4b20c0a74c0a641b4e77195d6019e3618ac ffi (1.17.4) sha256=bcd1642e06f0d16fc9e09ac6d49c3a7298b9789bcb58127302f934e437d60acf ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df @@ -59,11 +59,11 @@ CHECKSUMS ffi (1.17.4-x86_64-darwin) sha256=aa70390523cf3235096cf64962b709b4cfbd5c082a2cb2ae714eb0fe2ccda496 ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e - hotcell-core (0.3.1) sha256=c72bc2b6d151a8bf22600eb2ad202b72baf6c5c454077684d63547db176c77ed - hotcell-server (0.3.1) sha256=170b68343d30c325392d86b24263507a69b2790e8e0a31a1e7063a2e0da89614 - image_processing (2.0.3) sha256=793e33f38470edd0a2d6bfd00acf8cb239c76284ba2e3dfb76633ac2b457f23a + hotcell-core (0.4.0) sha256=37ee907dbdfcea529be9c10b37c378b20cfb5fdccd3a06c7cd8c7d365104a9ee + hotcell-server (0.4.0) sha256=6134245a7da611722c2de37e12ab0d0962fc97a5ab5dd2545c3c5f21f144d66b + image_processing (2.1.0) sha256=ca3814b1b909fc5fab68b261c50eaffef11e29a6907143e9cf1efc14b6dc6f47 logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 - mini_magick (5.3.3) sha256=b3beed8a8cef36bd03666365f14b89cd344da0ecd373af53e617c71bfd426aab + mini_magick (5.4.0) sha256=f120af581d9ed4ec52c57f35a67a605d112bb1d8f582d1415b147fda42d11d78 ruby-vips (2.3.0) sha256=e685ec02c13969912debbd98019e50492e12989282da5f37d05f5471442f5374 BUNDLED WITH From 08a331c79320538261c041205e5ca8e99ce78807 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Tue, 8 Sep 2026 11:17:47 -0400 Subject: [PATCH 2/4] Log what a failed cell tool wrote to stderr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A crash's diagnosis — `libgomp: Thread creation failed` — survived only in the exception's message, so a failure that was discarded rather than retried lost it. hotcell 0.4.0 carries the captured stream on the `perform.hot_cell` event; write it as a field on the existing log line. ref: https://github.com/basecamp/hotcell/pull/60 --- saas/lib/yabeda/hot_cell.rb | 1 + saas/test/lib/yabeda/hot_cell_test.rb | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/saas/lib/yabeda/hot_cell.rb b/saas/lib/yabeda/hot_cell.rb index 2934f44578..8bc5e9162d 100644 --- a/saas/lib/yabeda/hot_cell.rb +++ b/saas/lib/yabeda/hot_cell.rb @@ -78,6 +78,7 @@ def self.record_perform(event) ::Rails.logger.info " HotCell (#{duration_ms}ms) " + labels.merge( code: code || "ok", cause: event.payload[:cause], + stderr: event.payload[:stderr], perform_ms: event.payload[:perform_ms], duration_ms: duration_ms, bytes_in: event.payload[:bytes_in], diff --git a/saas/test/lib/yabeda/hot_cell_test.rb b/saas/test/lib/yabeda/hot_cell_test.rb index b3412d9600..7cfdf6c61b 100644 --- a/saas/test/lib/yabeda/hot_cell_test.rb +++ b/saas/test/lib/yabeda/hot_cell_test.rb @@ -107,6 +107,12 @@ class Yabeda::HotCellTest < ActiveSupport::TestCase assert_equal "fsize", logged["cause"] end + test "logs what a failed tool wrote to stderr" do + Yabeda::HotCell.record_perform perform_event(code: "killed", cause: "signal", stderr: "libgomp: Thread creation failed") + + assert_equal "libgomp: Thread creation failed", logged["stderr"] + end + test "does not report a failure to Sentry, because the raise already does" do Rails.error.expects(:report).never @@ -136,11 +142,11 @@ def stub_cell_metrics(counters) # duration_ms is measured by the event itself, not carried in the payload, so faking it takes the # same start/finish the real event has. - def perform_event(code: nil, perform_ms: 0, cause: nil, duration_ms: 0, bytes_in: nil, bytes_out: nil) + def perform_event(code: nil, perform_ms: 0, cause: nil, stderr: nil, duration_ms: 0, bytes_in: nil, bytes_out: nil) start = Time.now ActiveSupport::Notifications::Event.new("perform.hot_cell", start, start + duration_ms / 1000.0, nil, { cell: Fizzy::Saas::Cell::NAME, operation: "active_storage.transformers.image.vips", - code: code, cause: cause, perform_ms: perform_ms, bytes_in: bytes_in, bytes_out: bytes_out }) + code: code, cause: cause, stderr: stderr, perform_ms: perform_ms, bytes_in: bytes_in, bytes_out: bytes_out }) end def logged From aa81d668ad3811813c21273e48283e6875630d96 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Tue, 8 Sep 2026 14:29:40 -0400 Subject: [PATCH 3/4] Upgrade hotcell to 0.4.1 and boot the dev cell with --development The 0.4.0 dev cell needed a `TMPDIR` of its own, made by hand, or its boot sweep emptied the developer's `/tmp`. hotcell 0.4.1 adds `hotcell --development`, which keeps the scratch in a directory of the cell's own under the system temporary directory and never sweeps the directory it was given. Use it in `saas/Procfile.dev` instead. ref: https://github.com/basecamp/hotcell/pull/61 --- Gemfile.saas.lock | 16 ++++++++-------- saas/Procfile.dev | 3 +-- saas/config/deploy.yml | 2 +- saas/hotcell/Gemfile.lock | 16 ++++++++-------- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Gemfile.saas.lock b/Gemfile.saas.lock index 9999ad09a3..1be909a6d9 100644 --- a/Gemfile.saas.lock +++ b/Gemfile.saas.lock @@ -224,9 +224,9 @@ GEM activemodel (>= 7.0) activemodel-serializers-xml (~> 1.0) activesupport (>= 7.0) - activestorage-hotcell-client (0.4.0) + activestorage-hotcell-client (0.4.1) activestorage (>= 8.2.0.alpha) - hotcell-client (= 0.4.0) + hotcell-client (= 0.4.1) addressable (2.9.0) public_suffix (>= 2.0.2, < 8.0) ansi (1.6.0) @@ -343,10 +343,10 @@ GEM herb (0.10.3-x86_64-darwin) herb (0.10.3-x86_64-linux-gnu) herb (0.10.3-x86_64-linux-musl) - hotcell-client (0.4.0) + hotcell-client (0.4.1) activesupport (>= 7.1) - hotcell-core (= 0.4.0) - hotcell-core (0.4.0) + hotcell-core (= 0.4.1) + hotcell-core (0.4.1) http-2 (1.1.1) httpx (1.7.1) http-2 (>= 1.0.0) @@ -825,7 +825,7 @@ CHECKSUMS activerecord (8.2.0.alpha) activeresource (6.2.0) sha256=818ca60d3cd1ff7bbb7277f41250ad4d61a7cdbe30fbf52b2145e1b66ed13900 activestorage (8.2.0.alpha) - activestorage-hotcell-client (0.4.0) sha256=873a3c02d6c565bb2a7c5c5c2dfcb6370f98d05204d82a8a4adce52944f2a7b2 + activestorage-hotcell-client (0.4.1) sha256=46e09962ea839044241b026153c2c27b2f786ad929d4f8e493bcde1965244e1c activesupport (8.2.0.alpha) addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af ansi (1.6.0) sha256=ac9ea0c0ea8d32fb4e271348e609963ac78882f34b73836c2a02b3622e666658 @@ -895,8 +895,8 @@ CHECKSUMS herb (0.10.3-x86_64-darwin) sha256=e02e43b3bb1977f4fd08f3330b5f2aa3292ca2d572a8bd59688eca8b79725f46 herb (0.10.3-x86_64-linux-gnu) sha256=cbb49b66f2bdc92d17109d1ea9452e88ba6a8ae52e9ddd5279deff83dcc4c66d herb (0.10.3-x86_64-linux-musl) sha256=c84482d6b57f13c2e1a0fa029649efb0e5fdc876a3fd564bae09cf42bd4d5ae1 - hotcell-client (0.4.0) sha256=baab7c5815ba7b8a9454f4f25fab3a1b188f71f1aa37b9b2df9946d089eba52b - hotcell-core (0.4.0) sha256=37ee907dbdfcea529be9c10b37c378b20cfb5fdccd3a06c7cd8c7d365104a9ee + hotcell-client (0.4.1) sha256=45ad9c7e083a01df861d9906aa758efbd5dc1e2cf3fb6ba887b92bf57c14a019 + hotcell-core (0.4.1) sha256=5a5fff74264074122113a65080d09fe35d73bee6bed5c11e26562d050616eab6 http-2 (1.1.1) sha256=1141a5a03c2f4e6b8d2fa62394de581e1ff6387711cd7ed577212e9d95562bba httpx (1.7.1) sha256=ae380461539203c92f3ee65c13b22dfccb0d975156426869f57820505cacdf56 i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5 diff --git a/saas/Procfile.dev b/saas/Procfile.dev index 14b72897f3..bec20c87ae 100644 --- a/saas/Procfile.dev +++ b/saas/Procfile.dev @@ -1,5 +1,4 @@ # SaaS development: the app plus a hotcell cell beside it. This file lives here rather than in the root # Procfile.dev because the cell is SaaS-only and the open-source checkout must never boot one. web: bin/rails server -b 0.0.0.0 -p ${PORT:-3006} -# TMPDIR is set because the supervisor sweeps the scratch at boot, and unset it would sweep /tmp. -cell: mkdir -p $PWD/tmp/hotcell/tmp && env -u RUBYOPT -u RUBYLIB -u BUNDLER_SETUP -u BUNDLER_VERSION -u BUNDLE_BIN_PATH -u BUNDLE_LOCKFILE BUNDLE_GEMFILE=$PWD/saas/hotcell/Gemfile HOTCELL_DIR=$PWD/tmp/hotcell/active_storage TMPDIR=$PWD/tmp/hotcell/tmp HOTCELL_CONFIG=$PWD/saas/hotcell/config.rb HOTCELL_OPERATIONS=$PWD/saas/hotcell/operations bundle exec hotcell +cell: env -u RUBYOPT -u RUBYLIB -u BUNDLER_SETUP -u BUNDLER_VERSION -u BUNDLE_BIN_PATH -u BUNDLE_LOCKFILE BUNDLE_GEMFILE=$PWD/saas/hotcell/Gemfile HOTCELL_DIR=$PWD/tmp/hotcell/active_storage HOTCELL_CONFIG=$PWD/saas/hotcell/config.rb HOTCELL_OPERATIONS=$PWD/saas/hotcell/operations bundle exec hotcell --development diff --git a/saas/config/deploy.yml b/saas/config/deploy.yml index fa6d13ed38..76bf9da25d 100644 --- a/saas/config/deploy.yml +++ b/saas/config/deploy.yml @@ -74,7 +74,7 @@ accessories: # would make what a host runs depend on when it last rebooted. saas/hotcell/bin/build writes this line; # saas/hotcell/bin/push publishes the tag. Until push has run the pull fails loudly, which is the right # way for an unbuilt image to fail. - image: registry.37signals.com/basecamp/fizzy-hotcell:684eb866cdda + image: registry.37signals.com/basecamp/fizzy-hotcell:b7013561bf0a roles: [ web, jobs ] # a descriptor cannot cross machines, so a cell lives on its caller's host # An accessory's own key, not one of the options below. Kamal always emits a --network of its own, # defaulting to `kamal`, so the same setting under `options:` is a second --network flag and Docker diff --git a/saas/hotcell/Gemfile.lock b/saas/hotcell/Gemfile.lock index c81a87b7f2..6ba2f894d3 100644 --- a/saas/hotcell/Gemfile.lock +++ b/saas/hotcell/Gemfile.lock @@ -1,8 +1,8 @@ GEM remote: https://rubygems.org/ specs: - activestorage-hotcell-server (0.4.0) - hotcell-server (= 0.4.0) + activestorage-hotcell-server (0.4.1) + hotcell-server (= 0.4.1) image_processing (>= 2.1.0) mini_magick (>= 5.4.0) ruby-vips (>= 2.2.1) @@ -17,9 +17,9 @@ GEM ffi (1.17.4-x86_64-darwin) ffi (1.17.4-x86_64-linux-gnu) ffi (1.17.4-x86_64-linux-musl) - hotcell-core (0.4.0) - hotcell-server (0.4.0) - hotcell-core (= 0.4.0) + hotcell-core (0.4.1) + hotcell-server (0.4.1) + hotcell-core (= 0.4.1) image_processing (2.1.0) logger (1.7.0) mini_magick (5.4.0) @@ -46,7 +46,7 @@ DEPENDENCIES hotcell-server (~> 0.4.0) CHECKSUMS - activestorage-hotcell-server (0.4.0) sha256=cd2eee5cb3fb03761b4527a03d67b91e0c798f73463d1522c98f45d5334ba601 + activestorage-hotcell-server (0.4.1) sha256=00a7d7691d2f03ca3dd4ad455fc1cf79b61cb7d37974f737e6e08e8ee8660f77 bundler (4.0.18) sha256=02d9a17429de1847b4e0c9f27a9ee4b20c0a74c0a641b4e77195d6019e3618ac ffi (1.17.4) sha256=bcd1642e06f0d16fc9e09ac6d49c3a7298b9789bcb58127302f934e437d60acf ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df @@ -59,8 +59,8 @@ CHECKSUMS ffi (1.17.4-x86_64-darwin) sha256=aa70390523cf3235096cf64962b709b4cfbd5c082a2cb2ae714eb0fe2ccda496 ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e - hotcell-core (0.4.0) sha256=37ee907dbdfcea529be9c10b37c378b20cfb5fdccd3a06c7cd8c7d365104a9ee - hotcell-server (0.4.0) sha256=6134245a7da611722c2de37e12ab0d0962fc97a5ab5dd2545c3c5f21f144d66b + hotcell-core (0.4.1) sha256=5a5fff74264074122113a65080d09fe35d73bee6bed5c11e26562d050616eab6 + hotcell-server (0.4.1) sha256=9badf6200106b878c2280ebd0ec4d655f977f3a4e24684466a6c8054e05a3e20 image_processing (2.1.0) sha256=ca3814b1b909fc5fab68b261c50eaffef11e29a6907143e9cf1efc14b6dc6f47 logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 mini_magick (5.4.0) sha256=f120af581d9ed4ec52c57f35a67a605d112bb1d8f582d1415b147fda42d11d78 From 9bf9bd88bab40c005477e5da88583f13b0e3c2f1 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Tue, 8 Sep 2026 15:08:08 -0400 Subject: [PATCH 4/4] Pin the hotcell gems to exact versions A `~>` pin let a patch release move the app's client and the cell's server independently, and one version apart is a `protocol` failure on every request. Pin both Gemfiles to `0.4.1`. --- Gemfile.saas | 4 ++-- Gemfile.saas.lock | 4 ++-- saas/config/deploy.yml | 2 +- saas/hotcell/Gemfile | 4 ++-- saas/hotcell/Gemfile.lock | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Gemfile.saas b/Gemfile.saas index 58ab45c7a8..52251a26d5 100644 --- a/Gemfile.saas +++ b/Gemfile.saas @@ -11,8 +11,8 @@ gem "console1984", bc: "console1984" gem "audits1984", bc: "audits1984" # Attachment processing in an unprivileged sibling container -gem "hotcell-client", "~> 0.4.0" -gem "activestorage-hotcell-client", "~> 0.4.0" +gem "hotcell-client", "0.4.1" +gem "activestorage-hotcell-client", "0.4.1" gem "mini_magick", require: false # activestorage-hotcell-client loads the ImageMagick transformer even when unused # Native push notifications (iOS/Android) diff --git a/Gemfile.saas.lock b/Gemfile.saas.lock index 1be909a6d9..ce65d27857 100644 --- a/Gemfile.saas.lock +++ b/Gemfile.saas.lock @@ -739,7 +739,7 @@ DEPENDENCIES action_push_native actionpack-xml_parser activeresource - activestorage-hotcell-client (~> 0.4.0) + activestorage-hotcell-client (= 0.4.1) audits1984! autotuner aws-sdk-s3 @@ -755,7 +755,7 @@ DEPENDENCIES fizzy-saas! geared_pagination (~> 1.2) gvltools - hotcell-client (~> 0.4.0) + hotcell-client (= 0.4.1) image_processing (~> 2.0) importmap-rails jbuilder diff --git a/saas/config/deploy.yml b/saas/config/deploy.yml index 76bf9da25d..cb2c7b074e 100644 --- a/saas/config/deploy.yml +++ b/saas/config/deploy.yml @@ -74,7 +74,7 @@ accessories: # would make what a host runs depend on when it last rebooted. saas/hotcell/bin/build writes this line; # saas/hotcell/bin/push publishes the tag. Until push has run the pull fails loudly, which is the right # way for an unbuilt image to fail. - image: registry.37signals.com/basecamp/fizzy-hotcell:b7013561bf0a + image: registry.37signals.com/basecamp/fizzy-hotcell:2f4ddc90eae3 roles: [ web, jobs ] # a descriptor cannot cross machines, so a cell lives on its caller's host # An accessory's own key, not one of the options below. Kamal always emits a --network of its own, # defaulting to `kamal`, so the same setting under `options:` is a second --network flag and Docker diff --git a/saas/hotcell/Gemfile b/saas/hotcell/Gemfile index c9202b313f..857127ba4c 100644 --- a/saas/hotcell/Gemfile +++ b/saas/hotcell/Gemfile @@ -9,5 +9,5 @@ source "https://rubygems.org" -gem "hotcell-server", "~> 0.4.0" -gem "activestorage-hotcell-server", "~> 0.4.0" +gem "hotcell-server", "0.4.1" +gem "activestorage-hotcell-server", "0.4.1" diff --git a/saas/hotcell/Gemfile.lock b/saas/hotcell/Gemfile.lock index 6ba2f894d3..eca02cd98c 100644 --- a/saas/hotcell/Gemfile.lock +++ b/saas/hotcell/Gemfile.lock @@ -42,8 +42,8 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES - activestorage-hotcell-server (~> 0.4.0) - hotcell-server (~> 0.4.0) + activestorage-hotcell-server (= 0.4.1) + hotcell-server (= 0.4.1) CHECKSUMS activestorage-hotcell-server (0.4.1) sha256=00a7d7691d2f03ca3dd4ad455fc1cf79b61cb7d37974f737e6e08e8ee8660f77