Problema con sidekiq

L’ho posato sulla lista di sidekiq, lo posto pure qua magari c’
qualcuno che, per non lo traduco, scusate!

I have a worker which sends an email then writes to database. To avoid
to send the same email twice, as a safety measure, I generate a SHA from
email address + body.

Code looks like this, more or less:

 if EmailDigest.find_by_hash_id(composer.hash_id)
   Rails.logger.warn("Skipping email delivery for 

#{composer.hash_id}")
else
DigestMailer.digest(composer).deliver
EmailDigest.create!(hash_id: composer.hash_id)
end

The problem is that I received a few exceptions on create! line, because
hash_id was already taken, which is what the first line should check
for.

So I’m assuming there’s some concurrency issue, but the only thing I can
think of is two sidekiq worker working on the same queued item.
Or a worker working on the same item again. Is there any way to make
this happen? Any advice to give?

In pratica come se il primo controllo venisse bypassato. Boh.
Grattacapo.

-f

Hai provato ad usare find_or_create_by?
In generale sidekiq ha di questi problemi proprio perche’ e’ multithread
e volendo anche multiprocesso.

Se cerchi nel wiki del progetto ti fa capire che casi del genere possono
capitare tranquillamente, l’importante
e’ che i worker siano idempotenti in modo tale che possono essere
eseguiti anche diverse volte (anche
dando errore) senza realmente provocare alcun danno.

Ti consiglio di dare un’occhiata qui:

Se proprio invece vuoi processare con certi limiti (anche se credo sia
sconsigliato da sidekiq stesso),
puoi usare: GitHub - deanpcmad/sidekiq-limit_fetch: A Sidekiq plugin to support advanced queue control (limiting, pausing, blocking, querying)

Ciao


Matteo L.

Il giorno 17/apr/2013, alle ore 11:57, Fabrizio R.
[email protected] ha scritto:

Avevo letto le best practices, per questo ho impostato quel controllo di
sicurezza. Ma sinceramente pensavo si trattasse di edge cases non di
normale operativit. Ho cominciato a lavorarci da poco ed errori del
genere accadono molto di frequente.

-f

Grazie. Per il momento ho optato per una scelta diversa.
Essenzialmente ho eliminato il controllo preventivo, e mi affido alla
exception potenziale del database per decidere se spedire l’email. Non
perfetto perch l’invio dell’email pu sempre fallire dopo che ho
salvato il record nel database.
Poi mi rinfresco la memoria con il tutorial che mi hai mandato. Ed
eventualmente rifattorizzo tutto dopo che capito bene come padroneggiare
la Forza.

-f

2013/4/17 Fabrizio R. [email protected]

  EmailDigest.create!(hash_id: composer.hash_id)
end

The problem is that I received a few exceptions on create! line, because
hash_id was already taken, which is what the first line should check for.

So I’m assuming there’s some concurrency issue, but the only thing I can
think of is two sidekiq worker working on the same queued item.
Or a worker working on the same item again. Is there any way to make this
happen? Any advice to give?

In pratica come se il primo controllo venisse bypassato. Boh. Grattacapo

:slight_smile:

Benvenuto nella programmazione multithread.

Prova cos:

require ‘thread’
mutex = Mutex.new

if EmailDigest.find_by_hash_id(**composer.hash_id)
   Rails.logger.warn("Skipping email delivery for 

#{composer.hash_id}")
else
mutex.synchronize do
if not EmailDigest.find_by_hash_id(**composer.hash_id)
DigestMailer.digest(composer).**deliver
EmailDigest.create!(hash_id: composer.hash_id)
end
end
end

Certo che il multithreaded programming … che noia.

Non c’ un modo pi elegante ?
:wink:

S.