電商項目-業務相關

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

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