تحديثات مخزن البيانات الآمن من الفشل على محرك التطبيق

StackOverflow https://stackoverflow.com/questions/3800263

سؤال

بطبيعة الحال التوقف. ومع ذلك ، أود الحصول على "آمن" الفشل وضع وهو أكثر قوة في مواجهة أخطاء مخزن البيانات (انظر الدافع أدناه). يبدو أن قائمة انتظار المهمة هي مكان واضح للتأجيل عندما يكون مخزن البيانات غير متاح. لا أعرف أي حلول أخرى (بخلاف شحن البيانات إلى طرف ثالث عبر urlfetch).

تحفيز: لدي كيان هل حقا يجب وضعها في مخزن البيانات - ما عليك سوى عرض رسالة خطأ إلى المستخدم لن يفعله. على سبيل المثال ، ربما حدث بعض الآثار الجانبية التي لا يمكن التراجع عنها بسهولة (ربما بعض التفاعل مع موقع طرف ثالث).

لقد توصلت إلى غلاف بسيط يوفر (على ما أظن) "آمنًا" معقولًا (انظر أدناه). هل ترى أي مشاكل مع هذا ، أو لديك فكرة عن تنفيذ أكثر قوة؟ (ملاحظة: بفضل الاقتراحات المنشورة في إجابات نيك جونسون وساكسون دروس ، تم تحرير هذا المنشور مع بعض التحسينات على الكود.)

import logging
from google.appengine.api.labs.taskqueue import taskqueue
from google.appengine.datastore import entity_pb
from google.appengine.ext import db
from google.appengine.runtime.apiproxy_errors import CapabilityDisabledError

def put_failsafe(e, db_put_deadline=20, retry_countdown=60, queue_name='default'):
    """Tries to e.put().  On success, 1 is returned.  If this raises a db.Error
    or CapabilityDisabledError, then a task will be enqueued to try to put the
    entity (the task will execute after retry_countdown seconds) and 2 will be
    returned.  If the task cannot be enqueued, then 0 will be returned.  Thus a
    falsey value is only returned on complete failure.

    Note that since the taskqueue payloads are limited to 10kB, if the protobuf
    representing e is larger than 10kB then the put will be unable to be
    deferred to the taskqueue.

    If a put is deferred to the taskqueue, then it won't necessarily be
    completed as soon as the datastore is back up.  Thus it is possible that
    e.put() will occur *after* other, later puts when 1 is returned.

    Ensure e's model is imported in the code which defines the task which tries
    to re-put e (so that e can be deserialized).
    """
    try:
        e.put(rpc=db.create_rpc(deadline=db_put_deadline))
        return 1
    except (db.Error, CapabilityDisabledError), ex1:
        try:
            taskqueue.add(queue_name=queue_name,
                          countdown=retry_countdown,
                          url='/task/retry_put',
                          payload=db.model_to_protobuf(e).Encode())
            logging.info('failed to put to db now, but deferred put to the taskqueue e=%s ex=%s' % (e, ex1))
            return 2
        except (taskqueue.Error, CapabilityDisabledError), ex2:
            return 0

طلب معالج للمهمة:

from google.appengine.ext import db, webapp

# IMPORTANT: This task deserializes entity protobufs.  To ensure that this is
#            successful, you must import any db.Model that may need to be
#            deserialized here (otherwise this task may raise a KindError).

class RetryPut(webapp.RequestHandler):
    def post(self):
        e = db.model_from_protobuf(entity_pb.EntityProto(self.request.body))
        e.put() # failure will raise an exception => the task to be retried

أنا لا نتوقع استخدام هذا ل كل ضع - في معظم الوقت ، فإن إظهار رسالة الخطأ على ما يرام. من المغري استخدامه لكل وضع ، لكنني أعتقد في بعض الأحيان أنه قد يكون الأمر أكثر إرباكًا للمستخدم إذا أخبرتهم أن تغييراتهم ستظهر لاحقًا (وتستمر في إظهار البيانات القديمة حتى يتم نسخ مخزن البيانات احتياطيًا و المؤجل يضع التنفيذ).

هل كانت مفيدة؟

المحلول

نهجك معقول ، ولكن لديه العديد من التحذيرات:

  • بشكل افتراضي ، ستتم إعادة تشغيل عملية PUT حتى تنفد من الوقت. نظرًا لأن لديك استراتيجية احتياطية ، فقد ترغب في الاستسلام عاجلاً - وفي هذه الحالة يجب عليك توفير معلمة RPC لمكالمة طريقة PUT ، مع تحديد موعد نهائي مخصص.
  • ليست هناك حاجة إلى تعيين العد التنازلي الصريح - ستقوم قائمة انتظار المهمة بإعادة إعادة محاكمة العمليات الفاشلة لك على فترات زمنية متزايدة.
  • لا تحتاج إلى استخدام مخازن المؤسسات المخللة - تحتوي مخازن البروتوكول على ترميز طبيعي أكثر كفاءة. يرى هذا المشنور لإظهار كيفية استخدامه.
  • كما يشير Saxon ، تقتصر حمولات قائمة انتظار المهام على 10 كيلوغرامات ، لذلك قد تواجه مشكلة مع كيانات كبيرة.
  • الأهم من ذلك ، أن هذا يغير نموذج اتساق مخزن البيانات من "متسق بقوة" إلى "ثابت في النهاية". وهذا يعني ، يمكن تطبيق وضعك على قائمة انتظار المهمة في أي وقت في المستقبل ، مما يؤدي إلى الكتابة فوق أي تغييرات تم إجراؤها في غضون ذلك. أي عدد من شروط السباق ممكن ، مما يجعل المعاملات غير مجدية بشكل أساسي إذا كان هناك معلقة في قائمة انتظار المهمة.

نصائح أخرى

إحدى القضايا المحتملة هي ذلك تقتصر المهام على 10 كيلو بايت من البيانات, ، لذلك لن ينجح هذا إذا كان لديك كيان أكبر من ذلك بمجرد مخلل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top