I use this worker for process
class CreateOrUpdateContactWorker
include Sidekiq::Worker
sidekiq_options retry: 2, queue: 'contact_updater', concurrency: 1
sidekiq_retries_exhausted do |msg|
Airbrake.notify(error_message: "Contact update failed", session: { msg: msg })
end
def perform(user_id, changed_fields, update_address = false)
ContactUpdater.create_or_update_contact(user_id, changed_fields, update_address: update_address)
end
end
In the user model I have after_commit callback
def update_mautic_contact
CreateOrUpdateContactWorker.perform_async(id, previous_changes.keys, ship_address_changed || false)
end
The problem is when user updated twice at the same time, because to create_or_update_contact need some time. How can I limit threads only for specify user? That each task will be executed one by one for specify user_id.
I don't know if you have redis as part of your infrastructure but what you are describing is a race condition. To solve it you need mutex/locks to your critical path create_or_update_contact.
The race condition here is happening between two async workers/processes so you can't just use simple ruby mutex/lock. You need a distributed mutex that uses a central lock storage/keeper. This: https://github.com/kenn/redis-mutex should do it for you but you will need redis database.
Basically your code will something like:
class CreateOrUpdateContactWorker
include Sidekiq::Worker
sidekiq_options retry: 2, queue: 'contact_updater', concurrency: 1
sidekiq_retries_exhausted do |msg|
Airbrake.notify(error_message: "Contact update failed", session: { msg: msg })
end
def perform(user_id, changed_fields, update_address = false)
RedisMutex.with_lock("#{user_id}_create_or_update_contact") do
ContactUpdater.create_or_update_contact(user_id, changed_fields, update_address: update_address)
end
end
end
So if you have 2 user updates for user_id=1 at the same time the first to acquire the lock/mutex called 1_create_or_update_contact will execute first and will block the other call till it finishes and then the second call will start.
This will fix your problem :) I think redis is needed, useful and handful. I hardly can think of any of my rails projects without having to use redis.
I realised it with Redis, but without any gems. I used condition before execute worker:
def update_mautic_contact
if Rails.current.get("CreateOrUpdateContactWorkerIsRunning_#{id}")
Redis.current.set("CreateOrUpdateContactWorkerIsRunning_#{id}", true)
CreateOrUpdateContactWorker.perform_in(1.minutes, id, changed_fields)
else
Redis.current.set("CreateOrUpdateContactWorkerIsRunning_#{id}", true)
CreateOrUpdateContactWorker.perform_async(id, changed_fields)
end
end
and inside worker:
class CreateOrUpdateContactWorker
include Sidekiq::Worker
sidekiq_options retry: 2, queue: 'contact_updater', concurrency: 1
sidekiq_retries_exhausted do |msg|
Airbrake.notify(error_message: "Contact update failed", session: { msg: msg })
end
def perform(user_id, changed_fields, update_address = false)
ContactUpdater.create_or_update_contact(user_id, changed_fields, update_address: update_address)
Redis.current.del("CreateOrUpdateContactWorkerIsRunning_#{user_id}")
end
end
Related
I have the following piece of code in my Actor's (I call this Actor MasterActor) receive method:
override def receive: Receive = {
case StopActor(id, actorConfig) =>
log.info(s"Stopping actor with id = $id and config $actorConfig")
stopActor(id, powerPlantCfg).pipeTo(self)
context.become(waitForStop(sender()))
// Other messages... not shown here for simplicity
}
So what I'm doing above is to stop the actor and pipe the result of that which is a Future[Continue] (where Continue is a Monix Ack type) to the Actor that contains the above Receive method. The stopActor looks like this:
private def stopActor(id: Long, cfg: ActorConfig): Future[Ack] = async {
await(fetchActor(id).materialize) match {
case scala.util.Success(actorRef) =>
log.info(s"Stopping Actor with id = $id")
context.watch(actorRef)
context.stop(actorRef)
Continue
case scala.util.Failure(fail) =>
log.error(s"Could not fetch Actor instance for id = $id because of: $fail")
Continue
}
}
I'm doing the context.watch(actorRef) and this is how my waitForStop looks like:
private def waitForStop(source: ActorRef): Receive = {
case Continue =>
source ! Continue
context.become(receive)
case someShit =>
log.error(s"Unexpected message $someShit received while waiting for an actor to be stopped")
}
So I have 2 questions here:
When doing context.become(waitForStop(sender())), I'm closing in on the sender(), so I assume the sender in this case is the ActorRef that contains all this above code which is the MasterActor. Am I correct?
How do I know explicitly that this ActorRef that I'm trying to stop is actually stopped so that I can do a context.unwatch(actorRef) as soon as it is stopped?
Any suggestions?
You can be notified of the stop of an Actor by watching it. You are already familiar with watch:
val kenny = context.actorOf(Props[Kenny], name = "Kenny")
context.watch(kenny)
and then you can wait for a Terminated message. Once you receive it, you can unwatch what you need.
def receive = {
case Terminated(kenny) => println("OMG, they killed Kenny")
case _ => println("Parent received a message")
}
So my reccomendation would be to simply watch, become waiting for terminated, and issue the stop command. But I'm unsure what you are asking exactly, so this cvould be the wrong ans
Blog post example
Writing a few small experiments to familiarise myself with the language, but have run into an issue which I'm guessing is elementary.
I have a simple supervisor, with 3 simple workers:
def init do
Supervisor.start_link(
[
worker(__MODULE__, [:"process-1"], [function: :test, id: :"p-1"]),
worker(__MODULE__, [:"process-2"], [function: :test, id: :"p-2"]),
worker(__MODULE__, [:"process-3"], [function: :test, id: :"p-3"])
],
strategy: :one_for_one
)
end
":test" looks like this:
def test(name) do
flag(:trap_exit, true)
IO.puts "Testing: #{name} == #{inspect self}"
register(self, name)
receive do
{ :death } ->
IO.puts("I WOZ MURDERED!")
exit(self, "Ex process...")
{ :life } ->
IO.puts("#{inspect self} is listening...")
__MODULE__.test(name)
{ :EXIT, pid, reason } ->
IO.puts "REASON: #{inspect reason} - PROCESS: #{inspect pid}"
end
end
This compiles, but it only ever spawns one process, and hangs/blocks iex.
In contrast, when I use a simple chain of 'spawn_link'ed' processes, all three (or however many) processes start concurrently and return control to the iex shell so I can send the registered processes messages from the command line.
My intention, for now, is to create an OTP supervisor, run and register three (or however many) workers processes and attach them to the supervisor, send a simple message to kill a given worker, and then have the supervisor restart it.
What am I doing wrong?
The problem is the function: you're giving as part of the worker specification doesn't do what OTP expects.
From http://www.erlang.org/doc/man/supervisor.html
The start function must create and link to the child process, and
should return {ok,Child} or {ok,Child,Info} where Child is the pid of
the child process and Info an arbitrary term which is ignored by the
supervisor.
Your code doesn't spawn a child but goes into a receive loop. You could perhaps use Elixir's Task module to do something similar to what it looks like you want:
worker(Task, [__MODULE__, :test, [:"process-1"]], id: :"p-1"),
worker(Task, [__MODULE__, :test, [:"process-2"]], id: :"p-2"),
worker(Task, [__MODULE__, :test, [:"process-3"]], id: :"p-3")
However if you're looking to learn more about what OTP does then having a go at implementing your own GenServer might be a better option.
I'm trying to use Sidekiq with my app, but for some reason I get a undefined local variable or method "worker" for #<SolutionController:0xb55bc358>
I have sidekiq, sinatra and slim installed for the Sidekiq web UI, and it doesn't register anything. I do have sidekiq running in another terminal window for now.
Worker call :
worker.perform_async(#user)
My Worker :
# app/workers/worker.rb
class worker
include Sidekiq::Worker
sidekiq_options retry: false
def perform(s_user)
user = $client.user_timeline(s_user, exclude_replies: 1,include_rts: 1 ).take(10)
user.each do |t|
array_list = $client.retweeters_of(t.id)
end
limited_list = array_list
array = []
hash = {}
limited_list.each do |g|
hash = {:key => g.followers_count, :value => g.profile_image_url.to_s}
array.push(hash)
end
array.sort_by! {|h| h[:key]}
array.reverse!
final = array.take(10)
$redis.set("#{hash[:value]}", "#{hash[:value]}")
end
end
Thanks
I recommend a bit more descriptive name, with proper case. try renaming the class to MyWorker , the file to my_worker.rb and calling MyWorker.perform_async(#user)
What will happen, when I schedule a message in the constructor of my Actor and the actor fails (Exception) before the message was send?
When the actor is resumed or restarted, will the message send like nothing has happened?
When the actor is stopped, will the message send to the dead letter box?
When I start the timer in preStart(), will I have two scheduled message when the actor restarts after a failure?
The answers to your questions are as follows:
1) Yes, the actor will receive the message as long as you used the scheduler scheduleOnce variant that takes an ActorRef as an arg. Because an ActorRef is just a lightweight proxy based on an actor address, it can survive failures of the target actor and still route messages to it as long as it successfully restarts back up and re-binds to the address that the ActorRef represents/
2) Yes, if the ActorRef is for a path that is no longer represented in the ActorSystem then the message will be sent to deadletter instead.
3) Yes you will. If you do it in preStart or in the body of the actor (constructor) and the actor fails and restarts, then the scheduled will now have two jobs to do for the same ActorRef and thus two requests will eventually be received.
A little code to show all of this in action. Consider the following actor:
class TestSchedActor extends Actor{
import context._
override def preStart = {
context.system.scheduler.scheduleOnce(1 second, self, "bar")
}
def receive = {
case "foo" =>
val s:String = null
s.length
case "baz" =>
context stop self
case other =>
println(s"Got $other")
}
}
If you tested it in this way:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "foo"
Then the output would be:
[ERROR] [04/03/2014 07:58:24.988] [schedtest-akka.actor.default-dispatcher-2] [ akka://schedtest/user/$a] null
java.lang.NullPointerException
at code.TestSchedActor$$anonfun$receive$1.applyOrElse(Asking.scala:27)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
at akka.actor.ActorCell.invoke(ActorCell.scala:456)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)
at akka.dispatch.Mailbox.run(Mailbox.scala:219)
at akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)
Got bar
Got bar
This shows both #1 and #3 as the actor still received the message after failure and actually received 2 as it re-scheduled again when it was restarted.
If you tested the actor like this:
val system = ActorSystem("schedtest")
val ref = system.actorOf(Props[TestSchedActor])
ref ! "baz"
Then you would see the following output:
[INFO] [04/03/2014 08:01:14.199] [schedtest-akka.actor.default-dispatcher-2] [akka://schedtest/user/$a] Message [java.lang.String] from
Actor[akka://schedtest/user/$a#687201705] to Actor[akka://schedtest/user/$a#687201705] was
not delivered. [1] dead letters encountered. This logging can be turned off or adjusted
with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
Provided you had not disabled deadletter logging.
I assume that your actor sends a message (using a scheduled task) to itself (using something like system.actorSelection to resolve self address).
Then:
1) Yes;
2) Yes;
3) Yes (moreover, if you start the timer in the constructor you'll get the same behavior).
To avoid all such issues you can start the timer in preStart(), save the received Cancellable into a local variable inside the Actor and then cancel it in postStop(). postStop() / preStart() are called from preRestart() / postRestart(), so your scheduled task will be rescheduled on Actor restarts and cancelled on Actor stop.
I'm trying to write a reusable component in Groovy to easily shoot off emails from some of our Java applications. I would like to pass it a List, where Email is just a POJO(POGO?) with some email info. I'd like it to be multithreaded, at least running all the email logic in a second thread, or make one thread per email.
I am really foggy on multithreading in Java so that probably doesn't help! I've attempted a few different ways, but here is what I have right now:
void sendEmails(List<Email> emails) {
def threads = []
def sendEm = emails.each{ email ->
def th = new Thread({
Random rand = new Random()
def wait = (long)(rand.nextDouble() * 1000)
println "in closure"
this.sleep wait
sendEmail(email)
})
println "putting thread in list"
threads << th
}
threads.each { it.run() }
threads.each { it.join() }
}
I was hoping the sleep would randomly slow some threads down so the console output wouldn't be sequential. Instead, I see this:
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
putting thread in list
in closure
sending email1
in closure
sending email2
in closure
sending email3
in closure
sending email4
in closure
sending email5
in closure
sending email6
in closure
sending email7
in closure
sending email8
in closure
sending email9
in closure
sending email10
sendEmail basically does what you'd expect, including the println statement, and the client that calls this follows,
void doSomething() {
Mailman emailer = MailmanFactory.getExchangeEmailer()
def to = ["one","two"]
def from = "noreply"
def li = []
def email
(1..10).each {
email = new Email(to,null,from,"email"+it,"hello")
li << email
}
emailer.sendEmails li
}
To get you example above running concurrently you have to replace the line
threads.each { it.run() }
with
threads.each { it.start() }
as run() doesn't start a new thread and thus your code was running sequentially.
There's also a Groovy extension available called GPars. It supports several concurrency techniques like Fork/Join or the Actor model. Using GPars, your code could be simplified to this:
def sendEmails(emails) {
GParsPool.withPool {
emails.eachParallel { email ->
def wait = (long) new Random().nextDouble() * 1000
println "in closure"
this.sleep wait
sendEmail(email)
}
}
}
A couple of Java versions back (1.5) they introduced some new concurrency stuff that makes Java threading (even more) simple. Google for java ThreadExecutor, and you'll find some pages such as:
http://www.deitel.com/articles/java_tutorials/20051126/JavaMultithreading_Tutorial_Part4.html
Whether Groovy makes it even simpler, I can't say, but you might want apply the "new" Java techniques to your Java example first before making the comparison.