Tornado嵌入式协程并将数据保存到db

时间:2014-11-28 14:22:23

标签: mongodb asynchronous tornado coroutine tornado-motor

我正在使用的堆栈包括龙卷风(异步)和mongodb(电机) 我有以下算法来处理请求数据:

    来自传入请求的
  1. 数据将保存到特定于事件的集合
  2. 数据正在保存到统一的事件集合
  3. 这是请求处理程序代码:

    class EventHandler(BaseHandler):
        """ Handles all event requests
        """
    
        @gen.coroutine
        def post(self):
            """ Posts an event data
            """
            yield gen.Task(self.check_auth)
            self.validate_data()
            yield self._save_user()
    
            status_msg = yield self.save_entity()
            yield self.save_event()
    
            self.set_status(200, reason="OK, {}".format(status_msg))
    

    以下是方法的代码,从请求处理程序

    调用
    @gen.coroutine
    def save_entity(self):
        """ Saves event entity data for proper collection. Entities: orders, pageviews, users etc
        """
        event = self.data.get("event_type")
        if event not in self._event_schema_map.keys():
            raise Return("No specific entity, just event")
        try:
            if event == "cart_add":
                msg = yield gen.Task(self._save_product)
            elif event == "cart_delete":
                msg = yield gen.Task(self._delete_product)
            elif event == "pageview":
                msg = yield gen.Task(self._save_pageview)
            elif event == "order_complete":
                msg = yield gen.Task(self._save_order)
            elif event in ["email_known", "email_form"]:
                msg = yield gen.Task(self._save_email)
        except Exception as e:
            raise HTTPError(500, log_message=str(e))
        raise Return(msg)
    
    @gen.coroutine
    def save_event(self, event=None, event_type=None, event_data=None):
        """ Saves event data to db. Works both as standalone method and as plug-in method
        :param event: event name
        :param event_type: event type
        :param event_data: dict with event-specific infoelements data
        """
        yield self.motor.events.insert(
            {
                "client_id": self.data.get("client_id"),
                "user_id": self.data.get("user_id"),
                "timestamp": datetime.now(),
                "event": self.data.get("event", event),
                "event_type": self.data.get("event_type", event_type),
                "event_data": self.data.get("event_data", event_data),
                "event_url": self.data.get("event_url"),
                "utms": self.data.get("utms"),
                "analytics_short": self.data.get("analytics_short"),
                "analytics_long": self.data.get("analytics_long")
            }
        )
    

    所有_save_%smth%只是简单的电机CRUD操作,封装在函数调用中并包装在@engine装饰器中,如下所示:

    @gen.engine
    def _save_product(self, callback=None):
        """ Adds product to user's cart
        """
        cart_data = self.data.get("event_data")[0]
        try:
            yield self.motor.users.update(
                {"_id": self.data["user_id"], "client_id": self.data["client_id"]},
                {
                    '$set': {
                        "cart_updated_at": datetime.now(),
                        "reminder": False,
                    },
                    '$push': {
                        "items": {
                            "product_id": cart_data.get("product_id"),
                            "image": cart_data.get("image"),
                            "title": cart_data.get("title"),
                            "price": int(cart_data.get("price"))
                        }
                    }
                },
                upsert=True
            )
        except Exception as e:
            raise HTTPError(500, log_message=str(e))
        callback("New product in cart record added")
    
    @gen.engine
    def _save_order(self, callback=None):
        """ Saves order data to user's orders
        """
        order_data = self.data.get("event_data")
        try:
            yield self.motor.orders.update(
                {"user_id": self.data["user_id"], "client_id": self.data["client_id"]},
                {
                    '$push': {
                        "orders": {
                            "completed_at": datetime.now(),
                            "analytics_short": self.data["analytics_short"],
                            "analytics_long": self.data["analytics_long"],
                            "utms": self.data["utms"],
                            "items": [
                                {
                                    "product_id": i["product_id"],
                                    "price": int(i["price"]),
                                    "quantity": int(i["quantity"])
                                }
                                for i in order_data
                            ]
                        }
                    }
                },
                upsert=True,
            )
        except Exception as e:
            raise HTTPError(500, log_message="Error in order updating: {}".format(e))
        try:
            yield self.motor.users.update(
                {"_id": self.data["user_id"], "client_id": self.data["client_id"]},
                {
                    "$unset": {
                        "cart_created_at": '',
                        "cart_updated_at": '',
                        "reminder": '',
                        "items": ''
                    }
                }
            )
        except Exception as e:
            raise HTTPError(500, log_message="Error in cart updating: {}".format(e))
        callback("Order record added")
    

    因此请求数据在 save_entity 函数中保存两次 save_entity 函数中的“特定一个”和 save_event 中的“通用一个” FUNC。但实际上,我看到,经常(有50%的情况)被遗漏(数据未保存)并执行第二次保存。

    所有数据处理和验证都是在之前进行的,所以假设,抛出到mongo的数据是合适且有效的。

    所以我想弄清楚,这种情况会怎样。我的猜测是save_entity函数设计错误,并且由于几个嵌入式函数,请求本身完成,数据不会保存到db。可能是吗?

    UPD 添加了生产代码,所以现在情况会更清楚。我希望:) UPD 2 添加了几种CRUD方法

1 个答案:

答案 0 :(得分:0)

"更新"需要两个参数:一个指定要更新的文档的查询和一个更新文档。该查询遵循与find()或find_one()相同的语法。更新文档有两种模式:它可以替换整个文档,也可以更新文档的某些字段。 "更新"还需要一些可选参数,包括" multi"并且" upsert"。有关"更新"的更多信息方法,请参阅教程:

http://motor.readthedocs.org/en/stable/tutorial.html#updating-documents

在您的密码中,您拨打"更新"第一个参数但不是第二个参数。我希望你的代码丢弃" TypeError:update()缺少1个必需的位置参数:' document'",并且异常被吞下或丢失在日志文件中,某处更高你的通话链。