推送(友盟、谷歌)

1霞玄、需求背景

app需要推送骤铃、如下線通知、折扣通知等

2坷剧、實(shí)現(xiàn)方式

采取將推送任務(wù)放在任務(wù)表中惰爬,然后在管理平臺構(gòu)建推送(異步)任務(wù),讀取推送任務(wù)表听隐,進(jìn)行實(shí)時推送

3补鼻、表設(shè)計(jì)

推送內(nèi)容表

class PushContentInfo(db.Model):
    __tablename__ = 'tb_push_content_info'

    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    content_title = db.Column(db.String(64), nullable=False, info={'label': '內(nèi)容標(biāo)題'})
    push_title = db.Column(db.String(64), nullable=False, info={'label': '推送標(biāo)題'})
    push_content = db.Column(db.String(255), nullable=False, info={'label': '推送內(nèi)容'})
    redirect_type = db.Column(db.Integer, nullable=False, info={'label': '跳轉(zhuǎn)位置'})
    redirect_url = db.Column(db.String(255), nullable=False, info={'label': '跳轉(zhuǎn)url'})
    push_target = db.Column(db.String(64), nullable=False, info={'label': '推送目標(biāo)'})
    message_save_hours = db.Column(db.Integer, nullable=False, default=0, info={'label': '消息離線保存時間'})
    add_time = db.Column(db.DateTime, nullable=False, default=db.func.now(), info={'label': '創(chuàng)建時間'})
    update_time = db.Column(db.DateTime, nullable=False, default=db.func.now(), info={'label': '更新時間'})

推送任務(wù)表

class PushNotifyRecord(db.Model):
    __tablename__ = 'tb_push_notify_record'

    id = db.Column(db.Integer, autoincrement=True, primary_key=True)
    uid = db.Column(db.String(64), nullable=False, info={'label': '用戶id'})
    # device_code = db.Column(db.String(64), nullable=False, info={'label': '設(shè)備碼'})
    notify_app_type = db.Column(db.String(32), nullable=False, default='all', info={'label': '推送目標(biāo)'})
    push_content_id = db.Column(db.Integer, nullable=False, default=0, info={'label': '推送目標(biāo)'})
    task_status = db.Column(db.Integer, nullable=False, default=0, info={'label': '規(guī)則狀態(tài)'})
    add_time = db.Column(db.DateTime, nullable=False, default=db.func.now(), info={'label': '創(chuàng)建時間'})
    update_time = db.Column(db.DateTime, nullable=False, default=db.func.now(), info={'label': '更新時間'})

注意:友盟推送只需要用戶id,因?yàn)橛衙丝梢詣e名推送、給每個用戶綁定唯一的別名(使用uid進(jìn)行綁定)
谷歌推送需要單獨(dú)的設(shè)備碼风范,由設(shè)備提供咨跌,每個設(shè)備具備單個設(shè)備碼,如果需要但用戶多設(shè)備推送硼婿,需要進(jìn)行用戶和設(shè)備的關(guān)聯(lián)

異步任務(wù):

