Duc Le
Duc Le

Reputation: 31

RMagick (ImageMagick) hangs when run in a forked process

On an instance of Rails 3.0.0 with Ruby 1.8.7, I'm trying to push some image processing tasks using RMagick (2.13.0) into a separate process using fork(). However, the child process in which the image processing takes place ALWAYS hangs when Magick::Image.new, Magick::Image.crop, or Magick::Image.composite is called.

By "hanging" I mean the process just gets stuck at that particular command; it neither gets past that line nor throws any exception, and I have to manually kill the process. In addition, the child process doesn't seem to be using any additional memory when it gets stuck, which really makes me wonder what it's actually doing.

The relevant code looks somewhat like this: (this is not the actual code!)

def trigger_fork
    img_content = get_image_content
    p = Process.fork { process_image(img_content) }
    Process.detach(p)
    redirect_to root_path
end

def process_image(img_content)
    img = Magick::Image.from_blob(img_content)  # this works fine!
    composite_image(img)
end

def composite_image(img)
    # child process gets stuck here!!
    dummy = Magick::Image.new(100,100) { self.background_color = "white" }

    img.composite(dummy, 0, 0, Magick::XorCompositeOp)
end

If I replace Magick::Image.new with img.crop, the process will also hang! The interesting part is that if I disable forking and just run the process_image function in the same process as the caller, everything works just fine!

I've searched all over the Internet, but still can't figure out why this is happening. I'd really appreciate if someone can help me with this problem. Thanks!

Upvotes: 3

Views: 664

Answers (2)

Andrei Nistor
Andrei Nistor

Reputation: 535

I've had the same issue with a watermarking script.

I was generating the watermark image, then forking a few processes that composited the watermark over other images. The workers got stuck when calling composite. Moving the watermark generation code into the fork block fixed it for me.

As a rule of thumb, try to keep the code dealing with RMagick contained to a single process.

Note: this bug only bit me when I moved the code to production, everything worked fine on my workstation

Upvotes: 0

Ian
Ian

Reputation: 2108

If this is happening in a Rails process, I would guess that it has something to do with the way Ruby and RMagick handle memory. RMagick is known for having memory issues, and Rails is known for not being friendly to trying to do stuff like this.

I would strongly recommend a background job for this. If you have timing constraints, just add enough workers and resources that they get processed in a timely manner. Your problems with this approach won't stop once/if you solve this problem.

Upvotes: 1

Related Questions