class PgBouncerRunner attr_reader :pg_port, :pg_user, :pg_password, :pg_host, :pg_db attr_reader :pgb_port, :pgb_user, :pgb_password attr_reader :tmp_folder, :runner_thread, :runner_pid def initialize(pg_port: 5432, pg_user: ENV['USER'], pg_password: '', pg_host: '127.0.0.1', pg_db: ENV['USER'], verbose: true) @pg_port = pg_port @pg_user = pg_user @pg_password = pg_password @pg_host = pg_host @pg_db = pg_db @verbose = verbose @pgb_port = Network.find_available_port end def run create_config unless @tmp_folder verbose_arg = @verbose ? '-v' : '' pgb_user_arg = CLI_OPTS[:pgbouncer_user] ? "-u #{CLI_OPTS[:pgbouncer_user]}" : "" pgb_command = "#{pgbouncer_path} #{verbose_arg} #{pgb_user_arg} ./config.ini" if @verbose puts "Running pgbouncer with config at: #{@tmp_folder}" puts "EXEC #{pgb_command}" end Dir.chdir(@tmp_folder) do Open3.popen3(pgb_command) {|stdin, stdout, stderr, wait_thr| @runner_pid = wait_thr.pid # pid of the started process. #p "process_started: #{pid}" Thread.new do begin while line = stdout.gets puts "STDOUT: #{line}" if @verbose end rescue Exception => error puts error.message puts error.backtrace end end Thread.new do begin while line = stderr.gets puts "STDERR: #{line}" if @verbose end rescue Exception => error puts error.message puts error.backtrace end end exit_status = wait_thr.value # Process::Status object returned. puts "pgbouncer stoped: #{exit_status}" if @verbose } end end def pgbouncer_path if RUBY_PLATFORM =~ /darwin/ BASE_DIR + '/pgbouncer' else path = `which pgbouncer 2>/dev/null` if path == '' puts "Can not find pgbouncer in your system" puts "Please install it" exit(1) else return path.strip end end end def stop_async if @runner_pid && System.process_alive?(@runner_pid, verbose: @verbose) System.stop_process(@runner_pid) end end def run_async @runner_thread = Thread.new do begin run rescue Exception => error puts error.message puts error.backtrace end end self end def wait_for_pid while !@runner_pid sleep 0.04 end @runner_pid end def create_config @tmp_folder = Dir.mktmpdir pgb_config = render_template('config.ini.erb', {}) File.open(@tmp_folder + '/config.ini', 'w') {|f| f.write(pgb_config) } @pgb_user = "share" @pgb_password = SecureRandom.hex(10) File.open(@tmp_folder + '/users.txt', 'w') {|f| f.write(%{"#{@pgb_user}" "#{@pgb_password}"}) } end def make_db_url(remote_port) "postgres://#{pgb_user}:#{pgb_password}@dblink.tk:#{remote_port}/#{pg_db}" end private def render_template(file, params) erb = ERB.new(File.read(BASE_DIR + '/' + file)) erb.filename = file erb.result(binding) end end