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替換查詢接口(最主要原因)。