Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
29 changes: 25 additions & 4 deletions lib/dagger_ruby/progress_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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 = []
Expand Down Expand Up @@ -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!
Expand Down Expand Up @@ -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
Expand Down
27 changes: 27 additions & 0 deletions test/unit/test_progress_runner.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down