From b4e11287d2f216100c76c372019d2ccf4b15ee53 Mon Sep 17 00:00:00 2001 From: Gaurav Tiwari Date: Tue, 8 Sep 2026 14:49:46 +0100 Subject: [PATCH] Show slow Dagger startup status --- CHANGELOG.md | 4 ++++ lib/dagger_ruby/progress_runner.rb | 29 +++++++++++++++++++++++++---- test/unit/test_progress_runner.rb | 27 +++++++++++++++++++++++++++ 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2944d48..f4418f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ All notable changes are recorded here. The format follows ## [Unreleased] +### Fixed + +- Show an engine startup status in pretty progress mode when Dagger takes more than one second to start. + ## [0.11.0] - 2026-08-27 ### Added diff --git a/lib/dagger_ruby/progress_runner.rb b/lib/dagger_ruby/progress_runner.rb index 42cc136..0e4c1e1 100644 --- a/lib/dagger_ruby/progress_runner.rb +++ b/lib/dagger_ruby/progress_runner.rb @@ -6,6 +6,7 @@ module DaggerRuby class ProgressRunner DAGGER_EXEC_HEADING = /\A(?:\e\[[0-9;]*m)*▼ withExec\b/ INTERRUPT_TIMEOUT = 1 + STARTUP_NOTICE_DELAY = 1 TERMINATION_TIMEOUT = 1 def initialize(out: $stderr, result_out: $stdout, environment: ENV) @@ -35,6 +36,7 @@ def run(command, environment: {}) ) primary_writer.close dagger_writer.close + startup_notice = report_slow_startup _, status = Process.wait2(pid) clean_process_group(pid) server.close @@ -56,6 +58,7 @@ def run(command, environment: {}) stop_thread(listener) stop_thread(primary_reader) stop_thread(output_reader) + stop_thread(startup_notice) end end @@ -66,8 +69,7 @@ def listen(server) socket = server.accept renderer = Progress.new(out: @out, color: color?) socket.each_line do |line| - renderer.render(JSON.parse(line)) - progress_started! + render_progress(renderer, JSON.parse(line)) socket.puts("ok") socket.flush end @@ -78,6 +80,18 @@ def listen(server) end end + def report_slow_startup + Thread.new do + sleep startup_notice_delay + @started_mutex.synchronize do + next if @started + + @out.puts "Dagger is still starting. It may be downloading the engine image." + @out.flush + end + end + end + def relay_dagger_output(input) Thread.new do buffered = [] @@ -111,8 +125,11 @@ def relay_primary_output(input) end end - def progress_started! - @started_mutex.synchronize { @started = true } + def render_progress(renderer, event) + @started_mutex.synchronize do + @started = true + renderer.render(event) + end end def reset_progress_state! @@ -208,6 +225,10 @@ def monotonic_time Process.clock_gettime(Process::CLOCK_MONOTONIC) end + def startup_notice_delay + STARTUP_NOTICE_DELAY + end + def exit_status(status) status.exitstatus || (128 + status.termsig) end diff --git a/test/unit/test_progress_runner.rb b/test/unit/test_progress_runner.rb index 4f6b941..9629d75 100644 --- a/test/unit/test_progress_runner.rb +++ b/test/unit/test_progress_runner.rb @@ -58,6 +58,33 @@ def test_hides_dagger_startup_and_exec_headings_in_pretty_mode refute_includes output.string, "withExec" end + def test_reports_slow_dagger_startup_before_application_progress + output = StringIO.new + runner = DaggerRuby::ProgressRunner.new(out: output, environment: {}) + runner.stubs(:startup_notice_delay).returns(0.01) + command = [ + RbConfig.ruby, + "-rjson", + "-rsocket", + "-e", + <<~RUBY, + sleep 0.05 + socket = UNIXSocket.new(ENV.fetch("DAGGER_RUBY_PROGRESS_SOCKET")) + socket.puts JSON.generate(type: "start", step: 1, name: "[build] RUN tests") + socket.gets + socket.close + RUBY + ] + + status = runner.run(command) + + assert_equal 0, status + assert_equal <<~OUTPUT, output.string + Dagger is still starting. It may be downloading the engine image. + #1 [build] RUN tests + OUTPUT + end + def test_preserves_dagger_errors_when_the_build_never_starts output = StringIO.new command = [RbConfig.ruby, "-e", 'warn "dagger: engine failed to start"; exit 1']