Скрепка для памяти Jruby on Rails при выполнении вызовов ОС - PullRequest
0 голосов
/ 30 августа 2018

Я использую gem paperclip с jruby, у меня проблема с памятью из-за способа, которым paperclip выполняет вызовы ОС при работе в среде Java. Внутренне он использует gem terrapin для выполнения вызовов, и при работе на JVM он не поддерживает предоставленный ProccessRunner или PosixRunner, поэтому, когда вызов выполняется стандартным способом (обратные ссылки), процесс rails раздвоены обычным способом. Проблема в том, что когда происходит разветвление, стек из родительского процесса должен быть скопирован в дочерний процесс, что является проблемой в этой среде, потому что jruby слишком требователен к памяти.

PosixRunner поддерживается, если установлен gem posix-spawn , но он не совместим с jruby. Поэтому я пытаюсь адаптировать PosixRunner для создания SpoonRunner, который использует гем spoon , который совместим с jruby и делает то же самое, что и posix-spawn. Это хороший подход? Кто-то сделал это?

Проблема в том, что я не могу понять, как работать с файловыми дескрипторами, чтобы получить выходное значение выполняемой команды. Я был бы очень признателен за помощь с этим =)

Пожалуйста, проверьте комментарии к коду ниже:

module Terrapin
  class CommandLine
    class SpoonRunner
      def self.available?
        return @available unless @available.nil?

        @available = spoon_gem_available?
      end

      def self.supported?
        available?
      end

      def supported?
        self.class.supported?
      end

      def call(command, env = {}, options = {})
        pipe = MultiPipe.new
        pid = spawn(env, command, options.merge(pipe.pipe_options))
        pipe.read_and_then do
          waitpid(pid)
        end
        pipe.output
      end

      private

      def spawn(env, command, options)

        # spoon gem example
        # file_actions = Spoon::FileActions.new
        # file_actions.close(1)
        # the first argument is file_descriptor
        # file_actions.open(1, "/tmp/ls.out", File::WRONLY | File::TRUNC | File::CREAT, 0600)
        # spawn_attr = Spoon::SpawnAttributes.new
        # pid = Spoon.posix_spawn('/usr/bin/env', file_actions, spawn_attr, %w(env ls -R))

        puts "OPTIONS: #{options.inspect}"
        # OPTIONS: #<IO:fd 27>

        # why do I have to specify the file descriptor and the path, if the fd already exists
        # does it mean it is already associated to a path ? Is there a way I can use a random
        # one here and also an unique file name in order to keep things thread safe ?
        # I guess maybe I have to use the fd passed in options here and write on this file
        # that already exists, how can I do that ?

        fd = ?
        path = ?
        flags = ?

        file_actions = Spoon::FileActions.new
        # do I have to close it first ?
        file_actions.close(fd)
        file_actions.open(fd, path, flags, 0600)
        spawn_attr = Spoon::SpawnAttributes.new

        pid = Spoon.posix_spawn(hash_to_path_env(env), file_actions, spawn_attr, [command])
      end

      def hash_to_path_env(hash)
        # TODO
        return ""
      end

      def waitpid(pid)
        Process.waitpid(pid)
      end

      def self.spoon_gem_available?
        require 'spoon'
        true
      rescue LoadError
        false
      end

      private_class_method :spoon_gem_available?
    end
  end
end

Спасибо!

...