分布式爬虫的爬虫端（具体爬虫部分）
    被包装的函数必须满足如下要求：
       1. 有且仅有一个参数
       2. 对于每个任务，返回两个参数： code, message

    :param cfg_uri: 读取任务的路径
    :param queue: Queue的名字
    :param logger: 日志记录工具
    :param fetchsize: 每次取出消息数量

def consumer(cfg_uri, queue, logger=None, fetchsize=1):
    """
    分布式爬虫的爬虫端（具体爬虫部分）
    被包装的函数必须满足如下要求：
       1. 有且仅有一个参数
       2. 对于每个任务，返回两个参数： code, message

    :param cfg_uri: 读取任务的路径
    :param queue: Queue的名字
    :param logger: 日志记录工具
    :param fetchsize: 每次取出消息数量
    """
    from stompest.protocol import StompSpec

    _info, _exception = _deal_logger(logger)
    cfg_uri = _build_uri(cfg_uri)

    def decorator(function):

        def _build_conn():
            client = _conn(cfg_uri, queue, _info)
            client.subscribe(queue, {
                StompSpec.ACK_HEADER: StompSpec.ACK_CLIENT_INDIVIDUAL,
                'activemq.prefetchSize': fetchsize
            })
            return client

        @wraps(function)
        def wapper():
            client = _build_conn()
            while True:
                try:
                    frame = client.receiveFrame()
                    _info('got new frame %s' % frame)
                    param = loads(frame.body)
                    code, msg = function(param)
                    _info('result of task [%s]: [%s]-[%s]' % (frame.body, code, msg))
                except (KeyboardInterrupt, AssertionError, ConsumerFatalError), e:
                    _exception(e)
                    break
                except Exception, e:
                    _exception(e)
                finally:
                    try:
                        client.ack(frame)
                    except Exception, e:
                        _exception(e)
                        client.close()
                        client = _build_conn()
            client.disconnect()
            _info('disconnected %s' % cfg_uri)
        return wapper
    return decorator