@app.task()
def scan_for_push_to_user():
    """
    定時通知記錄表,用于通知用戶
    :return:
    """
    # 獲取待推送記錄
    print 'start scan_for_push_to_user'
    rs = redis.StrictRedis.from_url(settings.REDIS_URL)
    ret = rs.set('qms_push_user_lock', 1, nx=True, ex=20 * 60)
    if not ret:
        logger.info('[scan_for_push_to_user] being locked')
        return
    push_task_dict = {}
    need_push_records = PushNotifyRecord.objects.filter(task_status=0)
    for item_record in need_push_records:
        push_task_dict.setdefault(item_record.notify_app_type + '-' + str(item_record.push_content_id), []).append(
            item_record
        )

    for item_task in push_task_dict:
        list_length = len(push_task_dict[item_task])
        logger.info('[scan_for_push_to_user] task %s push member count %s', item_task, list_length)
        limit = 1000
        step = list_length / limit + 1
        push_app_type, push_content_id = item_task.split('-')
        for i in range(step):
            start = i * limit
            end = start + limit
            if start >= list_length:
                break
            task_id_list = [x.id for x in push_task_dict[item_task][start:end]]
            uid_list = [x.uid for x in push_task_dict[item_task][start:end]]
            ret = PushNotifyRecord.objects.filter(id__in=task_id_list, task_status=0).update(task_status=1)
            if ret != len(task_id_list):
                break
            push_to_user.delay(task_id_list, uid_list, push_app_type, push_content_id)
        # 開始友盟推送
        logger.info('u_push------start')
        push_content_info = PushContentInfo.objects.get(id=push_content_id)
        go_url = push_content_info.redirect_url
        task_id_list = [x.id for x in push_task_dict[item_task]]
        # 獲取到需要單獨(dú)設(shè)備發(fā)送的數(shù)據(jù)
        push_notify_wait = PushNotifyRecord.objects.filter(
            id__in=task_id_list,
            task_status=1
        ).all()
        task_code_list = []
        task_uid_list = []
        for i in push_notify_wait:
            if i.device_code:
                task_code_list.append(i.uid + ':' + i.device_code)
            else:
                task_uid_list.append(i.uid)
        if push_app_type == 'android' or push_app_type == 'all':
            android_push.u_group_push(task_code_list,
                                      push_content_info.push_title,
                                      push_content_info.push_content,
                                      'qy_uid_device_android',
                                      go_url, redirect_type=push_content_info.redirect_type)
            android_push.u_group_push(task_uid_list,
                                      push_content_info.push_title,
                                      push_content_info.push_content,
                                      'qy_android',
                                      go_url, redirect_type=push_content_info.redirect_type)
        if push_app_type == 'ios' or push_app_type == 'all':
            ios_push.u_group_push(task_code_list,
                                  push_content_info.push_title,
                                  push_content_info.push_content,
                                  'qy_uid_device_ios',
                                  go_url, redirect_type=push_content_info.redirect_type,
                                  production_mode=settings.U_PUSH_PRODUCTION_MODE)
            ios_push.u_group_push(task_uid_list,
                                  push_content_info.push_title,
                                  push_content_info.push_content,
                                  'qy_ios',
                                  go_url, redirect_type=push_content_info.redirect_type,
                                  production_mode=settings.U_PUSH_PRODUCTION_MODE)
        PushNotifyRecord.objects.filter(id__in=task_id_list, task_status=1).update(task_status=2)
    rs.delete('qms_push_user_lock')


@app.task()
def push_to_user(task_id_list, uid_list, push_app_type, push_content_id):
    if uid_list:
        logger.info('[g_push_to_user] receive task %s-%s', push_app_type, push_content_id)
        push_content_info = PushContentInfo.objects.get(id=push_content_id)
        if push_content_info.db_push_target != 'APP':
            return True
        # 獲取到需要單獨(dú)設(shè)備發(fā)送的數(shù)據(jù)
        push_notify_wait = PushNotifyRecord.objects.filter(
            id__in=task_id_list,
            task_status=1
        ).all()
        member_objs = GoogleMemberDeviceToken.objects.filter(uid__in=uid_list).all()
        member_dict = {}
        for i in member_objs:
            member_dict.setdefault(i.uid, []).append({'code': i.device_code, 'token': i.device_token})
        task_token_list = []
        for i in push_notify_wait:
            if push_app_type == 'android' or push_app_type == 'all':
                if i.device_code:
                    for j in member_dict[i.uid]:
                        if i.device_code == j['code']:
                            task_token_list.append(j['token'])
                else:
                    for j in member_dict[i.uid]:
                        task_token_list.append(j['token'])
        for i in task_token_list:
            android_push.g_token_push(
                i,
                push_content_info.push_title,
                push_content_info.push_content,
                push_content_info.message_save_hours * 60 * 60
            )
        PushNotifyRecord.objects.filter(id__in=task_id_list, task_status=1).update(task_status=2)


