I want to sign_out a given user from a background job? E.g. sign out a given user fom a Sidekiq background worker. Any idea how I can access the method sign_out from the worker?
class SessionWorker
include Sidekiq::Worker
sidekiq_options retry: false
def perform(user_id)
# user = User.find(user_id)
# sign_out(user) if user
end
end
end
Not 100% sure, but:
I don't think this is possible because when you run code from a background worker, that code is executed in a different context than your web application and thus has no access to the warden session where the login is 'registrated'.
Related
I am new to Ruby on Rails and Sidekiq. I want to set this delete request to be done in Sidekiq queue and I don't know how to send it to the perform method, I am sending the Book model to the perform method
My controller Action code
def destroy
BaseWorkerJob.perform_async(Book)
end
My BaseWorkerJob class code
class BaseWorkerJob
include Sidekiq::Job
sidekiq_options retry:0
def perform(book)
# Do something
book.find(params[:id]).destroy!
sleep 15
end
end
SideKiq Error
enter image description here
ruby 3.1.2
Rails 7.0.4
You can send the model name and object id to the worker
def destroy
BaseWorkerJob.perform_async(Book.to_s, params[:id])
end
class BaseWorkerJob
include Sidekiq::Job
sidekiq_options retry: 0
def perform(klass_name, object_id)
klass_name.constantize.find(object_id).destroy!
end
end
Try it out!
I have certain actions in my app, and when they occur mailers are sent out.
My actions and mailers and everything work just fine. However, I'm trying to pass this job over a sidekiq worker.
My workers in the app are working fine, but I'm having issues getting my mailers to work via this workers.
Here's my worker
class SendMailerWorker
include Sidekiq::Worker
sidekiq_options retry: false
def perform
#candidate = Candidate.find(params[:id])
#candidate.destroy
TestMailer.send_request()
end
end
And here's my controller
def destroy
SendMailerWorker.perform_async
end
Yet this set up doesn't work, I'm getting the following error: NameError: undefined local variable or method `params'
So the question is, how do I access params in the worker?
Just pass your parameters from controller to sidekiq worker
class SendMailerWorker
include Sidekiq::Worker
sidekiq_options retry: false
def perform(candidate_id)
#candidate = Candidate.find(candidate_id)
#candidate.destroy
TestMailer.send_request()
end
end
def destroy
SendMailerWorker.perform_async(params[:id])
end
I only want to perform the background job when the user is logged in. When the user is logged in, I start a worker:
Warden::Manager.after_authentication do |user,auth,opts|
ImapWorker.perform_async(user.id)
end
All my ImapWorker does is use ruby's Net::Imap API to wait for new emails to come in from a remote email server. It uses Imap's idle functionality to wait for new events.
class ImapWorker
include Sidekiq::Worker
def perform(user_id)
user = User.find(user_id)
imap = Net::IMAP.new('imap.gmail.com',993,true)
imap.login(user.email, user.password)
imap.select('INBOX')
imap.add_response_handler do |resp|
if resp.kind_of?(Net::IMAP::UntaggedResponse) and resp.name == "EXISTS"
check_email
end
end
imap.idle
end
end
Now when my user logs out, I want to end the worker. I know in devise, I can hook into the log out functionality as such:
Warden::Manager.before_logout do |user,auth,opts|
...
end
But how exactly do I stop the sidekiq worker?
require 'sidekiq/api'; Sidekiq::ProcessSet.new.each(&:stop!)
How can I destroy an entity after some action is performed in Sidekiq's worker?
I have following code which doesn't work (mail is not deleted):
class MailingWorker
include Sidekiq::Workerdef
def perform(mail_id)
mail = Mail.find mail_id
#some logic for sending email
mail.destroy
end
end
There's a controller action in my Rails app that contacts a user via text-message and email. For reasons I won't go into, the text-message needs to complete before the email can be sent successfully. I originally had something like this:
controller:
class MyController < ApplicationController
def contact_user
ContactUserWorker.perform_async(#user.id)
end
end
workers:
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
This was unreliable; sometimes the email would fail, sometimes both would fail. I'm trying to determine whether perform_async was the cause of the problem. Was the async part allowing the email to fire off before the text had completed? I'm a little fuzzy on how exactly perform_async works, but that sounded like a reasonable guess.
At first, I refactored ContactUserWorker to:
class ContactUserWorker
include Sidekiq::Worker
def perform(user_id)
user = User.find(user_id)
User.send_text
SendUserEmailWorker.perform_async(user_id)
end
end
Eventually though, I just moved the call to send_text out of the workers altogether and into the controller:
class MyController < ApplicationController
def contact_user
#user.send_text
SendUserEmailWorker.perform_async(#user.id)
end
end
This is a simplified version of the real code, but that's the gist of it. It seems to be working fine now, though I still wonder whether the problem was Sidekiq-related or if something else was going on.
I'm curious whether my original structure would've worked if I'd used perform instead of perform_async for all the calls except the email call. Like this:
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
If the email can only be sent after the text message has been sent, then send the email after successful completion of sending the text.
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
In user.send_text you need to handle the fact that neither the text or the email has been sent.
I'm curious whether my original structure would've worked if I'd used perform instead of perform_async for all the calls except the email call
It would have. But this is not what you actually intdending. What you really want is this:
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
end
The problem was indeed the perform async part. It schedules both tasks to be executed in the background by a separate sidekiq daemon process. i guess your sidekiq is configured to execute the jobs concurrently. In the first version you've first scheduled the ContactUserWorker to perform it's job in a background outside of the current rails request. As this worker is startet later on, it kicks off two separate delayed workers in turn, which are then run in parallel and so there is no way to determine which of the both executes/finishes first.
I don't know what you mean exatly by sending text, but sending an email is an io blocking process and therefore it was a good idea to perform this in a background, because it would be blocking a complete rails process otherwise until the email is delivered (on a typical unicorn/passenger multi-process deployment). And as you actually want to execute both tasks sequentially and as an atomic operation, it's totally fine, performing them by a single sidekiq job/worker.
You also don't have to check if send_text succeeds. Sidekiq will retry the complete job if any part of it fails with an exception