4

I've got an issue with Ruby. Specifically, the spawn() and fork() methods.

I'm developing a website using Nanoc on Windows, and upon trying to implement the nanoc-live gem, I get the message that fork() is unimplemented on this machine.

Upon researching what I could about this, the only thing I really came back with, was to replace it with spawn(). However, I don't know Ruby. And the nanoc-live documentation is down. I have asked on what support forums they have with no luck.

I don't ask how to do this lightly because I like figuring out issues but this has me stumped, and I'm hardly a Ruby dev. How would I replace the below method call so it uses spawn()? Or, if someone has a different solution in their back pocket, that would also be great.

Ruby version 3.2.2
Nanoc version 4.12.15
Windows 10

This is the offending method

      def run_parent
        # create initial child
        pipe_read, pipe_write = IO.pipe
        fork { run_child(pipe_write, pipe_read) { |s| yield(s) } }  Here is the method call
        pipe_read.close

        changes = gen_lib_changes
        puts 'Listening for lib/ changes…'
        changes.each do |_e|
          # stop child
          pipe_write.write('q')
          pipe_write.close
          Process.wait

          # create new child
          pipe_read, pipe_write = IO.pipe
          fork { run_child(pipe_write, pipe_read) { |s| yield(s) } }
          pipe_read.close
        end
      rescue Interrupt
      end

And this is the run_child method called by fork()

def run_child(pipe_write, pipe_read)
        pipe_write.close

        site = Nanoc::Core::SiteLoader.new.new_from_cwd
        changes_enum = gen_changes_for_child(site)
        yield(site)

        quit = Object.new
        parent_enum = Enumerator.new do |y|
          pipe_read.read
          y << quit
        end

        puts 'Listening for site changes…'
        SlowEnumeratorTools.merge([parent_enum, changes_enum]).each do |e|
          break if quit.equal?(e)

          $stderr.print 'Reloading site… '
          $stderr.flush
          site_loader = Nanoc::Core::SiteLoader.new
          site = Nanoc::Core::Site.new(
            config: Nanoc::Core::ConfigLoader.new.new_from_cwd,
            data_source: site_loader.gen_data_source_for_config(site.config),
            code_snippets: site.code_snippets,
          )
          $stderr.puts 'done'

          yield(site)
        end

        exit 0
      rescue Interrupt
        exit 0
      end

Thanks In Advance.

TechnicalTophat
  • 1,655
  • 1
  • 15
  • 37

2 Answers2

1

You can use spawn like this to achieve what you want. However, as the answer details, process spawning like this in Windows is not optimal. You should consider threads.

spawn() docs if you didn't have them already

amycodes
  • 902
  • 14
  • All the linked question has done is made me question life more. But thank you. Changing production source code to use threading for windows compatibility. Sigh. – TechnicalTophat Jun 05 '23 at 04:23
1

Firstly, Linux supports forking, but Windows does not; Windows only supports spawning:

  • forking = a parent process creates a copy of itself (a child) that has an exact copy of all the memory segments it uses

  • spawning = a parent process creates an entirely new child process that does not share its memory and the parent process must wait for the child process to finish before continuing

To be clear, this is an issue fundamental to the Windows operating system in general and not to any specific programming language, including Ruby. For instance, I have run into an issue regarding this here when using Python.

Thus, the answer in the link provided by @amycodes unfortunately contains accurate information.

To mimic fork, you will have to spawn a new process/thread and then copy your data to the new process/thread. You will have to also check if your data can be copied in a threadsafe manner (e.g. generators cannot be marshaled across process boundaries in Python, and you are using a yield in your source code, which makes me think what you want to do might not be possible). Since you are replacing a built-in operation in Linux OS's with a process/thread create plus a copy, please note that this will run slower than it does on Linux (such is the price to be paid for using Windows).

I am not particularly well-versed in Ruby, so I'm hoping someone else can double-check my answer.

(Best of luck my friend!)

adam.hendry
  • 4,458
  • 5
  • 24
  • 51
  • Keep ChatGPT responses out of your answer. It's strictly prohibited, even if you acknowledge that the following content is AI generated. – kelsny Jun 04 '23 at 18:42
  • @zenly I did not realize. I will remove it. Can you please elaborate why ChatGPT is prohibited? Are there `stackoverflow` rules/guidelines that state this somewhere? – adam.hendry Jun 04 '23 at 18:44
  • 1
    It's pinned on the right side under "Hot Meta Posts": https://meta.stackoverflow.com/questions/421831/temporary-policy-chatgpt-is-banned?cb=1 – kelsny Jun 04 '23 at 23:17