电商项目-业务相关

1.漏斗模型

reseller_id, login_at, session_time, click_times, cart_times, pay_times, pay_offer, pay_amount, search_list, view_times, catalog_id, supplier_id, category_id, last_share_time, which_app

2.表示商品的状态太多,修改的地方少而使用的地方多,导致查询的速度较慢,查询字段不易涵盖全和es需要不断调整

用一个新字段表示复合状态,其他状态共同维护这个状态

3.supplier和supplier_admin分离,supplier也要拆分。为后续多个店铺管理员做准备

4.gunicorn配置

import multiprocessing
import gevent.monkey

gevent.monkey.patch_all()

bind = ":8000"
debug = False

loglevel = 'error'
# 访问日志
accesslog = "/dev/null"
# 错误日志
errorlog = "/var/log/gunicorn.log"
capture_output = True  # 影响代码中的print Redirect stdout/stderr to specified file in errorlog.
# 启动的进程数
workers = multiprocessing.cpu_count()
worker_connections = 1000
worker_class = 'gevent'
reload = False
timeout = 120

5.ab命令,-T表示请求头数据类型,-H表示其他header, -p表示输入参数文件  -s表示timeout

ab -c 10 -n 10  -T 'application/json'  -H  'token:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE1NjcxNTMxMjgsImV4cCI6MTU2OTc0NTEyOCwic291cmNlX3R5cGUiOjMsInVpZCI6MTExNywiZGV2aWNlX2lkIjoxODk0ODIyODM1fQ.q6HSY8Vxz83U_tSime6enWIWJ7qOgldnkPmdrrq8pNY' -s 120 -p /home/test/filter_search.txt  http://127.0.0.1:5000/api/v1.0/product/filter/search

 

6.APScheduler

schedulers(triggers, executors, job stores)

BackgroundScheduler和主业务一起跑,BlockedScheduler单独跑

job stores: 如果你需要在程序关闭或重启时,保存任务的状态,那么就要选择持久化的任务储存器。序列化和反序列化

triggers:

date 日期:触发任务运行的具体日期,作业任务只会执行一次

interval 间隔:触发任务运行的时间间隔

cron 周期:触发任务运行的周期  在特定时间周期性地触发

 

1.通过调用add_job()

2.通过装饰器scheduled_job()

第一种add_job()方法会返回一个apscheduler.job.Job实例,这样就可以在运行时,修改或删除任务。

 

1.调用remove_job(),参数为:任务ID,任务储存器名称

2.在通过add_job()创建的任务实例上调用remove()方法

 

7.系统日志

存储在es or mango

某个api的输入,输出,token(type, uid),操作时间,api_version

from flask import request_tearing_down

from flask import request_started, request_finished

request_tearing_down(action, app)

8.api权鉴

api鉴权
header里面增加以下参数:
AppId: 供应商code

AuthRole:'Supplier'
TimeStamp:当前时间戳  (10位的秒级时间戳)

Random:随机数(10位)
Signature:签名  (包括AppId,AuthRole,TimeStamp,Random)根据key值的字母升序排序后,以key1:value1:key2:value2这样方式连接组成的字符串,如'AppId:12346669:AuthRole:Supplier:Random:1565168569:TimeStamp:1565168569',带上私钥由AES加密后的到的签名

服务端验证签名和时间戳,将Signature和Random存入缓存,防止短时间多次请求或者重复攻击。

 

签名中也可以混入特定的secretkey来保证特定接口的请求

签名生成aes规则:
#aes demo https://blog.csdn.net/HH775313602/article/details/78991340

pip install pycrypto
import base64
from Crypto.Cipher import AES
 
 
# 补足字符串长度为16的倍数
def add_to_16(s):
    while len(s) % 16 != 0:
        s += '\0'
    return str.encode(s)  # 返回bytes
 

key = '1234567890123456'  # 密钥长度必须为16、24或32位,分别对应AES-128、AES-192和AES-256
text = 'abcdefg'  # 待加密文本
 
aes = AES.new(str.encode(key), AES.MODE_ECB)  # 初始化加密器,本例采用ECB加密模式
encrypted_text = str(base64.encodebytes(aes.encrypt(add_to_16(text))), encoding='utf8').replace('\n', '')  # 加密
decrypted_text = str(aes.decrypt(base64.decodebytes(bytes(encrypted_text, encoding='utf8'))).rstrip(b'\0').decode("utf8"))  # 解密
 
print('加密值:', encrypted_text)
print('解密值:', decrypted_text)

9.重启脚本

import os

