From daa914b21435ceb0ff84f0e50c4fc0ee6858de14 Mon Sep 17 00:00:00 2001 From: Schneems Date: Mon, 16 Dec 2024 11:10:20 -0600 Subject: [PATCH] Make background tasks lazy Previously when a background task was defined it would perform work on initialization, this fails if the first task is not actually executed yet: ```term :::>- pre.erb background.start('heroku run:inside <%= dyno_ps_name %> "bash"', wait: "$", timeout: 120, name: "heroku_run") :::-- background.stdin_write("ls -lah", name: "heroku_run", wait: "$", timeout: 30) :::-- background.stdin_write("exit", name: "heroku_run", wait: "exit") :::-> background.stop(name: "heroku_run") ``` Gives: ``` /Users/rschneeman/.gem/ruby/3.3.1/gems/rundoc-4.1.1/lib/rundoc/code_command/background/process_spawn.rb:41:in `find': Could not find task with name "heroku_run", known task names: [] (RuntimeError) from /Users/rschneeman/.gem/ruby/3.3.1/gems/rundoc-4.1.1/lib/rundoc/code_command/background/stdin_write.rb:9:in `initialize' from /Users/rschneeman/.gem/ruby/3.3.1/gems/rundoc-4.1.1/lib/rundoc.rb:13:in `new' from /Users/rschneeman/.gem/ruby/3.3.1/gems/rundoc-4.1.1/lib/rundoc.rb:13:in `code_command_from_keyword' from /Users/rschneeman/.gem/ruby/3.3.1/gems/rundoc-4.1.1/lib/rundoc/peg_parser.rb:210:in `block in ' from /Users/rschneeman/.gem/ruby/3.3.1/gems/parslet-2.0.0/lib/parslet/transform.rb:217:in `instance_eval' from /Users/rschneeman/.gem/ruby/3.3.1/gems/parslet-2.0.0/lib/parslet/transform.rb:217:in `call_on_match' from /Users/rschneeman/.gem/ruby/3.3.1/gems/parslet-2.0.0/lib/parslet/transform.rb:235:in `block in transform_elt' from /Users/rschneeman/.gem/ruby/3.3.1/gems/parslet-2.0.0/lib/parslet/transform.rb:232:in `each' ``` Because the `background.stdin_write` call to `new()` happens at parse time, but the `background.start` call to `new()` happens at runtime, (Because `pre.erb` is the command, and it hasn't yet created the start command and pushed it onto the stack). This change makes the lookup for background tasks lazy, so as long as the task is started by execution (runtime) of the command it will succeed. --- .../code_command/background/log/clear.rb | 9 ++++- .../code_command/background/log/read.rb | 9 ++++- lib/rundoc/code_command/background/start.rb | 38 ++++++++++++------- .../code_command/background/stdin_write.rb | 11 ++++-- lib/rundoc/code_command/background/stop.rb | 11 ++++-- lib/rundoc/code_command/background/wait.rb | 9 ++++- 6 files changed, 61 insertions(+), 26 deletions(-) diff --git a/lib/rundoc/code_command/background/log/clear.rb b/lib/rundoc/code_command/background/log/clear.rb index 470d1ef..c583baf 100644 --- a/lib/rundoc/code_command/background/log/clear.rb +++ b/lib/rundoc/code_command/background/log/clear.rb @@ -1,7 +1,12 @@ class Rundoc::CodeCommand::Background::Log class Clear < Rundoc::CodeCommand def initialize(name:) - @spawn = Rundoc::CodeCommand::Background::ProcessSpawn.find(name) + @name = name + @background = nil + end + + def background + @background ||= Rundoc::CodeCommand::Background::ProcessSpawn.find(@name) end def to_md(env = {}) @@ -9,7 +14,7 @@ def to_md(env = {}) end def call(env = {}) - @spawn.log.truncate(0) + background.log.truncate(0) "" end end diff --git a/lib/rundoc/code_command/background/log/read.rb b/lib/rundoc/code_command/background/log/read.rb index d80dd29..eaddc05 100644 --- a/lib/rundoc/code_command/background/log/read.rb +++ b/lib/rundoc/code_command/background/log/read.rb @@ -1,7 +1,12 @@ class Rundoc::CodeCommand::Background::Log class Read < Rundoc::CodeCommand def initialize(name:) - @spawn = Rundoc::CodeCommand::Background::ProcessSpawn.find(name) + @name = name + @background = nil + end + + def background + @background ||= Rundoc::CodeCommand::Background::ProcessSpawn.find(@name) end def to_md(env = {}) @@ -9,7 +14,7 @@ def to_md(env = {}) end def call(env = {}) - @spawn.log.read + background.log.read end end end diff --git a/lib/rundoc/code_command/background/start.rb b/lib/rundoc/code_command/background/start.rb index 4324987..9eda8b8 100644 --- a/lib/rundoc/code_command/background/start.rb +++ b/lib/rundoc/code_command/background/start.rb @@ -3,20 +3,30 @@ class Rundoc::CodeCommand::Background class Start < Rundoc::CodeCommand def initialize(command, name:, wait: nil, timeout: 5, log: Tempfile.new("log"), out: "2>&1", allow_fail: false) + @timeout = timeout @command = command @name = name @wait = wait @allow_fail = allow_fail - FileUtils.touch(log) - - @spawn = ProcessSpawn.new( - @command, - timeout: timeout, - log: log, - out: out - ) - puts "Spawning commmand: `#{@spawn.command}`" - ProcessSpawn.add(@name, @spawn) + @log = log + @redirect = out + FileUtils.touch(@log) + + @background = nil + end + + def background + @background ||= begin + ProcessSpawn.new( + @command, + timeout: @timeout, + log: @log, + out: @redirect + ).tap do |spawn| + puts "Spawning commmand: `#{spawn.command}`" + ProcessSpawn.add(@name, spawn) + end + end end def to_md(env = {}) @@ -24,14 +34,14 @@ def to_md(env = {}) end def call(env = {}) - @spawn.wait(@wait) - @spawn.check_alive! unless @allow_fail + background.wait(@wait) + background.check_alive! unless @allow_fail - @spawn.log.read + background.log.read end def alive? - !!@spawn.alive? + !!background.alive? end end end diff --git a/lib/rundoc/code_command/background/stdin_write.rb b/lib/rundoc/code_command/background/stdin_write.rb index 6164471..089af3a 100644 --- a/lib/rundoc/code_command/background/stdin_write.rb +++ b/lib/rundoc/code_command/background/stdin_write.rb @@ -6,10 +6,15 @@ class StdinWrite < Rundoc::CodeCommand def initialize(contents, name:, wait:, timeout: 5, ending: $/) @contents = contents @ending = ending - @spawn = Rundoc::CodeCommand::Background::ProcessSpawn.find(name) @wait = wait + @name = name @timeout_value = Integer(timeout) @contents_written = nil + @background = nil + end + + def background + @background ||= Rundoc::CodeCommand::Background::ProcessSpawn.find(@name) end # The command is rendered (`:::>-`) by the output of the `def call` method. @@ -20,11 +25,11 @@ def to_md(env = {}) # The contents produced by the command (`:::->`) are rendered by the `def to_md` method. def call(env = {}) writecontents - @spawn.log.read + background.log.read end def writecontents - @contents_written ||= @spawn.stdin_write( + @contents_written ||= background.stdin_write( contents, wait: @wait, ending: @ending, diff --git a/lib/rundoc/code_command/background/stop.rb b/lib/rundoc/code_command/background/stop.rb index 9349df4..70c6535 100644 --- a/lib/rundoc/code_command/background/stop.rb +++ b/lib/rundoc/code_command/background/stop.rb @@ -1,7 +1,12 @@ class Rundoc::CodeCommand::Background class Stop < Rundoc::CodeCommand def initialize(name:) - @spawn = Rundoc::CodeCommand::Background::ProcessSpawn.find(name) + @name = name + @background = nil + end + + def background + @background ||= Rundoc::CodeCommand::Background::ProcessSpawn.find(@name) end def to_md(env = {}) @@ -9,8 +14,8 @@ def to_md(env = {}) end def call(env = {}) - @spawn.stop - @spawn.log.read + background.stop + background.log.read end end end diff --git a/lib/rundoc/code_command/background/wait.rb b/lib/rundoc/code_command/background/wait.rb index 3b3de81..5de3747 100644 --- a/lib/rundoc/code_command/background/wait.rb +++ b/lib/rundoc/code_command/background/wait.rb @@ -1,9 +1,14 @@ class Rundoc::CodeCommand::Background class Wait < Rundoc::CodeCommand def initialize(name:, wait:, timeout: 5) - @spawn = Rundoc::CodeCommand::Background::ProcessSpawn.find(name) + @name = name @wait = wait @timeout_value = Integer(timeout) + @background = nil + end + + def background + @background ||= Rundoc::CodeCommand::Background::ProcessSpawn.find(name) end def to_md(env = {}) @@ -11,7 +16,7 @@ def to_md(env = {}) end def call(env = {}) - @spawn.wait(@wait, @timeout_value) + background.wait(@wait, @timeout_value) "" end end