Hola amigos.

Tengo este problemita en manos y antes de hacer chanchadas me gustaría
saber si alguien tiene sugerencias al respecto. Estoy intentando
arreglar un problema en un código hecho por otra gente, y más allá de
que cuesta entenderlo, creo que ya sé qué está pasando.
Lamentablemente por temas de Non-Disclosure Agreements no puedo poner
mucho código acá... pero les explico.

Cada tanto (especialmente en horas pico) nos aparece en el log del
postgres este error:
PGError: ERROR: duplicate key violates unique constraint
"blogger_group_blog_entries_blogger_group_id_blog_entry_id":

Ese índice está definido así:
"blogger_group_blog_entries_blogger_group_id_blog_entry_id" UNIQUE,
btree (blogger_group_id, blog_entry_id)

Este es un ejemplo de insert que dispara ese error:
INSERT INTO blogger_group_blog_entries ("featured", "blocked",
"blogger_group_id", "blog_entry_id", "active", "agent_id") VALUES('f',
'f', 231, 462217, 't', 51023)


Lo que me llamó la atención, es que si uno sigue el código esto no
"debería" suceder nunca. El código en cuestión se ejecuta cuando se
crea o modifica un BlogEntry. Cuando se trata de una modificación, por
cuestiones que no vienen al caso se debe "reconstruir" todos los
BloggerGroupBlogEntry (registros de la tabla
blogger_group_blog_entries) entonces la cosa es más o menos así
(simplificado):

# Se borran los registros actuales relacionados con este agente y este
blog_entry, .
BloggerGroupBlogEntry.delete_all("agent_id = " + @agent.id.to_s + "
and blog_entry_id = " + @blog_entry.id.to_s)
# Ahora se vuelven a crear los registros uno a uno. Sí, son los mismos
registros en cuanto a ids y relaciones, sólo tienen cambios en campos
NO relevantes al índice único y todo eso.
@blogger_groups.each do |bg|
  bgbe = BloggerGroupBlogEntry.new
  bgbe.blogger_group_id = bg.id
  bgbe.blog_entry_id = @blog_entry.id
  bgbe.agent_id = @agent.id
  #bgbe ... seteo de otros datos no relevantes ...
  bgbe.save
end

No es código mío... yo sólo trato de arreglar el error... :)

Entonces, como ven... esto no debería dar clave duplicada, pues los
registros que estoy insertando, primero fueron borrados, y como ya
existían, cumplían la unicidad del índice.

Ahora viene mi deducción: Este problema sucede casi únicamente en
ocasiones donde el sitio ha estado muy sobrecargado, con varios miles
de usuarios simultáneos usándolo, y con algún problema de performance
en el hardware. En esas ocasiones, los usuarios suelen ser muy
impacientes y hacen el submit del formulario repetidamente... lo cual
ocasiona varios requests con los mismos parámetros ejecutándose al
mismo tiempo.

Mi teoría es que dos o más requests simultáneos "compiten" por hacer
los MISMOS inserts y el más lento termina intentando insertar
registros que ya otro request insertó.

¿qué opinan?

Más allá de eso... ¿qué sugerencias me pueden dar para evitar este
problema? En lo posible evitando locks gigantes.

Gracias!

-- 
Diego Algorta Casamayou
http://www.oboxodo.com - http://diego.algorta.net
_______________________________________________
Ruby mailing list
[email protected]
http://lista.rubyargentina.com.ar/listinfo.cgi/ruby-rubyargentina.com.ar

Responder a