복붙노트

[REDIS] sidekiq 두 개의 별도의 레디 스 인스턴스에 대한 작업?

REDIS

sidekiq 두 개의 별도의 레디 스 인스턴스에 대한 작업?

안녕하세요,

나는 두 개의 별도하지만, 관련 응용 프로그램을 가지고있다. 그들은 모두 자신의 배경 큐 (: 별도의 Sidekiq & 레디 스 프로세스를 읽기)이 있어야합니다. 그러나, 나는 가끔 APP1에서 APP2의 큐에 작업을 밀어 수 있도록하고 싶습니다.

간단한 큐 / 푸시 관점에서, 그것은 APP1 기존 Sidekiq / 레디 스 스택을 가지고 있지 않은 경우이 작업을 수행하기 쉬운 것입니다 :

# In a process, far far away

# Configure client 
Sidekiq.configure_client do |config|
  config.redis = { :url => 'redis://redis.example.com:7372/12', :namespace => 'mynamespace' }
end

# Push jobs without class definition 
Sidekiq::Client.push('class' => 'Example::Workers::Trace', 'args' => ['hello!'])

# Push jobs overriding default's 
Sidekiq::Client.push('queue' => 'example', 'retry' => 3, 'class' =>     'Example::Workers::Trace', 'args' => ['hello!'])

그러나 이미 APP1에서 Sidekiq.configure_client 및 Sidekiq.configure_server라는 것이다 주어진, 아마 뭔가 요구 사항이 발생하는 경우 여기 사이의 단계가있다.

분명히 난 그냥 바로 Sidekiq 내부에서 직렬화 및 정규화 코드를 취할 수 있으며, 수동으로 APP2의 레디 스 큐에 밀어하지만 부서지기 쉬운 해결책처럼 보인다. 나는 Client.push 기능을 사용할 수 있도록하고 싶습니다.

나는 나의 이상적인 솔루션은 다음과 같을 것입니다 가정 :

SidekiqTWO.configure_client {원격 연결 .....} SidekiqTWO :: Client.push (작업 ....)

또는:

$는 = 원격 remote_connection을 레디 스 .....

Sidekiq :: Client.push (작업, $ redis_remote)

분명히 조금 우스운 만의 내 이상적인 사용 사례가.

감사!