@app.task()
def expired_user_push():
    mc = MemberClient()
    start_time = (datetime.datetime.now() - datetime.timedelta(minutes=1)).strftime('%Y-%m-%d %H:%M:00')
    end_time = (datetime.datetime.now() - datetime.timedelta(minutes=1)).strftime('%Y-%m-%d %H:%M:59')
    success, expired_users = mc.query_expired_users(start_time, end_time)
    logger.info('response data: %s', expired_users)
    if not success:
        return True
    uids = expired_users.get('uid_list')
    if not uids:
        return True
    t_content_record, _ = PushContentInfo.objects.get_or_create(
        content_title='會員權(quán)益到期通知',
        push_title='會員權(quán)益到期通知',
        push_content='VIP體驗(yàn)權(quán)益已到期锌半,新用戶充值VIP盡享驚喜折扣,去看看吧~',
        redirect_url='sixfast://com.xg.push/main?type=qeeyou://personal_center',
    )
    v_content_record, _ = PushContentInfo.objects.get_or_create(
        content_title='會員權(quán)益到期通知',
        push_title='會員權(quán)益到期通知',
        push_content='您的VIP權(quán)益已到期寇漫,立即續(xù)費(fèi)VIP刊殉,享受極速回國體驗(yàn)~',
        redirect_url='sixfast://com.xg.push/main?type=qeeyou://personal_center',
    )
    for member_id in expired_users.get('uid_list'):
        success, result = mc.query(member_id)
        if not success:
            continue
        duration_account = result.get('duration_account')
        max_time = datetime.datetime(year=1990, month=1, day=1)
        max_time_duration_type = 'OVIP'
        for account in duration_account:
            duration_time = datetime.datetime.strptime(account.get('duration_expire_at'), "%Y-%m-%d %H:%M:%S")
            if duration_time > max_time:
                max_time = duration_time
                max_time_duration_type = account.get('duration_type')
        if max_time > datetime.datetime.now():
            continue
        if max_time_duration_type in ("TVIP", ):
            push_record = PushNotifyRecord(
                uid=member_id,
                notify_app_type='all',
                push_content_id=t_content_record.id
            )

        else:
            push_record = PushNotifyRecord(
                uid=member_id,
                notify_app_type='all',
                push_content_id=v_content_record.id
            )
        push_record.save()
    return True

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市州胳,隨后出現(xiàn)的幾起案子记焊,更是在濱河造成了極大的恐慌,老刑警劉巖栓撞,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件遍膜,死亡現(xiàn)場離奇詭異,居然都是意外死亡瓤湘,警方通過查閱死者的電腦和手機(jī)瓢颅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來弛说,“玉大人挽懦,你說我怎么就攤上這事∧救耍” “怎么了信柿?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長虎囚。 經(jīng)常有香客問我角塑,道長,這世上最難降的妖魔是什么淘讥? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任圃伶,我火速辦了婚禮,結(jié)果婚禮上蒲列,老公的妹妹穿的比我還像新娘窒朋。我一直安慰自己,他們只是感情好蝗岖,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布侥猩。 她就那樣靜靜地躺著,像睡著了一般抵赢。 火紅的嫁衣襯著肌膚如雪欺劳。 梳的紋絲不亂的頭發(fā)上唧取,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機(jī)與錄音划提,去河邊找鬼枫弟。 笑死,一個胖子當(dāng)著我的面吹牛鹏往,可吹牛的內(nèi)容都是我干的淡诗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼伊履,長吁一口氣:“原來是場噩夢啊……” “哼韩容!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唐瀑,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤群凶,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后哄辣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體座掘,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年柔滔,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片萍虽。...
    茶點(diǎn)故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡睛廊,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出杉编,到底是詐尸還是另有隱情超全,我是刑警寧澤,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布邓馒,位于F島的核電站嘶朱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏光酣。R本人自食惡果不足惜疏遏,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望救军。 院中可真熱鬧财异,春花似錦、人聲如沸唱遭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拷泽。三九已至疫鹊,卻和暖如春袖瞻,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背拆吆。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工聋迎, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人锈拨。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓砌庄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親奕枢。 傳聞我的和親對象是個殘疾皇子娄昆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,494評論 2 348

推薦閱讀更多精彩內(nèi)容