Надеюсь, кто-то может помочь мне понять, вижу ли я проблему или просто не понимаю поведение хвостового курсора mongodb. Я использую mongodb 2.0.4 и pymongo 2.1.1.
Вот скрипт, демонстрирующий проблему.
#!/usr/bin/python
import sys
import time
import pymongo
MONGO_SERVER = "127.0.0.1"
MONGO_DATABASE = "mdatabase"
MONGO_COLLECTION = "mcollection"
mongodb = pymongo.Connection(MONGO_SERVER, 27017)
database = mongodb[MONGO_DATABASE]
if MONGO_COLLECTION in database.collection_names():
database[MONGO_COLLECTION].drop()
print "creating capped collection"
database.create_collection(
MONGO_COLLECTION,
size=100000,
max=100,
capped=True
)
collection = database[MONGO_COLLECTION]
# Run this script with any parameter to add one record
# to the empty collection and see the code below
# loop correctly
#
if len(sys.argv[1:]):
collection.insert(
{
"key" : "value",
}
)
# Get a tailable cursor for our looping fun
cursor = collection.find( {},
await_data=True,
tailable=True )
# This will catch ctrl-c and the error thrown if
# the collection is deleted while this script is
# running.
try:
# The cursor should remain alive, but if there
# is nothing in the collection, it dies after the
# first loop. Adding a single record will
# keep the cursor alive forever as I expected.
while cursor.alive:
print "Top of the loop"
try:
message = cursor.next()
print message
except StopIteration:
print "MongoDB, why you no block on read?!"
time.sleep(1)
except pymongo.errors.OperationFailure:
print "Delete the collection while running to see this."
except KeyboardInterrupt:
print "trl-C Ya!"
sys.exit(0)
print "and we're out"
# End
Итак, если вы посмотрите на код, довольно просто продемонстрировать проблему, с которой я столкнулся. Когда я запускаю код для пустой коллекции (правильно закрытой и готовой к хвосту), курсор умирает, и мой код завершается после одного цикла. Добавление первой записи в коллекцию заставляет ее вести себя так, как я ожидаю от хвостового курсора.
Кроме того, как обстоят дела с исключением StopIteration, убивающим cursor.next(), ожидающим данных? Почему серверная часть не может просто заблокировать, пока данные не станут доступными? Я предполагал, что await_data на самом деле что-то сделает, но кажется, что это только заставляет соединение ждать на секунду или две дольше, чем без него.
В большинстве примеров в сети показано размещение второго цикла While True вокруг цикла cursor.alive, но затем, когда скрипт заканчивает пустую коллекцию, цикл просто крутится и крутится, тратя процессорное время впустую. Я действительно не хочу вводить ни одной поддельной записи, чтобы избежать этой проблемы при запуске приложения.