해결법

  1. ==============================

    1.그래서 한 가지의 FAQ에 따르면,는 "Sidekiq 메시지 형식은 매우 간단하고 안정적이다. : 그것은 JSON 형식으로 단지 해시이다"이다 내가 sidekiq에 JSON을 보낼 생각하지 않는다 mine-- 강조 할 너무 취성이다. 당신이 OP의 상황으로,에 작업을 전송하는 레디 스 예를 중심으로 세밀한 제어를 할 때 특히, 아마 그냥 날 작업이 큐에되는과 함께 레디 스 인스턴스를 표시 할 것입니다 조금 래퍼를 쓸 것입니다.

    그래서 한 가지의 FAQ에 따르면,는 "Sidekiq 메시지 형식은 매우 간단하고 안정적이다. : 그것은 JSON 형식으로 단지 해시이다"이다 내가 sidekiq에 JSON을 보낼 생각하지 않는다 mine-- 강조 할 너무 취성이다. 당신이 OP의 상황으로,에 작업을 전송하는 레디 스 예를 중심으로 세밀한 제어를 할 때 특히, 아마 그냥 날 작업이 큐에되는과 함께 레디 스 인스턴스를 표시 할 것입니다 조금 래퍼를 쓸 것입니다.

    레디 스 인스턴스에 라운드 로빈 작업에 케빈 베델의 일반적인 상황에, 난 당신이 컨트롤을하고 싶지 않아 다 치지는의 레디 스 인스턴스는 그냥 대기열 및 분포를 자동으로 관리 할 수있다 할 used--입니다. 한 사람 만이 지금까지를 요청하고, 그들이 레디 스를 사용하는 솔루션 :: 분산 해낸 것 같습니다 :

    datastore_config = YAML.load(ERB.new(File.read(File.join(Rails.root, "config", "redis.yml"))).result)
    
    datastore_config = datastore_config["defaults"].merge(datastore_config[::Rails.env])
    
    if datastore_config[:host].is_a?(Array)
      if datastore_config[:host].length == 1
        datastore_config[:host] = datastore_config[:host].first
      else
        datastore_config = datastore_config[:host].map do |host|
          host_has_port = host =~ /:\d+\z/
    
          if host_has_port
            "redis://#{host}/#{datastore_config[:db] || 0}"
          else
            "redis://#{host}:#{datastore_config[:port] || 6379}/#{datastore_config[:db] || 0}"
          end
        end
      end
    end
    
    Sidekiq.configure_server do |config|
      config.redis = ::ConnectionPool.new(:size => Sidekiq.options[:concurrency] + 2, :timeout => 2) do
        redis = if datastore_config.is_a? Array
          Redis::Distributed.new(datastore_config)
        else
          Redis.new(datastore_config)
        end
    
        Redis::Namespace.new('resque', :redis => redis)
      end
    end
    

    또 다른 한가지는 고 가용성을 얻을 수 및 장애 복구하기 위해 당신의 탐구에서 고려해야 할 것은 안정성 기능을 포함하는 Sidekiq 프로를 얻는 것입니다 :는 "Sidekiq 프로 클라이언트가 과도 레디 스 중단을 견딜 수 그것은 오류에 로컬 작업을 대기열에 그 일자리를 제공하려고합니다. 일단 연결이 복원됩니다. " sidekiq 어쨌든 배경 프로세스이기 때문에, 약간의 지연은 레디 스 인스턴스는 응용 프로그램에 영향을 미치지 않습니다 다운 된 경우. 당신이 개 레디 스 인스턴스 중 하나가 다운 당신이 라운드 로빈을 사용하는 경우이 기능을 사용하지 않는, 당신은 여전히 ​​일자리를 잃었습니다.

  2. ==============================

    2.carols10cents 말한다으로는 아주 간단하지만 난 항상 기능을 캡슐화하고 다른 프로젝트 나 호텔 오늘부터 블로그에서 아이디어를 업데이트에서 재사용 할 수 좋아. 이것은 다음과 같은 솔루션은 호텔 오늘의 레일 4.1 및 봄 프리 로더를 생존하지 않습니다에 향상시킨다.

    carols10cents 말한다으로는 아주 간단하지만 난 항상 기능을 캡슐화하고 다른 프로젝트 나 호텔 오늘부터 블로그에서 아이디어를 업데이트에서 재사용 할 수 좋아. 이것은 다음과 같은 솔루션은 호텔 오늘의 레일 4.1 및 봄 프리 로더를 생존하지 않습니다에 향상시킨다.

    현재 내가 lib 디렉토리 / remote_sidekiq / 다음 파일을 추가로 할 수 있도록 :

    remote_sidekiq.rb

    class RemoteSidekiq
      class_attribute :redis_pool
    end
    

    remote_sidekiq_worker.rb

    require 'sidekiq'
    require 'sidekiq/client'
    
    module RemoteSidekiqWorker
      def client
        pool = RemoteSidekiq.redis_pool || Thread.current[:sidekiq_via_pool] || Sidekiq.redis_pool
        Sidekiq::Client.new(pool)
      end
    
      def push(worker_name, attrs = [], queue_name = "default")
        client.push('args' => attrs, 'class' => worker_name, 'queue' => queue_name)
      end
    end
    

    당신은 세트 redis_pool하는 초기화를 만들어야합니다

    설정 / 초기화 / remote_sidekiq.rb

    url = ENV.fetch("REDISCLOUD_URL")
    namespace = 'primary'
    
    redis = Redis::Namespace.new(namespace, redis: Redis.new(url: url))
    
    RemoteSidekiq.redis_pool = ConnectionPool.new(size: ENV['MAX_THREADS'] || 6) { redis }
    

    알렉스겠습니까 EDITH :

    대신 라인의 sidekiq 결코 버전에서 :

    redis = Redis::Namespace.new(namespace, redis: Redis.new(url: url))
    
    RemoteSidekiq.redis_pool = ConnectionPool.new(size: ENV['MAX_THREADS'] || 6) { redis }
    

    사용 라인 :

    redis_remote_options = {
      namespace: "yournamespace",
      url: ENV.fetch("REDISCLOUD_URL")
    }
    
    RemoteSidekiq.redis_pool = Sidekiq::RedisConnection.create(redis_remote_options)
    

    당신이 원하는 어디든지 당신은 단순히는 RemoteSidekiqWorker 모듈을 포함 할 수 있습니다. 작업이 완료!

    **** 더 많은 대규모 환경 ****

    RemoteWorker 모델에 추가하면 추가 혜택을 추가합니다 :

    다음의 예는 RemoteWorker

    class RemoteTraceWorker
      include RemoteSidekiqWorker
      include ActiveModel::Model
    
      attr_accessor :message
    
      validates :message, presence: true
    
      def perform_async
        if valid?
          push(worker_name, worker_args)
        else
          raise ActiveModel::StrictValidationFailed, errors.full_messages
        end
      end
    
      private
    
      def worker_name
        :TraceWorker.to_s
      end
    
      def worker_args
        [message]
      end
    end
    
  3. ==============================

    3.내가 메시지 큐의 판독 방법이 복잡 ActiveJob를 사용하고 있기 때문에 나는 몇 가지 문제로 이것으로 실행을 가로 질러왔다.

    내가 메시지 큐의 판독 방법이 복잡 ActiveJob를 사용하고 있기 때문에 나는 몇 가지 문제로 이것으로 실행을 가로 질러왔다.

    ARO의 대답에 구축, 당신은 여전히 ​​redis_pool 설치가 필요합니다 :

    remote_sidekiq.rb

    class RemoteSidekiq
      class_attribute :redis_pool
    end
    

    설정 / 초기화 / remote_sidekiq.rb

    url = ENV.fetch("REDISCLOUD_URL")
    namespace = 'primary'
    
    redis = Redis::Namespace.new(namespace, redis: Redis.new(url: url))
    
    RemoteSidekiq.redis_pool = ConnectionPool.new(size: ENV['MAX_THREADS'] || 6) { redis }
    

    이제 대신 근로자의 우리가 요청을 대기하는 ActiveJob 어댑터를 만듭니다 :

    lib 디렉토리 / active_job / queue_adapters / remote_sidekiq_adapter.rb

    require 'sidekiq'
    
    module ActiveJob
      module QueueAdapters
        class RemoteSidekiqAdapter
          def enqueue(job)
            #Sidekiq::Client does not support symbols as keys
            job.provider_job_id = client.push \
              "class"   => ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper,
              "wrapped" => job.class.to_s,
              "queue"   => job.queue_name,
              "args"    => [ job.serialize ]
          end
    
          def enqueue_at(job, timestamp)
            job.provider_job_id = client.push \
              "class"   => ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper,
              "wrapped" => job.class.to_s,
              "queue"   => job.queue_name,
              "args"    => [ job.serialize ],
              "at"      => timestamp
          end
    
          def client
            @client ||= ::Sidekiq::Client.new(RemoteSidekiq.redis_pool)
          end
        end
      end
    end
    

    지금은 이벤트를 큐에 어댑터를 사용할 수 있습니다 :

    require 'active_job/queue_adapters/remote_sidekiq_adapter'
    
    class RemoteJob < ActiveJob::Base
      self.queue_adapter = :remote_sidekiq
    
      queue_as :default
    
      def perform(_event_name, _data)
        fail "
          This job should not run here; intended to hook into
          ActiveJob and run in another system
        "
      end
    end
    

    지금은 정상적인 ActiveJob API를 사용하여 작업을 대기 할 수 있습니다. 무엇이든 응용 프로그램은 큐의 아웃 작업을 수행 할 수 일치 RemoteJob가 필요합니다 읽습니다.

  4. from https://stackoverflow.com/questions/14741700/work-with-two-separate-redis-instances-with-sidekiq by cc-by-sa and MIT license