def daima():
    # 进入后端目录/opt/socialcommerce
    if not os.path.exists('/opt/socialcommerce'):
        print('/opt/socialcommerce目录不存在')

    os.chdir('/opt/socialcommerce')
    # 从git下更新代码
    os.system('git stash;git pull')
    # 后端代码迁移
    print('代码迁移')
    os.chdir('/opt/socialcommerce/Pinshop')
    os.system('pip3 install -r requirements.txt')
    #os.system('rm -rf /opt/socialcommerce/Pinshop/migrations')
    #os.system('python3 manage.py db init')
    #os.system('python3 manage.py db migrate')
    #os.system('python3 manage.py db upgrade')
    print('代码迁移完成')
    # 进入前端目录/opt/dist
    if not os.path.exists('/opt/dist'):
        print('/opt/dist目录不存在')
    #os.chdir('/opt/dist')
    #os.system('git pull')
    #print('前端代码迁移完成')
    #os.system('nginx -s reload')
    print('nginx进程重启')
    # 杀掉gunicorn进程
    # os.system('kill -s 9 `pgrep gunicorn`')
    os.system('ps aux | grep "gunicorn" |grep -v grep| cut -c 10-15 | xargs kill ')
    print('杀掉gunicorn进程')
    # 重启gunicorn进程
    os.chdir('/opt/socialcommerce/Pinshop')
    os.system('gunicorn  manage:app  -c ./guni_conf.py --chdir . 1>/dev/null 2>&1 &')
    os.system('exit')
    print('重启服务成功')
    return

10.版本控制

a.通过app整体使用版本标志控制/Vx.xx,所有接口用新的url请求,新的接口调用老的接口的函数,优缺点:代码行数急剧增加,改动较多

b.通过app单个接口不断的使用新的版本,优缺点:app的接口上会存在很多版本号的接口

c.请求头header里面,放置版本信息,后台代码分支控制不同分支,优缺点:绝大部分接口不需要变动,变动接口走分支,单个函数看起来较长

比较合适的是方案三,原则:老的app会周期强制更新版本,这时候一些老的分支控制都会删除。

11.网络问题

短信改成异步的之后,会先发送到消息队列,这时候有人上传商品就会消耗大量网络,用户就收不到。
#api服务一套网络
#celery的work一套网络
#商品上传一套网络

12.从平台页面跳转到某个商户页面

点击dashboard按钮
1.获取supplier的token2(两个域名的storage独立)
2.跳转到supplier的主页面地址后面加上token=;前端判断这个地址,存储token2后跳转一下

13.orm报错

Table 'order' is already defined for this MetaData instance.  Specify 'extend_existing=True' to redefine options and columns on an existing Table object.
find . -name "*.pyc" | xargs rm -rf
TypeError: Additional arguments should be named <dialectname>_<argument>, got 'commit'
py3clean .
in_transit_at = db.Column(db.TIMESTAMP(True), nullable=True, commit="物流商商开始发货时间")这个字段改过名字,哪里有缓存导致一直认为是额外字段
其实原因是commit错写成comment

14.开发单元测试分析-mock

1.mock简介

在做单元测试过程中,经常会有以下的场景:

1.被测对象依赖的对象构造复杂
我们想对class A进行单元测试,需要构造大量的class B、C、D等依赖对象,他们的构造过程复杂(体现在构造步骤多、耗时较长),这时我们可以利用mock去构造虚拟的class B、C、D对象用于class A的测试,因为我们只是想测试class A的行为是否符合预期,我们并不需要测试依赖对象。 
2.被测单元依赖的模块尚未开发完成,而被测对象需要依赖模块的返回值进行测试: ----- 比如service层的代码中,包含对dao层的调用,但dao层代码尚未开发 ----- 比如web的前端依赖后端接口获取数据进行联调测试,但后端接口并未开发完成

哪些时机和场合需要使用mock(when&where)

 

1.单元测试/接口测试中测试对象依赖其他对象,这些对象的构造复杂、耗时或者根本无法构造(未交付)
2.我们只测试对象内部逻辑的质量,不关心依赖对象的逻辑正确性和稳定性
基于以下2个原则
1.不需要对所有的依赖对象/服务进行mock,只对那些构造步骤复杂、构造耗时较长、不稳定的依赖对象/服务进行mock。
2.如果做分层测试(比如分层自动化),高层的测试设计可以基于以下假设:低层的测试已保证低层对象的质量,高层对低层的依赖可以mock,无需关心所依赖的低层对象的质量。 

 

2.比较困难的地方

1.流程经常变化,新功能迭代的快。

2.电商项目,查询msyql,es,sqs,redis的代码是主要的,字段比较多,暂时不好展开。

3.代码结构没有分层,所以难以mock替换查询接口(最主要原因)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章