Pregunta

Considere una aplicación GAE (Python) que permite a los usuarios comentan sobre las canciones. El número esperado de usuarios es de 1.000.000. El número esperado de canciones es 5000.

La aplicación debe ser capaz de:

  • Dar el número de canciones que un usuario ha comentado
  • Dar el número de usuarios que han comentado una canción

gestión de contador debe ser transaccional para que siempre reflejan los datos subyacentes.

Parece aplicaciones GAE debe mantener estos tipos de conteos calculados en todo momento desde la consulta por ellos durante la petición sería ineficiente.

Mi modelo de datos

class Song(BaseModel):
    name = db.StringProperty()
    # Number of users commenting on the song
    user_count = db.IntegerProperty('user count', default=0, required=True)
    date_added = db.DateTimeProperty('date added', False, True)
    date_updated = db.DateTimeProperty('date updated', True, False)

class User(BaseModel):
    email = db.StringProperty()
    # Number of songs commented on by the user
    song_count = db.IntegerProperty('song count', default=0, required=True)
    date_added = db.DateTimeProperty('date added', False, True)
    date_updated = db.DateTimeProperty('date updated', True, False)

class SongUser(BaseModel):
    # Will be child of User
    song = db.ReferenceProperty(Song, required=True, collection_name='songs')
    comment = db.StringProperty('comment', required=True)
    date_added = db.DateTimeProperty('date added', False, True)
    date_updated = db.DateTimeProperty('date updated', True, False)

Código
Este se encarga de recuento de canciones del usuario transaccionalmente pero no número de usuarios de la canción.

s = Song(name='Hey Jude')
s.put()

u = User(email='me@example.com')
u.put()

def add_mapping(song_key, song_comment, user_key):
    u = User.get(user_key)

    su = SongUser(parent=u, song=song_key, song_comment=song_comment, user=u);
    u.song_count += 1

    u.put()
    su.put()

# Transactionally add mapping and increase user's song count
db.run_in_transaction(add_mapping, s.key(), 'Awesome', u.key())

# Increase song's user count (non-transactional)
s.user_count += 1
s.put()

La pregunta es:? ¿Cómo puedo manejar ambos contadores transaccionalmente

En base a mi entendimiento que esto sería imposible, ya usuario, Song, y SongUser tendría que ser una parte de la misma grupo de entidades . No pueden estar en un grupo de entidades porque entonces todos mis datos estarían en un grupo y no podía ser distribuido por el usuario.

¿Fue útil?

Solución

En realidad, no debería tener que preocuparse por el manejo de la cuenta del usuario de canciones en las que han comentado dentro de una transacción, ya que parece poco probable que un usuario sería capaz de comentar en más de una canción a la vez, ¿verdad?

Ahora, es sin duda el caso de que muchos usuarios podrían comentando sobre la misma canción al mismo tiempo, de modo que es donde tiene que preocuparse acerca de asegurarse de que los datos no se hace inválida por una condición de carrera.

Sin embargo, si se mantiene la cuenta del número de usuarios que han comentado una canción dentro de la entidad de la canción, y bloquear la entidad con una transacción, se le va a poner muy alta la pelea por esa entidad y del almacén de datos los tiempos de espera harán que la aplicación tiene un montón de problemas.

Esta respuesta para este problema es contadores fragmentados .

Con el fin de asegurarse de que se puede crear una nueva entidad SongUser y actualizar contador fragmentada de la canción relacionada, se debe considerar que la entidad SongUser han relacionado la canción como un padre. Eso va a poner en el mismo grupo de entidades y se puede tanto crear el SongUser y actualizada del mostrador fragmentada en la misma transacción. La relación de la SongUser al usuario que lo creó se puede mantener en un ReferenceProperty.

En cuanto a su preocupación por los dos cambios (el transaccional y la actualización del usuario) no las dos siguientes, que es siempre una posibilidad, pero teniendo en cuenta que, o bien la actualización puede fallar, necesitará tener adecuado de control de excepciones para asegurar que tanto tener éxito. Eso es un punto importante: el de transacción por las actualizaciones no están garantizados para tener éxito. Usted puede obtener una excepción TransactionfailedError si la transacción no se puede completar por cualquier motivo.

Por lo tanto, si la transacción se completa sin generar una excepción, ejecutar la actualización de usuario en una transacción. Eso hará que se reintentos automáticos de la actualización al usuario, en caso de producirse algún error. A menos que haya algo acerca de la posible contención en la entidad Usuario que no entiendo, la posibilidad de que no va a tener éxito con el tiempo es incomparablemente pequeña . Si ese es un riesgo inaceptable, entonces no creo que eso AppEngine tiene una solución perfecta a este problema para usted.

En primer lugar preguntarse: ¿es realmente tan malo si el recuento de canciones que alguien ha comentado está apagado por uno? Es esto tan crítica como la actualización de un saldo de la cuenta bancaria o de completar una venta de acciones?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top