2014-06-10 2 views
2

내 Rails 앱에는 텍스트 메시지와 이메일을 통해 사용자에게 연락하는 컨트롤러 작업이 있습니다. 내가 들어 가지 않을 이유가 있기 때문에 이메일을 성공적으로 보내기 전에 문자 메시지를 작성해야합니다.Sidekiq : perform_async 및 순서 종속적 인 작업

컨트롤러 :

class MyController < ApplicationController 
    def contact_user 
    ContactUserWorker.perform_async(@user.id) 
    end 
end 

근로자 : 나는 원래 이런 걸했다

class ContactUserWorker 
    include Sidekiq::Worker 

    def perform(user_id) 
    SendUserTextWorker.perform_async(user_id) 
    SendUserEmailWorker.perform_async(user_id) 
    end 
end 

class SendUserTextWorker 
    include Sidekiq::Worker 

    def perform(user_id) 
    user = User.find(user_id) 
    user.send_text 
    end 
end 

class SendUserEmailWorker 
    include Sidekiq::Worker 

    def perform(user_id) 
    user = User.find(user_id) 
    user.send_email 
    end 
end 

이 신뢰할 수없는되었다; 때로는 이메일이 실패하고 때로는 실패 할 수도 있습니다. perform_async이 문제의 원인인지 여부를 확인하려고합니다. 텍스트가 완료되기 전에 async 부분이 전자 메일을 시작하도록 허용 했습니까? 나는 정확히 어떻게 perform_async가 작동하는지에 대해 조금 퍼지지만, 그것은 합리적인 추측처럼 들렸다. 결국하지만

class ContactUserWorker 
    include Sidekiq::Worker 

    def perform(user_id) 
    user = User.find(user_id) 
    User.send_text 

    SendUserEmailWorker.perform_async(user_id) 
    end 
end 

, 난 그냥 모두 노동자 중 send_text로 통화를 이동 컨트롤러에 :

은 처음에는에 ContactUserWorker를 리팩토링

class MyController < ApplicationController 
    def contact_user 
    @user.send_text 
    SendUserEmailWorker.perform_async(@user.id) 
    end 
end 

이것은 단순화 실제 코드의 버전이지만 그게 그 핵심입니다. 사이드 킨과 관련된 문제인지 아니면 다른 문제가 있는지 궁금해 할지라도 지금은 잘 작동하고있는 것 같습니다.

이메일 전화를 제외한 모든 통화에 perform_async 대신 perform을 사용하면 원래 구조가 작동했는지 여부가 궁금합니다. 이처럼 :

class MyController < ApplicationController 
    def contact_user 
    ContactUserWorker.perform(@user.id) 
    end 
end 

class ContactUserWorker 
    include Sidekiq::Worker 

    def perform(user_id) 
    SendUserTextWorker.perform(user_id) 
    SendUserEmailWorker.perform_async(user_id) 
    end 
end 

답변

1

전자 메일을 보낼 수있는 경우 텍스트 메시지를 보낸 후에 텍스트를 성공적으로 보낸 후 전자 메일을 보냅니다.

class ContactUserWorker 
    include Sidekiq::Worker 

    def perform(user_id) 
    SendUserTextWorker.perform_async(user_id) 
    end 
end 

class SendUserTextWorker 
    include Sidekiq::Worker 

    def perform(user_id) 
    user = User.find(user_id) 
    text_sent = user.send_text 
    SendUserEmailWorker.perform_async(user_id) if text_sent 
    end 
end 

class SendUserEmailWorker 
    include Sidekiq::Worker 

    def perform(user_id) 
    user = User.find(user_id) 
    user.send_email 
    end 
end 

user.send_text에서 텍스트 또는 이메일이 전송되지 않았다는 사실을 처리해야합니다.

1

내가 사용 더라면 내 원래의 구조가 작업 한 것인지 궁금 그것은 것 이메일 전화

제외한 모든 통화에 대해 perform_async 대신 수행합니다. 그러나 이것은 당신이 실제로 의도하는 것이 아닙니다.

class MyController < ApplicationController 
    def contact_user 
    ContactUserWorker.perform_async(@user.id) 
    end 
end 

class ContactUserWorker 
    include Sidekiq::Worker 
    attr_reader :user_id 

def perform(user_id) 
    @user_id = user_id 
    user.send_text 
    user.send_email 
end 

def user 
    @user ||= User.find user_id 
end 

문제는 참이었다 비동기 부분을 수행 : 당신이 정말 원하는 것은 이것이다. 별도의 sidekiq 데몬 프로세스를 통해 두 작업이 모두 백그라운드에서 실행되도록 예약합니다. sidekiq 작업을 동시에 실행하도록 구성되어있는 것 같아요. 첫 번째 버전에서는 먼저 ContactUserWorker이 현재 레일 요청 이외의 배경에서 작업을 수행하도록 예약했습니다. 이 근로자가 나중에 시동을 걸면 차례 차례로 두 명의 별도 지연 근로자가 발길을 뽑아 내고 그 다음에 병렬로 진행되기 때문에 어느 쪽이 먼저 실행/완료되는지 결정할 방법이 없습니다.

텍스트를 보내서 무엇을 의미하는지 모르겠지만 전자 메일을 보내는 것은 차단 프로세스이므로 io 차단 프로세스를 백그라운드에서 수행하는 것이 좋습니다. 그렇지 않으면 전체 레일스 프로세스를 차단할 것이므로 전자 메일이 배달 될 때까지 (일반적인 유니콘/승객 다중 프로세스 배포에서). 그리고 실제로 두 작업을 순차적으로 그리고 원 자성 작업으로 실행하기를 원한다면, 그것은 하나의 sidekiq 작업/작업자에 의해 수행되는 것이 아주 좋습니다.

send_text가 성공했는지 확인할 필요도 없습니다.Sidekiq은 예외가있는 부분이있는 경우 전체 작업을 다시 시도합니다.

관련 문제