Tornado 中 self.write("hello")出现"Broken pipe Error",如何解决?


其实这里就是解决 微信公众号的5秒重传机制 ,使得公众号后台能获得充裕的处理时间 (5+5+5)s
我的做法是(以下针对微信公众号的文本消息):
要想突破5秒时间的响应限制,可以根据文本消息中唯一值MsgId进行排重。当普通微信用户向公众账号发消息时,微信服务器将POST消息的XML数据包发到开发者填写的URL上进行处理,开发者服务器首先对每个到来的文本消息利用memcached,以MsgId为键,值为1,设置 set(MsgId, 1) ,然后进行响应处理,若处理完成会更改MsgId对应的值为某一字符串。而当这次请求响应无法在5秒内完成,微信服务器将用第一次同样的XML数据包(MsgId相同)发起第二次请求,这样开发者服务器通过get(MsgId)的值进行判断,若 get(MsgId) 为1,则令其自增 incr(MsgId) 为2。然后进行等待直到 get(MsgId) 不为1或2或3。若 get(MsgId) 不为1或2或3,则直接响应微信服务器,响应完成。第三次请求同理。下面是此想法的实现为代码:


 class WeixinHandler(tornado.web.RequestHandler):
    def post(self):
        # 省略文本解析...
        key = msgId
        if mc.get(key) == None:
            mc.set(key, 1)
        elif mc.get(key) == 1 or mc.get(key) == 2:
            mc.incr(key)

        if mc.get(key) == 1:
            # 任务处理
        elif mc.get(key) == 2:
            # 无限等待 mc.get(key) != 2 and mc.get(key) != 3
        elif mc.get(key) == 3:
            if mc.get(key) == 3:
                mc.set(key, u'任务无法完成')
            else:
                pass
        else:
            pass
        self.write(mc.get(key))
        mc.delete(key) # 每次请求都会调用,这样的话,一个失败的`write`(上面的
                       # 语句)就会导致其它的请求响应异常了。

这里的问题是对于同一个消息的三次请求,每次都要 self.write() ,而若微信服务器发起了第二次请求,第一次请求就会在 self.write() 时出现 write error: broken pipe 而且接着又调用 mc.delete(key) 了,这样一来就会导致后续的请求响应乱套了,原本的第二次请求可能又会进行任务处理,可能导致无法响应微信服务器。我尝试用异常进行处理:


 try:
        self.write(mc.get(key))
    except IOError as e:
        print "write error ..."
        return
    mc.delete(key)

却仍然没有用,查看了Tornado中的 write函数源代码 发现其并未对 write error: broken pipe 抛出异常,使得 try... except ... 无法捕获。

各位大神,这个该如何解决啊,已经困扰我好几个月了。

python 微信 tornado

天然星☆↗ 10 years, 3 months ago

Your Answer