2012-07-10 10 views
10

Estoy usando el controlador mgo para MongoDB bajo Go.MongoDB en Go (golang) con mgo: ¿Cómo actualizo un registro, descubro si la actualización fue exitosa y obtengo los datos en una sola operación atómica?

Mi aplicación solicita una tarea (con solo un registro seleccione en Mongo de una colección llamada "trabajos") y luego se registra como un candidato para completar esa tarea (una actualización del mismo registro de "trabajo", configurándose como cesionario).

El programa se ejecutará en varias máquinas, todas hablando con el mismo Mongo. Cuando mi programa enumera las tareas disponibles y luego elige una, es posible que otras instancias ya hayan obtenido esa asignación y la asignación actual haya fallado.

¿Cómo puedo asegurarme de que el registro que leo y luego actualizo tiene o no un cierto valor (en este caso, un destinatario) en el momento de la actualización?

Estoy tratando de obtener una tarea, no importa cuál sea, así que creo que primero debería seleccionar una tarea pendiente e intentar asignarla, manteniéndola solo en el caso de que la actualización fuera exitosa.

lo tanto, mi consulta debe ser algo como:

"De todos los registros en la recopilación 'empleos', actualizar sólo una que tiene asignee = null, el establecimiento de identificación para el cesionario Entonces, dame. ese registro para poder ejecutar el trabajo ".

¿Cómo podría expresar eso con el controlador mgo para Go?

Respuesta

2

Espero que haya visto los comentarios sobre la respuesta que seleccionó, pero ese enfoque es incorrecto. Hacer una selección y luego actualizar dará como resultado un viaje de ida y vuelta y dos máquinas y estará buscando el mismo trabajo antes de que uno de ellos pueda actualizar el assignee. Es necesario utilizar el método findAndModify lugar: http://www.mongodb.org/display/DOCS/findAndModify+Command

+0

En realidad, la solución que necesito es la que tux21b ofrece. Necesito volver a seleccionar todas las "opciones", seleccionar una y luego intentar asignarla a mí mismo. Si no tiene éxito, lo probaría con otro. –

+0

¿Por qué necesita seleccionar TODAS las opciones? ¿Dijiste que solo necesitas seleccionar eso que no se tomó (también conocido como assignee == null)? –

+0

Tienes razón. Mis necesidades resultaron ser diferentes de lo que pensé cuando escribí la pregunta, pero su respuesta se ajusta mejor a la pregunta. –

2

chicos El MongoDB describen un escenario similar en la documentación oficial: http://www.mongodb.org/display/DOCS/Atomic+Operations

Básicamente, todo lo que tiene que hacer, es ir a buscar cualquier trabajo con assignee=null. Supongamos que obtiene el trabajo con el _id=42. A continuación, puede continuar y modificar el documento localmente, configurando assignee="worker1.example.com" y llamando al Collection.Update() con el selector {_id=42, assignee=null} y su documento actualizado. Si la base de datos todavía puede encontrar un documento que coincida con este selector, reemplazará el documento atómicamente. De lo contrario, obtendrá un ErrNotFound que indica que otro hilo ya ha reclamado la tarea. Si ese es el caso, intente de nuevo.

+4

Performing seleccione seguido de una actualización no es atómica; ¡realiza dos viajes de ida y vuelta! El comando findAndModify realizará esta operación atómicamente. Mongo documentos para este comando están aquí: http://www.mongodb.org/display/DOCS/findAndModify+Command Mgo documentos para hacer esto en Go están aquí: http://go.pkgdoc.org/labix .org/v2/mgo # Query.Aplicar – jorelli

+1

La selección + actualización no necesita ser atómica para este algoritmo en particular. Siempre que la actualización en sí sea atómica (que básicamente es una operación CompareAndSwap/CompareExchange) todo está bien. – tux21b

+1

Si dos máquinas seleccionan el mismo trabajo en la primera consulta, una de ellas fallará en la actualización. Claro, el resultado final puede ser siempre que los datos en la base de datos nunca se vuelven inconsistentes, pero el caso de falla al usar dos operaciones separadas causa una gran cantidad innecesaria de ida y vuelta. Esta es ... la razón completa por la que existe el comando findAndModify. – jorelli

41

Ésta es una vieja pregunta, pero por si acaso alguien todavía está mirando en casa, esto está muy bien soportado a través del método Query.Apply. Ejecuta el comando findAndModify como se indica en otra respuesta, pero se oculta convenientemente detrás de Go goodness.

El ejemplo en la documentación coincide casi exactamente la cuestión aquí:

change := mgo.Change{ 
     Update: bson.M{"$inc": bson.M{"n": 1}}, 
     ReturnNew: true, 
} 
info, err = col.Find(M{"_id": id}).Apply(change, &doc) 
fmt.Println(doc.N) 
Cuestiones relacionadas