ruby-on-rails - 我刚刚部署了 discourse 应用程序,在 Heroku db :migrate. 期间出现错误,可能是 redis 无法连接

标签 ruby-on-rails ruby heroku redis discourse

我在heroku上的rails中部署了discourse应用程序。 部署成功 当我执行 heroku run rake db:migrate db:seed_fu 时出现错误 在heroku run rake 上也遇到其他错误 db:create

    config/discourse_defaults.conf 

    # message bus redis server address
    message_bus_redis_host = redis://h:p27179a7ac96b0d215c36e5d5a4bda0c0565e1e6d96cdf043b9f5481d68dd1541@ec2-3-219-59-76.compute-1.amazonaws.com:27969


    # message bus redis server port
    message_bus_redis_port = 27969

    # message bus redis slave server address
    message_bus_redis_slave_host =

    # message bus redis slave server port
    message_bus_redis_slave_port = 27969


    config/intializer/001-redis.rb

    if Rails.env.development? && ENV['DISCOURSE_FLUSH_REDIS']
      puts "Flushing redis (development mode)"
      $redis.flushall
    end
application.rb

    # frozen_string_literal: true

    # note, we require 2.5.2 and up cause 2.5.1 had some mail bugs we no longer
    # monkey patch, so this avoids people booting with this problem version
    begin
      if !RUBY_VERSION.match?(/^2\.(([67])|(5\.[2-9]))/)
        STDERR.puts "Discourse requires Ruby 2.5.2 or up"
        exit 1
      end
    rescue
      # no String#match?
      STDERR.puts "Discourse requires Ruby 2.5.2 or up"
      exit 1
    end

    require File.expand_path('../boot', __FILE__)
    require 'active_record/railtie'
    require 'action_controller/railtie'
    require 'action_view/railtie'
    require 'action_mailer/railtie'
    require 'sprockets/railtie'

    # Plugin related stuff
    require_relative '../lib/discourse_event'
    require_relative '../lib/discourse_plugin'
    require_relative '../lib/discourse_plugin_registry'

    require_relative '../lib/plugin_gem'

    # Global config
    require_relative '../app/models/global_setting'
    GlobalSetting.configure!
    unless Rails.env.test? && ENV['LOAD_PLUGINS'] != "1"
      require_relative '../lib/custom_setting_providers'
    end
    GlobalSetting.load_defaults

    if ENV['SKIP_DB_AND_REDIS'] == '1'
      GlobalSetting.skip_db = true
      GlobalSetting.skip_redis = true
    end

    require 'pry-rails' if Rails.env.development?

    if defined?(Bundler)
      bundler_groups = [:default]

      if !Rails.env.production?
        bundler_groups = bundler_groups.concat(Rails.groups(
          assets: %w(development test profile)
        ))
      end

      Bundler.require(*bundler_groups)
    end

    module Discourse
      class Application < Rails::Application

        def config.database_configuration
          if Rails.env.production?
            GlobalSetting.database_config
          else
            super
          end
        end
        # Settings in config/environments/* take precedence over those specified here.
        # Application configuration should go into files in config/initializers
        # -- all .rb files in that directory are automatically loaded.

        # this pattern is somewhat odd but the reloader gets very
        # confused here if we load the deps without `lib` it thinks
        # discourse.rb is under the discourse folder incorrectly
        require_dependency 'lib/discourse'
        require_dependency 'lib/es6_module_transpiler/rails'
        require_dependency 'lib/js_locale_helper'

        # tiny file needed by site settings
        require_dependency 'lib/highlight_js/highlight_js'

        # mocha hates us, active_support/testing/mochaing.rb line 2 is requiring the wrong
        #  require, patched in source, on upgrade remove this
        if Rails.env.test? || Rails.env.development?
          require "mocha/version"
          require "mocha/deprecation"
          if Mocha::VERSION == "0.13.3" && Rails::VERSION::STRING == "3.2.12"
            Mocha::Deprecation.mode = :disabled
          end
        end

        # Disable so this is only run manually
        # we may want to change this later on
        # issue is image_optim crashes on missing dependencies
        config.assets.image_optim = false

        # Custom directories with classes and modules you want to be autoloadable.
        config.autoload_paths += Dir["#{config.root}/app/serializers"]
        config.autoload_paths += Dir["#{config.root}/lib/validators/"]
        config.autoload_paths += Dir["#{config.root}/app"]

        if Rails.env.development? && !Sidekiq.server?
          config.autoload_paths += Dir["#{config.root}/lib"]
        end

        # Only load the plugins named here, in the order given (default is alphabetical).
        # :all can be used as a placeholder for all plugins not explicitly named.
        # config.plugins = [ :exception_notification, :ssl_requirement, :all ]

        config.assets.paths += %W(#{config.root}/config/locales #{config.root}/public/javascripts)

        if Rails.env == "development" || Rails.env == "test"
          config.assets.paths << "#{config.root}/test/javascripts"
          config.assets.paths << "#{config.root}/test/stylesheets"
          config.assets.paths << "#{config.root}/node_modules"
        end

        # Allows us to skip minifincation on some files
        config.assets.skip_minification = []

        # explicitly precompile any images in plugins ( /assets/images ) path
        config.assets.precompile += [lambda do |filename, path|
          path =~ /assets\/images/ && !%w(.js .css).include?(File.extname(filename))
        end]

        config.assets.precompile += %w{
          vendor.js
          admin.js
          preload-store.js
          browser-update.js
          break_string.js
          ember_jquery.js
          pretty-text-bundle.js
          wizard-application.js
          wizard-vendor.js
          plugin.js
          plugin-third-party.js
          markdown-it-bundle.js
          service-worker.js
          google-tag-manager.js
          google-universal-analytics.js
          preload-application-data.js
          print-page.js
          omniauth-complete.js
          activate-account.js
          auto-redirect.js
          wizard-start.js
          onpopstate-handler.js
          embed-application.js
        }

        # Precompile all available locales
        unless GlobalSetting.try(:omit_base_locales)
          Dir.glob("#{config.root}/app/assets/javascripts/locales/*.js.erb").each do |file|
            config.assets.precompile << "locales/#{file.match(/([a-z_A-Z]+\.js)\.erb$/)[1]}"
          end
        end

        # out of the box sprockets 3 grabs loose files that are hanging in assets,
        # the exclusion list does not include hbs so you double compile all this stuff
        initializer :fix_sprockets_loose_file_searcher, after: :set_default_precompile do |app|
          app.config.assets.precompile.delete(Sprockets::Railtie::LOOSE_APP_ASSETS)
          start_path = ::Rails.root.join("app/assets").to_s
          exclude = ['.es6', '.hbs', '.js', '.css', '']
          app.config.assets.precompile << lambda do |logical_path, filename|
            filename.start_with?(start_path) &&
            !exclude.include?(File.extname(logical_path))
          end
        end

        # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
        # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
        config.time_zone = 'UTC'

        # auto-load locales in plugins
        # NOTE: we load both client & server locales since some might be used by PrettyText
        config.i18n.load_path += Dir["#{Rails.root}/plugins/*/config/locales/*.yml"]

        # Configure the default encoding used in templates for Ruby 1.9.
        config.encoding = 'utf-8'
        config.assets.initialize_on_precompile = false

        # Configure sensitive parameters which will be filtered from the log file.
        config.filter_parameters += [
          :password,
          :pop3_polling_password,
          :api_key,
          :s3_secret_access_key,
          :twitter_consumer_secret,
          :facebook_app_secret,
          :github_client_secret,
          :second_factor_token,
        ]

        # Enable the asset pipeline
        config.assets.enabled = true

        # Version of your assets, change this if you want to expire all your assets
        config.assets.version = '1.2.4'

        # see: http://stackoverflow.com/questions/11894180/how-does-one-correctly-add-custom-sql-dml-in-migrations/11894420#11894420
        config.active_record.schema_format = :sql

        # per https://www.owasp.org/index.php/Password_Storage_Cheat_Sheet
        config.pbkdf2_iterations = 64000
        config.pbkdf2_algorithm = "sha256"

        # rack lock is nothing but trouble, get rid of it
        # for some reason still seeing it in Rails 4
        config.middleware.delete Rack::Lock

        # wrong place in middleware stack AND request tracker handles it
        config.middleware.delete Rack::Runtime

        # ETags are pointless, we are dynamically compressing
        # so nginx strips etags, may revisit when mainline nginx
        # supports etags (post 1.7)
        config.middleware.delete Rack::ETag

        unless Rails.env.development?
          require 'middleware/enforce_hostname'
          config.middleware.insert_after Rack::MethodOverride, Middleware::EnforceHostname
        end

        require 'content_security_policy/middleware'
        config.middleware.swap ActionDispatch::ContentSecurityPolicy::Middleware, ContentSecurityPolicy::Middleware

        require 'middleware/discourse_public_exceptions'
        config.exceptions_app = Middleware::DiscoursePublicExceptions.new(Rails.public_path)

        # Our templates shouldn't start with 'discourse/templates'
        config.handlebars.templates_root = 'discourse/templates'
        config.handlebars.raw_template_namespace = "Discourse.RAW_TEMPLATES"

        require 'discourse_redis'
        require 'logster/redis_store'
        require 'freedom_patches/redis'
        # Use redis for our cache
        config.cache_store = DiscourseRedis.new_redis_store
        $redis = DiscourseRedis.new
        Logster.store = Logster::RedisStore.new(DiscourseRedis.new)

        # we configure rack cache on demand in an initializer
        # our setup does not use rack cache and instead defers to nginx
        config.action_dispatch.rack_cache = nil

        # ember stuff only used for asset precompliation, production variant plays up
        config.ember.variant = :development
        config.ember.ember_location = "#{Rails.root}/vendor/assets/javascripts/production/ember.js"
        config.ember.handlebars_location = "#{Rails.root}/vendor/assets/javascripts/handlebars.js"

        require 'auth'

        if GlobalSetting.relative_url_root.present?
          config.relative_url_root = GlobalSetting.relative_url_root
        end

        if Rails.env == "test"
          if ENV['LOAD_PLUGINS'] == "1"
            Discourse.activate_plugins!
          end
        else
          Discourse.activate_plugins!
        end

        require_dependency 'stylesheet/manager'
        require_dependency 'svg_sprite/svg_sprite'

        config.after_initialize do
          # require common dependencies that are often required by plugins
          # in the past observers would load them as side-effects
          # correct behavior is for plugins to require stuff they need,
          # however it would be a risky and breaking change not to require here
          require_dependency 'category'
          require_dependency 'post'
          require_dependency 'topic'
          require_dependency 'user'
          require_dependency 'post_action'
          require_dependency 'post_revision'
          require_dependency 'notification'
          require_dependency 'topic_user'
          require_dependency 'topic_view'
          require_dependency 'topic_list'
          require_dependency 'group'
          require_dependency 'user_field'
          require_dependency 'post_action_type'
          # Ensure that Discourse event triggers for web hooks are loaded
          require_dependency 'web_hook'

          # So open id logs somewhere sane
          OpenID::Util.logger = Rails.logger

          # Load plugins
          Discourse.plugins.each(&:notify_after_initialize)

          # we got to clear the pool in case plugins connect
          ActiveRecord::Base.connection_handler.clear_active_connections!

          # This nasty hack is required for not precompiling QUnit assets
          # in test mode. see: https://github.com/rails/sprockets-rails/issues/299#issuecomment-167701012
          ActiveSupport.on_load(:action_view) do
            default_checker = ActionView::Base.precompiled_asset_checker

            ActionView::Base.precompiled_asset_checker = -> logical_path do
              default_checker[logical_path] ||
                %w{qunit.js qunit.css test_helper.css test_helper.js wizard/test/test_helper.js}.include?(logical_path)
            end
          end
        end

        if ENV['RBTRACE'] == "1"
          require 'rbtrace'
        end

        config.generators do |g|
          g.test_framework :rspec, fixture: false
        end

        # we have a monkey_patch we need to require early... prior to connection
        # init
        require 'freedom_patches/reaper'

      end
    end


    app/model/global_settingg.rb

    # frozen_string_literal: true

    class GlobalSetting

      def self.register(key, default)
        define_singleton_method(key) do
          provider.lookup(key, default)
        end
      end

      VALID_SECRET_KEY ||= /^[0-9a-f]{128}$/
      # this is named SECRET_TOKEN as opposed to SECRET_KEY_BASE
      # for legacy reasons
      REDIS_SECRET_KEY ||= 'SECRET_TOKEN'

      REDIS_VALIDATE_SECONDS ||= 30

      # In Rails secret_key_base is used to encrypt the cookie store
      # the cookie store contains session data
      # Discourse also uses this secret key to digest user auth tokens
      # This method will
      # - use existing token if already set in ENV or discourse.conf
      # - generate a token on the fly if needed and cache in redis
      # - enforce rules about token format falling back to redis if needed
      def self.safe_secret_key_base

        if @safe_secret_key_base && @token_in_redis && (@token_last_validated + REDIS_VALIDATE_SECONDS) < Time.now
          @token_last_validated = Time.now
          token = $redis.without_namespace.get(REDIS_SECRET_KEY)
          if token.nil?
            $redis.without_namespace.set(REDIS_SECRET_KEY, @safe_secret_key_base)
          end
        end

        @safe_secret_key_base ||= begin
          token = secret_key_base
          if token.blank? || token !~ VALID_SECRET_KEY

            @token_in_redis = true
            @token_last_validated = Time.now

            token = $redis.without_namespace.get(REDIS_SECRET_KEY)
            unless token && token =~ VALID_SECRET_KEY
              token = SecureRandom.hex(64)
              $redis.without_namespace.set(REDIS_SECRET_KEY, token)
            end
          end
          if !secret_key_base.blank? && token != secret_key_base
            STDERR.puts "WARNING: DISCOURSE_SECRET_KEY_BASE is invalid, it was re-generated"
          end
          token
        end
      rescue Redis::CommandError => e
        @safe_secret_key_base = SecureRandom.hex(64) if e.message =~ /READONLY/
      end

      def self.load_defaults
        default_provider = FileProvider.from(File.expand_path('../../../config/discourse_defaults.conf', __FILE__))
        default_provider.keys.concat(@provider.keys).uniq.each do |key|
          default = default_provider.lookup(key, nil)

          instance_variable_set("@#{key}_cache", nil)

          define_singleton_method(key) do
            val = instance_variable_get("@#{key}_cache")
            unless val.nil?
              val == :missing ? nil : val
            else
              val = provider.lookup(key, default)
              if val.nil?
                val = :missing
              end
              instance_variable_set("@#{key}_cache", val)
              val == :missing ? nil : val
            end
          end
        end
      end

      def self.skip_db=(v)
        @skip_db = v
      end

      def self.skip_db?
        @skip_db
      end

      def self.skip_redis=(v)
        @skip_redis = v
      end

      def self.skip_redis?
        @skip_redis
      end

      def self.use_s3?
        (@use_s3 ||=
          begin
            s3_bucket &&
            s3_region && (
              s3_use_iam_profile || (s3_access_key_id && s3_secret_access_key)
            ) ? :true : :false
          end) == :true
      end

      def self.s3_bucket_name
        @s3_bucket_name ||= s3_bucket.downcase.split("/")[0]
      end

      # for testing
      def self.reset_s3_cache!
        @use_s3 = nil
      end

      def self.database_config
        hash = { "adapter" => "postgresql" }

        %w{
          pool
          connect_timeout
          timeout
          socket
          host
          backup_host
          port
          backup_port
          username
          password
          replica_host
          replica_port
        }.each do |s|
          if val = self.public_send("db_#{s}")
            hash[s] = val
          end
        end

        hash["adapter"] = "postgresql_fallback" if hash["replica_host"]

        hostnames = [ hostname ]
        hostnames << backup_hostname if backup_hostname.present?

        hostnames << URI.parse(cdn_url).host if cdn_url.present?

        hash["host_names"] = hostnames
        hash["database"] = db_name

        hash["prepared_statements"] = !!self.db_prepared_statements

        { "production" => hash }
      end

      # For testing purposes
      def self.reset_redis_config!
        @config = nil
        @message_bus_config = nil
      end

      def self.redis_config
        @config ||=
          begin
            c = {}
            c[:host] = redis_host if redis_host
            c[:port] = redis_port if redis_port

            if redis_slave_host && redis_slave_port
              c[:slave_host] = redis_slave_host
              c[:slave_port] = redis_slave_port
              c[:connector] = DiscourseRedis::Connector
            end

            c[:password] = redis_password if redis_password.present?
            c[:db] = redis_db if redis_db != 0
            c[:db] = 1 if Rails.env == "test"
            c[:id] = nil if redis_skip_client_commands

            c.freeze
          end
      end

      def self.message_bus_redis_config
        return redis_config unless message_bus_redis_enabled
        @message_bus_config ||=
          begin
            c = {}
            c[:host] = message_bus_redis_host if message_bus_redis_host
            c[:port] = message_bus_redis_port if message_bus_redis_port

            if message_bus_redis_slave_host && message_bus_redis_slave_port
              c[:slave_host] = message_bus_redis_slave_host
              c[:slave_port] = message_bus_redis_slave_port
              c[:connector] = DiscourseRedis::Connector
            end

            c[:password] = message_bus_redis_password if message_bus_redis_password.present?
            c[:db] = message_bus_redis_db if message_bus_redis_db != 0
            c[:db] = 1 if Rails.env == "test"
            c[:id] = nil if message_bus_redis_skip_client_commands

            c.freeze
          end
      end

      def self.add_default(name, default)
        unless self.respond_to? name
          define_singleton_method(name) do
            default
          end
        end
      end

      class BaseProvider
        def self.coerce(setting)
          return setting == "true" if setting == "true" || setting == "false"
          return $1.to_i if setting.to_s.strip =~ /^([0-9]+)$/
          setting
        end

        def resolve(current, default)
          BaseProvider.coerce(
            if current.present?
              current
            else
              default.present? ? default : nil
            end
          )
        end
      end

      class FileProvider < BaseProvider
        attr_reader :data
        def self.from(file)
          if File.exists?(file)
            parse(file)
          end
        end

        def initialize(file)
          @file = file
          @data = {}
        end

        def read
          ERB.new(File.read(@file)).result().split("\n").each do |line|
            if line =~ /^\s*([a-z_]+[a-z0-9_]*)\s*=\s*(\"([^\"]*)\"|\'([^\']*)\'|[^#]*)/
              @data[$1.strip.to_sym] = ($4 || $3 || $2).strip
            end
          end
        end

        def lookup(key, default)
          var = @data[key]
          resolve(var, var.nil? ? default : "")
        end

        def keys
          @data.keys
        end

        def self.parse(file)
          provider = self.new(file)
          provider.read
          provider
        end

        private_class_method :parse
      end

      class EnvProvider < BaseProvider
        def lookup(key, default)
          var = ENV["DISCOURSE_" + key.to_s.upcase]
          resolve(var , var.nil? ? default : nil)
        end

        def keys
          ENV.keys.select { |k| k =~ /^DISCOURSE_/ }.map { |k| k[10..-1].downcase.to_sym }
        end
      end

      class BlankProvider < BaseProvider
        def lookup(key, default)

          if key == :redis_port
            return ENV["DISCOURSE_REDIS_PORT"] if ENV["DISCOURSE_REDIS_PORT"]
          end
          default
        end

        def keys
          []
        end
      end

      class << self
        attr_accessor :provider
      end

      def self.configure!
        if Rails.env == "test"
          @provider = BlankProvider.new
        else
          @provider =
            FileProvider.from(File.expand_path('../../../config/discourse.conf', __FILE__)) ||
            EnvProvider.new
        end
      end

    end
error 
Failed to report error: Name or service not known 2 Name or service not known subscribe failed, reconnecting in 1 second. Call stack ["/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/connection/hiredis.rb:19:in `connect'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/connection/hiredis.rb:19:in `connect'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:334:in `establish_connection'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:99:in `block in connect'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:291:in `with_reconnect'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:98:in `connect'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:274:in `with_socket_timeout'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/client.rb:131:in `call_loop'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/subscribe.rb:43:in `subscription'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis/subscribe.rb:12:in `subscribe'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:2824:in `_subscription'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:2192:in `block in subscribe'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:45:in `block in synchronize'",
 "/app/vendor/ruby-2.5.5/lib/ruby/2.5.0/monitor.rb:226:in `mon_synchronize'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:45:in `synchronize'",
 "/app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.1/lib/redis.rb:2191:in `subscribe'",
 "/app/vendor/bundle/ruby/2.5.0/gems/message_bus-2.2.2/lib/message_bus/backends/redis.rb:287:in `global_subscribe'",
 "/app/vendor/bundle/ruby/2.5.0/gems/message_bus-2.2.2/lib/message_bus.rb:721:in `global_subscribe_thread'",
 "/app/vendor/bundle/ruby/2.5.0/gems/message_bus-2.2.2/lib/message_bus.rb:669:in `block in new_subscriber_thread'"]
fatal: not a git repository (or any parent up to mount point /)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).
rake aborted!
Name or service not known

最佳答案

添加您的数据库和 redis 主机名以及端口号。在discourse_defaults.conf中

设置可在 Hroku_addons 中使用。就我而言,如下:

redis_host = ***-***-***.compute-1.amazonaws.com
redis_port = *****

关于ruby-on-rails - 我刚刚部署了 discourse 应用程序,在 Heroku db :migrate. 期间出现错误,可能是 redis 无法连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57805020/

相关文章:

ruby - 格式化相对日期

python - Heroku 上的 Django 部署问题与正在运行的应用程序 : PUSH REJECTED ERROR 的精确克隆

ruby-on-rails - Heroku Rails Angular JS 编译 Assets

node.js - nodejs 和express 与heroku 我得到了R10

ruby-on-rails - 什么是 gem 安装 bundler ?

ruby-on-rails - 如何分析我的 rspec 测试以找到最大的内存消耗?

css - 基于媒体查询的 Controller 操作 (Rails)

ruby-on-rails - Rails中的initialize方法有什么作用

ruby-on-rails - 如何计算对象数量而不是获取 Ruby 中的所有对象?

mysql - 使用 ActiveRecord 急切加载数据库表