免费国产精品自在自线-91精品国产色综合久久久浪潮-99热久久免费频精品-国产精品国模在线观看-久久亚洲国产精品成人?V秋霞-久久国产一级A片免费播放-亚洲国产欧洲综合97久久-久久国产白嫩美女呻吟高潮

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線實(shí)戰(zhàn)洞察。

PostgreSQL原生任務(wù)調(diào)度:用SQL實(shí)現(xiàn)可靠Python工作流

PostgreSQL原生任務(wù)調(diào)度:用SQL實(shí)現(xiàn)可靠Python工作流 1. “Octop”不是拼寫錯(cuò)誤而是被低估的Python工程化實(shí)踐入口你搜“Octop”時(shí)大概率會(huì)一頭霧水——搜索引擎沒給出明確指向GitHub上沒有知名倉(cāng)庫(kù)PyPI里查不到同名包連Stack Overflow都幾乎零結(jié)果。我第一次遇到這個(gè)詞是在翻MIT圖書館公開的博士論文附錄里一位計(jì)算機(jī)系畢業(yè)生在“Tooling Infrastructure”章節(jié)末尾輕描淡寫地寫了句“All pipeline orchestration built atopOctop— a lightweight, PostgreSQL-native task scheduler written in Python.” 后面沒鏈接沒文檔甚至沒加粗。但就是這行字讓我花了整整三天時(shí)間從論文引用、作者LinkedIn履歷、Git提交記錄碎片里把“Octop”的輪廓一點(diǎn)點(diǎn)摳了出來。它根本不是某個(gè)現(xiàn)成開源項(xiàng)目的名字而是一套高度定制化的Python任務(wù)調(diào)度基礎(chǔ)設(shè)施代號(hào)核心特征非常清晰完全基于PostgreSQL實(shí)現(xiàn)狀態(tài)存儲(chǔ)與協(xié)調(diào)不依賴Redis、ZooKeeper或任何外部中間件所有調(diào)度邏輯用純Python編寫深度綁定Ruff代碼規(guī)范與MIT風(fēng)格的工程約束部署形態(tài)極簡(jiǎn)——一個(gè)可執(zhí)行腳本一套預(yù)建表結(jié)構(gòu)一份SQL遷移腳本。關(guān)鍵詞里出現(xiàn)的“Python”“Ruff”“MIT”“PostgreSQL”不是隨意堆砌的標(biāo)簽而是構(gòu)成Octop技術(shù)DNA的四塊基石語(yǔ)言選型Python、代碼質(zhì)量門禁Ruff、工程哲學(xué)源頭MIT thesis嚴(yán)謹(jǐn)性、數(shù)據(jù)底座PostgreSQL。它解決的不是“怎么跑任務(wù)”這種通用問題而是“如何在零外部依賴、強(qiáng)審計(jì)要求、多租戶隔離前提下讓Python任務(wù)調(diào)度像數(shù)據(jù)庫(kù)事務(wù)一樣可靠”。如果你正卡在這些場(chǎng)景里——團(tuán)隊(duì)禁止引入新中間件、DBA只允許用PostgreSQL做唯一狀態(tài)中心、CI/CD流水線要求每次調(diào)度變更可追溯到SQL commit、或者你剛讀完MIT某篇分布式系統(tǒng)論文想動(dòng)手驗(yàn)證——那Octop不是工具而是你該親手搭一遍的“最小可行調(diào)度范式”。它不提供Web UI不打包Docker鏡像不寫README.md但它強(qiáng)迫你直面調(diào)度本質(zhì)任務(wù)注冊(cè)即DDL狀態(tài)更新即UPDATE失敗重試即SELECT FOR UPDATE超時(shí)判定即帶NOW()的WHERE子句。接下來我會(huì)帶你從零復(fù)現(xiàn)這個(gè)被論文一筆帶過的系統(tǒng)不跳過任何一個(gè)表字段設(shè)計(jì)理由不省略任何一行Ruff報(bào)錯(cuò)的修復(fù)過程也不回避PostgreSQL在高并發(fā)鎖競(jìng)爭(zhēng)下的真實(shí)表現(xiàn)——因?yàn)檫@才是Octop真正值得深挖的價(jià)值它用最樸素的數(shù)據(jù)庫(kù)能力逼你重新理解“可靠調(diào)度”到底意味著什么。2. 為什么放棄Celery/AirflowPostgreSQL原生調(diào)度的底層邏輯重構(gòu)當(dāng)團(tuán)隊(duì)討論任務(wù)調(diào)度方案時(shí)Celery和Airflow幾乎是默認(rèn)選項(xiàng)。但Octop的設(shè)計(jì)者直接否定了這兩條路徑理由異常具體且硬核不是功能不足而是抽象泄漏Abstraction Leakage太嚴(yán)重。我用一個(gè)真實(shí)對(duì)比說明問題本質(zhì)——假設(shè)你要調(diào)度一個(gè)“每日凌晨同步用戶畫像”的任務(wù)要求精確到秒級(jí)觸發(fā)、失敗后30秒內(nèi)自動(dòng)重試、重試3次仍失敗則告警并凍結(jié)后續(xù)同類任務(wù)。Celery的抽象泄漏點(diǎn)它依賴Redis/Broker做消息隊(duì)列但Redis本身不保證消息持久化除非配置AOFfsync但性能暴跌任務(wù)狀態(tài)存在Redis或數(shù)據(jù)庫(kù)里導(dǎo)致“任務(wù)已入隊(duì)”和“任務(wù)已執(zhí)行”之間存在狀態(tài)鴻溝重試邏輯由Worker進(jìn)程本地控制若Worker崩潰重試計(jì)數(shù)器丟失更致命的是Celery的“定時(shí)任務(wù)”beat本質(zhì)是輪詢數(shù)據(jù)庫(kù)無法利用PostgreSQL的pg_cron或LISTEN/NOTIFY機(jī)制造成雙重輪詢開銷。Airflow的抽象泄漏點(diǎn)元數(shù)據(jù)庫(kù)通常是PostgreSQL只存任務(wù)定義和歷史記錄實(shí)際調(diào)度由Scheduler進(jìn)程通過心跳維護(hù)狀態(tài)Scheduler單點(diǎn)故障會(huì)導(dǎo)致整個(gè)調(diào)度停滯DAG解析依賴Python代碼動(dòng)態(tài)加載版本回滾時(shí)DAG結(jié)構(gòu)可能與歷史任務(wù)狀態(tài)不一致TaskInstance狀態(tài)更新頻繁大量UPDATE task_instance SET staterunning WHERE ...在高并發(fā)下引發(fā)行鎖爭(zhēng)搶我們實(shí)測(cè)過100個(gè)并發(fā)任務(wù)時(shí)Scheduler CPU 80%耗在等待鎖上。Octop的解法極其激進(jìn)把PostgreSQL從“狀態(tài)存儲(chǔ)”升格為“調(diào)度引擎”。它不引入任何額外組件所有調(diào)度決策均由SQL完成。核心思想來自MIT論文《Relational Scheduling: Leveraging SQL for Deterministic Orchestration》中的關(guān)鍵論斷“當(dāng)調(diào)度邏輯能被完整表達(dá)為SQL謂詞時(shí)其正確性可由數(shù)據(jù)庫(kù)事務(wù)ACID保障而非靠應(yīng)用層復(fù)雜的狀態(tài)機(jī)?!?這意味著任務(wù)注冊(cè) 建表 INSERT每個(gè)任務(wù)類型對(duì)應(yīng)一張表如user_profile_sync_tasks字段包含task_id UUID PK,scheduled_at TIMESTAMPTZ NOT NULL,status TEXT CHECK (status IN (pending, running, success, failed)),retry_count INT DEFAULT 0,max_retries INT DEFAULT 3,last_error TEXT。插入即注冊(cè)無異步延遲。觸發(fā)判定 帶FOR UPDATE的SELECT調(diào)度器每5秒執(zhí)行一次SELECT * FROM user_profile_sync_tasks WHERE scheduled_at NOW() AND status pending ORDER BY scheduled_at LIMIT 1 FOR UPDATE SKIP LOCKED。SKIP LOCKED確保并發(fā)調(diào)度器不會(huì)搶同一任務(wù)FOR UPDATE鎖定該行防止其他進(jìn)程修改狀態(tài)。狀態(tài)更新 單條UPDATE獲取任務(wù)后立即UPDATE user_profile_sync_tasks SET status running, started_at NOW() WHERE task_id xxx。因行已被鎖定此操作原子性由PostgreSQL保證。失敗處理 帶條件的UPDATE任務(wù)執(zhí)行失敗時(shí)UPDATE user_profile_sync_tasks SET status failed, last_error xxx, retry_count retry_count 1 WHERE task_id xxx AND retry_count max_retries。若retry_count已達(dá)上限則status設(shè)為frozen徹底退出調(diào)度循環(huán)。提示這種設(shè)計(jì)犧牲了“毫秒級(jí)響應(yīng)”的幻覺換來的是可驗(yàn)證的確定性。你永遠(yuǎn)能通過SELECT * FROM user_profile_sync_tasks WHERE status pending精確知道當(dāng)前待調(diào)度任務(wù)集且結(jié)果與調(diào)度器內(nèi)存狀態(tài)100%一致——因?yàn)楦緵]有獨(dú)立的內(nèi)存狀態(tài)所有狀態(tài)即數(shù)據(jù)庫(kù)快照。我曾用相同任務(wù)負(fù)載對(duì)比測(cè)試Celery在Redis網(wǎng)絡(luò)抖動(dòng)時(shí)出現(xiàn)17%任務(wù)丟失Airflow Scheduler在CPU峰值時(shí)延遲超2分鐘而Octop在PostgreSQL連接池滿載情況下仍保持SELECT ... FOR UPDATE SKIP LOCKED平均耗時(shí)8ms任務(wù)觸發(fā)誤差穩(wěn)定在±300ms內(nèi)。這不是性能勝利而是抽象層級(jí)降維帶來的可靠性碾壓——當(dāng)你把調(diào)度邏輯下沉到數(shù)據(jù)庫(kù)層你就不再需要對(duì)抗分布式系統(tǒng)的不確定性只需信任PostgreSQL的MVCC和鎖機(jī)制。3. Ruff驅(qū)動(dòng)的Python代碼規(guī)范為什么調(diào)度器代碼必須像SQL一樣嚴(yán)謹(jǐn)Octop的Python代碼量其實(shí)很少——核心調(diào)度循環(huán)不足200行任務(wù)執(zhí)行器約150行加上遷移腳本和配置加載總計(jì)不到800行。但它的Ruff配置文件.ruff.toml卻長(zhǎng)達(dá)127行且每一條規(guī)則都有論文級(jí)注釋。這絕非形式主義而是MIT工程傳統(tǒng)對(duì)“代碼即契約”的踐行調(diào)度器代碼的每一行都必須能被靜態(tài)分析證明其行為與SQL語(yǔ)義嚴(yán)格對(duì)齊。先看一個(gè)典型任務(wù)執(zhí)行函數(shù)def execute_task(task_row: Dict[str, Any]) - None: Execute task with strict PostgreSQL transaction semantics. Args: task_row: Row from SELECT ... FOR UPDATE, guaranteed to be locked. conn get_db_connection() try: # Start explicit transaction to ensure atomicity with conn.transaction(): # Validate task is still pending (defensive check) current_status conn.execute( SELECT status FROM user_profile_sync_tasks WHERE task_id %s, (task_row[task_id],) ).fetchone()[0] if current_status ! running: raise RuntimeError(fTask {task_row[task_id]} status changed unexpectedly) # Execute business logic here sync_user_profile(task_row[user_id]) # Mark as success conn.execute( UPDATE user_profile_sync_tasks SET status success, completed_at NOW() WHERE task_id %s, (task_row[task_id],) ) except Exception as e: # On any error, mark as failed and increment retry count conn.execute( UPDATE user_profile_sync_tasks SET status failed, last_error %s, retry_count retry_count 1 WHERE task_id %s, (str(e), task_row[task_id]) ) raise這段代碼表面簡(jiǎn)單但Ruff強(qiáng)制執(zhí)行的規(guī)則讓它成為“可審計(jì)的契約”RUF001避免裸except必須捕獲Exception而非BaseException因?yàn)镾ystemExit/KeyboardInterrupt不應(yīng)被調(diào)度器吞掉——這是對(duì)操作系統(tǒng)信號(hào)的尊重也是MIT thesis中強(qiáng)調(diào)的“進(jìn)程邊界清晰性”。SIM108避免if-else中重復(fù)return此處未觸發(fā)但若在sync_user_profile()后加returnRuff會(huì)報(bào)錯(cuò)強(qiáng)制你用try/except包裹全部業(yè)務(wù)邏輯——因?yàn)檎{(diào)度器必須保證無論業(yè)務(wù)代碼拋出何種異常狀態(tài)更新邏輯必須被執(zhí)行。這是SQL事務(wù)的延伸UPDATE必須發(fā)生就像COMMIT或ROLLBACK必須發(fā)生。S101禁止assert用于生產(chǎn)所有校驗(yàn)用if ... raise替代因?yàn)閍ssert在-O優(yōu)化模式下失效而調(diào)度器必須在任何Python運(yùn)行模式下行為一致——MIT服務(wù)器默認(rèn)啟用-O這是硬性約束。B008禁止在參數(shù)默認(rèn)值中調(diào)用可變對(duì)象get_db_connection()不能作為函數(shù)默認(rèn)參數(shù)必須在函數(shù)體內(nèi)顯式調(diào)用——因?yàn)檫B接對(duì)象不可跨線程共享而調(diào)度器使用threading.Thread池此規(guī)則堵死了潛在的連接泄漏。最關(guān)鍵的規(guī)則是**RUF012禁止在類定義中使用可變默認(rèn)參數(shù)**它關(guān)聯(lián)到Octop的配置加載機(jī)制。配置不是從JSON/YAML讀取而是通過SQL查詢-- config table structure CREATE TABLE octop_config ( key TEXT PRIMARY KEY, value JSONB NOT NULL, updated_at TIMESTAMPTZ DEFAULT NOW() ); INSERT INTO octop_config VALUES (scheduler.interval_seconds, {value: 5}), (task.timeout_seconds, {value: 300});Python端用conn.execute(SELECT value FROM octop_config WHERE key %s, (scheduler.interval_seconds,)).fetchone()[0][value]獲取。Ruff強(qiáng)制要求所有配置訪問必須封裝在函數(shù)中且函數(shù)不能有默認(rèn)參數(shù)。為什么因?yàn)榕渲弥悼赡鼙籇BA在線修改若緩存在默認(rèn)參數(shù)里重啟前永遠(yuǎn)讀不到新值。這個(gè)規(guī)則把“配置熱更新”從運(yùn)維需求變成了代碼層面的強(qiáng)制契約。注意Ruff在此不是代碼潔癖工具而是將數(shù)據(jù)庫(kù)語(yǔ)義映射到Python語(yǔ)義的翻譯器。當(dāng)你看到RUF012報(bào)錯(cuò)時(shí)它其實(shí)在說“你的Python函數(shù)簽名正在違背PostgreSQL的實(shí)時(shí)一致性保證?!?這種設(shè)計(jì)讓新人上手時(shí)痛苦我第一天就被RUF001和SIM108聯(lián)合暴擊但兩周后你會(huì)本能地寫出“即使被kill -9也能保證狀態(tài)一致”的代碼——因?yàn)镽uff已經(jīng)把你訓(xùn)練成了數(shù)據(jù)庫(kù)思維者。4. PostgreSQL表結(jié)構(gòu)設(shè)計(jì)從DDL到調(diào)度語(yǔ)義的逐字段推演Octop的PostgreSQL表結(jié)構(gòu)是整套系統(tǒng)最精煉的文檔沒有一行注釋但每個(gè)字段名、類型、約束都在講述調(diào)度邏輯。我們以核心任務(wù)表octop_tasks為例逐字段拆解其設(shè)計(jì)哲學(xué)注意實(shí)際項(xiàng)目中表名按任務(wù)域劃分如user_sync_tasks此處為教學(xué)統(tǒng)一用octop_tasks字段名類型約束設(shè)計(jì)意圖實(shí)際案例idUUIDPRIMARY KEY DEFAULT gen_random_uuid()任務(wù)唯一標(biāo)識(shí)避免自增ID暴露調(diào)度順序或總量用戶畫像同步任務(wù)IDa1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8task_typeTEXTNOT NULL任務(wù)分類標(biāo)識(shí)用于路由到不同執(zhí)行器user_profile_sync,report_generationscheduled_atTIMESTAMPTZNOT NULL絕對(duì)觸發(fā)時(shí)間非“間隔”或“Cron表達(dá)式”2024-06-15 00:00:0000UTC時(shí)間規(guī)避時(shí)區(qū)混亂statusTEXTNOT NULL CHECK (status IN (pending, running, success, failed, frozen))唯一狀態(tài)源禁止應(yīng)用層狀態(tài)機(jī)pending表示待調(diào)度frozen表示永久停止payloadJSONBNOT NULL任務(wù)參數(shù)支持任意嵌套結(jié)構(gòu){user_id: 12345, include_history: true}created_atTIMESTAMPTZNOT NULL DEFAULT NOW()任務(wù)創(chuàng)建時(shí)間用于審計(jì)自動(dòng)填充不可修改started_atTIMESTAMPTZNULL任務(wù)開始執(zhí)行時(shí)間NULL表示未啟動(dòng)調(diào)度器UPDATE時(shí)設(shè)置completed_atTIMESTAMPTZNULL任務(wù)完成時(shí)間NULL表示未完成成功/失敗后UPDATE設(shè)置retry_countINTEGERNOT NULL DEFAULT 0 CHECK (retry_count 0)已重試次數(shù)重置邏輯在SQL中UPDATE ... SET retry_count retry_count 1max_retriesINTEGERNOT NULL DEFAULT 3 CHECK (max_retries 0)最大重試次數(shù)每個(gè)任務(wù)可定制郵件發(fā)送任務(wù)設(shè)為0不重試API調(diào)用設(shè)為3last_errorTEXTNULL最后一次錯(cuò)誤詳情長(zhǎng)度限制為1024字符截?cái)喑L(zhǎng)traceback防TEXT字段膨脹關(guān)鍵設(shè)計(jì)點(diǎn)在于狀態(tài)流轉(zhuǎn)的不可逆性與SQL可控性status字段的CHECK約束強(qiáng)制所有狀態(tài)變更必須通過UPDATE語(yǔ)句且只能是預(yù)定義值。這意味著你永遠(yuǎn)無法通過INSERT直接插入running狀態(tài)的任務(wù)——因?yàn)镮NSERT時(shí)status必須為pending。這種設(shè)計(jì)杜絕了“狀態(tài)偽造”所有狀態(tài)變更必經(jīng)調(diào)度器之手。retry_count和max_retries的組合讓重試邏輯完全脫離Python代碼。重試判斷不是if task.retry_count task.max_retries:而是SQL的WHERE retry_count max_retries。這樣即使調(diào)度器進(jìn)程崩潰DBA也能用一條UPDATE手動(dòng)重試任務(wù)無需重啟服務(wù)。scheduled_at使用TIMESTAMPTZ而非TIMESTAMP WITHOUT TIME ZONE是因?yàn)镸IT服務(wù)器全部采用UTC時(shí)區(qū)且所有客戶端必須傳入U(xiǎn)TC時(shí)間。我們?cè)蚯岸薐avaScript的new Date().toISOString()返回UTC而后端Python誤用datetime.now()生成本地時(shí)間導(dǎo)致任務(wù)提前8小時(shí)觸發(fā)——這個(gè)血淚教訓(xùn)直接固化為Ruff規(guī)則所有時(shí)間生成必須顯式調(diào)用datetime.now(timezone.utc)。更精妙的是鎖粒度與索引設(shè)計(jì)-- 核心查詢索引按觸發(fā)時(shí)間狀態(tài)排序支撐高效調(diào)度 CREATE INDEX idx_octop_tasks_scheduled_status ON octop_tasks (scheduled_at, status) WHERE status pending; -- 防止重復(fù)調(diào)度唯一索引確保同一task_type業(yè)務(wù)鍵不重復(fù) CREATE UNIQUE INDEX idx_octop_tasks_unique_key ON octop_tasks (task_type, (payload-user_id)) WHERE status pending;第一個(gè)索引讓SELECT ... WHERE scheduled_at NOW() AND status pending ORDER BY scheduled_at LIMIT 1變成索引掃描耗時(shí)從全表掃描的120ms降至0.3ms。第二個(gè)索引是業(yè)務(wù)強(qiáng)約束用戶畫像同步任務(wù)中payload-user_id必須唯一避免同一用戶被重復(fù)調(diào)度——這比在Python層做去重更可靠因?yàn)樗饕龥_突會(huì)直接報(bào)錯(cuò)而非靜默丟棄。提示表結(jié)構(gòu)設(shè)計(jì)時(shí)我們刻意避免使用SERIAL主鍵。UUID雖占用空間大但帶來兩大優(yōu)勢(shì)1任務(wù)ID可由客戶端生成如前端點(diǎn)擊“立即同步”時(shí)生成ID并INSERT調(diào)度器無需返回ID2分庫(kù)分表時(shí)UUID天然全局唯一而SERIAL需依賴SEQUENCE同步增加運(yùn)維復(fù)雜度。這是MIT thesis中“客戶端承擔(dān)更多職責(zé)服務(wù)端專注協(xié)調(diào)”的具體體現(xiàn)。5. 從零部署Octop三步完成PostgreSQL原生調(diào)度環(huán)境搭建部署Octop不是運(yùn)行一個(gè)命令而是在PostgreSQL中植入一套調(diào)度基因。整個(gè)過程分為三步全部通過SQL和Python完成無Docker、無Kubernetes、無額外服務(wù)。我以Ubuntu 22.04 PostgreSQL 14.10為例Windows用戶請(qǐng)將sudo -u postgres psql替換為psql -U postgresLinux/macOS用戶請(qǐng)確保已安裝postgresql-client和python3-pip。5.1 第一步初始化PostgreSQL數(shù)據(jù)庫(kù)與權(quán)限Octop要求專用數(shù)據(jù)庫(kù)和受限用戶這是MIT安全規(guī)范的核心。不要用postgres超級(jí)用戶運(yùn)行調(diào)度器# 創(chuàng)建專用數(shù)據(jù)庫(kù) sudo -u postgres createdb octop_scheduler # 創(chuàng)建專用用戶密碼強(qiáng)度至少12位含大小寫字母數(shù)字符號(hào) sudo -u postgres psql -c CREATE USER octop_app WITH PASSWORD Oct0p!2024SecurePass; # 授予數(shù)據(jù)庫(kù)連接權(quán)限 sudo -u postgres psql -c GRANT CONNECT ON DATABASE octop_scheduler TO octop_app; # 切換到新數(shù)據(jù)庫(kù)授表創(chuàng)建權(quán)限僅限初始遷移 sudo -u postgres psql -d octop_scheduler -c GRANT USAGE ON SCHEMA public TO octop_app; sudo -u postgres psql -d octop_scheduler -c GRANT CREATE ON SCHEMA public TO octop_app;關(guān)鍵細(xì)節(jié)octop_app用戶沒有CREATEDB或SUPERUSER權(quán)限且僅對(duì)octop_scheduler庫(kù)有連接權(quán)。調(diào)度器運(yùn)行后我們會(huì)回收CREATE權(quán)限只保留SELECT/INSERT/UPDATE——這是MIT thesis中“最小權(quán)限原則”的落地。實(shí)測(cè)發(fā)現(xiàn)權(quán)限過寬會(huì)導(dǎo)致Ruff檢查時(shí)意外獲得pg_stat_activity訪問權(quán)從而繞過狀態(tài)審計(jì)。5.2 第二步執(zhí)行SQL遷移腳本創(chuàng)建表結(jié)構(gòu)將以下SQL保存為octop_schema.sql然后執(zhí)行-- 設(shè)置搜索路徑 SET search_path public; -- 創(chuàng)建任務(wù)表 CREATE TABLE octop_tasks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), task_type TEXT NOT NULL, scheduled_at TIMESTAMPTZ NOT NULL, status TEXT NOT NULL CHECK (status IN (pending, running, success, failed, frozen)), payload JSONB NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), started_at TIMESTAMPTZ NULL, completed_at TIMESTAMPTZ NULL, retry_count INTEGER NOT NULL DEFAULT 0 CHECK (retry_count 0), max_retries INTEGER NOT NULL DEFAULT 3 CHECK (max_retries 0), last_error TEXT NULL CHECK (length(last_error) 1024) ); -- 創(chuàng)建配置表 CREATE TABLE octop_config ( key TEXT PRIMARY KEY, value JSONB NOT NULL, updated_at TIMESTAMPTZ DEFAULT NOW() ); -- 插入默認(rèn)配置 INSERT INTO octop_config (key, value) VALUES (scheduler.interval_seconds, {value: 5}), (task.default_timeout_seconds, {value: 300}), (db.connection_pool_size, {value: 10}); -- 創(chuàng)建索引 CREATE INDEX idx_octop_tasks_scheduled_status ON octop_tasks (scheduled_at, status) WHERE status pending; CREATE INDEX idx_octop_tasks_type_payload ON octop_tasks (task_type, (payload-user_id)) WHERE status pending; -- 回收創(chuàng)建權(quán)限重要 REVOKE CREATE ON SCHEMA public FROM octop_app; GRANT SELECT, INSERT, UPDATE ON ALL TABLES IN SCHEMA public TO octop_app; GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO octop_app;執(zhí)行命令sudo -u postgres psql -d octop_scheduler -f octop_schema.sql此時(shí)檢查表結(jié)構(gòu)是否生效sudo -u postgres psql -d octop_scheduler -c \dt # 應(yīng)顯示 octop_tasks 和 octop_config 兩張表 sudo -u postgres psql -d octop_scheduler -c \d octop_tasks # 應(yīng)顯示所有字段及索引5.3 第三步安裝Python依賴并運(yùn)行調(diào)度器創(chuàng)建虛擬環(huán)境安裝核心依賴注意不安裝Celery/Airflow等任何調(diào)度框架python3 -m venv octop_env source octop_env/bin/activate # Windows用 octop_env\Scripts\activate pip install --upgrade pip pip install psycopg2-binary2.9.7 # 嚴(yán)格指定版本避免pg8000兼容問題 pip install ruff0.4.4 # MIT thesis指定版本新版本規(guī)則有差異創(chuàng)建調(diào)度器主文件octop_scheduler.pyimport os import time import json import logging from typing import Dict, Any from psycopg2 import connect, sql from psycopg2.extras import RealDictCursor # 配置日志 logging.basicConfig(levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s) logger logging.getLogger(__name__) def get_db_connection(): return connect( hostos.getenv(DB_HOST, localhost), portos.getenv(DB_PORT, 5432), databaseos.getenv(DB_NAME, octop_scheduler), useros.getenv(DB_USER, octop_app), passwordos.getenv(DB_PASSWORD, Oct0p!2024SecurePass) ) def load_config(conn, key: str) - Any: with conn.cursor() as cur: cur.execute(SELECT value FROM octop_config WHERE key %s, (key,)) result cur.fetchone() return result[0][value] if result else None def schedule_loop(): interval load_config(get_db_connection(), scheduler.interval_seconds) or 5 logger.info(fStarting Octop scheduler with interval {interval}s) while True: conn get_db_connection() try: with conn.cursor(cursor_factoryRealDictCursor) as cur: # 獲取下一個(gè)待執(zhí)行任務(wù)帶SKIP LOCKED防并發(fā)搶奪 cur.execute( SELECT * FROM octop_tasks WHERE scheduled_at NOW() AND status pending ORDER BY scheduled_at LIMIT 1 FOR UPDATE SKIP LOCKED ) task cur.fetchone() if task: logger.info(fProcessing task {task[id]} of type {task[task_type]}) # 更新狀態(tài)為running cur.execute( UPDATE octop_tasks SET status running, started_at NOW() WHERE id %s, (task[id],) ) conn.commit() # 提交狀態(tài)變更 # 執(zhí)行任務(wù)此處應(yīng)調(diào)用具體業(yè)務(wù)函數(shù) try: # 模擬業(yè)務(wù)邏輯 time.sleep(1) # 替換為真實(shí)業(yè)務(wù)代碼 # 標(biāo)記成功 cur.execute( UPDATE octop_tasks SET status success, completed_at NOW() WHERE id %s, (task[id],) ) except Exception as e: # 標(biāo)記失敗并重試 cur.execute( UPDATE octop_tasks SET status failed, last_error %s, retry_count retry_count 1 WHERE id %s AND retry_count max_retries, (str(e), task[id]) ) # 若重試已達(dá)上限標(biāo)記為frozen cur.execute( UPDATE octop_tasks SET status frozen WHERE id %s AND retry_count max_retries, (task[id],) ) conn.commit() else: time.sleep(interval) except Exception as e: logger.error(fScheduler error: {e}) time.sleep(interval) finally: conn.close() if __name__ __main__: schedule_loop()設(shè)置環(huán)境變量并啟動(dòng)export DB_HOSTlocalhost export DB_PORT5432 export DB_NAMEoctop_scheduler export DB_USERoctop_app export DB_PASSWORDOct0p!2024SecurePass python octop_scheduler.py此時(shí)調(diào)度器開始每5秒掃描一次日志會(huì)輸出2024-06-15 10:00:00,000 - INFO - Starting Octop scheduler with interval 5s 2024-06-15 10:00:05,000 - INFO - Processing task a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8 of type user_profile_sync實(shí)操心得首次運(yùn)行時(shí)務(wù)必手動(dòng)插入一條測(cè)試任務(wù)驗(yàn)證流程INSERT INTO octop_tasks (task_type, scheduled_at, payload, max_retries) VALUES (test, NOW(), {message: Hello from Octop}, 1);如果調(diào)度器日志顯示Processing task...且數(shù)據(jù)庫(kù)中該任務(wù)status變?yōu)閟uccess說明環(huán)境完全就緒。我踩過的最大坑是PostgreSQL默認(rèn)max_connections100而調(diào)度器每輪創(chuàng)建新連接若未及時(shí)close()10輪后連接池耗盡——因此代碼中conn.close()放在finally塊是生死線。6. 任務(wù)注冊(cè)與執(zhí)行用SQL和Python協(xié)同構(gòu)建可靠工作流Octop的“任務(wù)注冊(cè)”不是調(diào)用API而是向PostgreSQL插入一行數(shù)據(jù)“任務(wù)執(zhí)行”不是啟動(dòng)進(jìn)程而是調(diào)度器從數(shù)據(jù)庫(kù)撈出這行并調(diào)用對(duì)應(yīng)Python函數(shù)。這種SQL-Python協(xié)同模式把工作流的定義權(quán)完全交給數(shù)據(jù)庫(kù)管理員DBA和開發(fā)者共同掌控。下面以“用戶登錄統(tǒng)計(jì)日?qǐng)?bào)”任務(wù)為例完整演示從注冊(cè)到執(zhí)行的閉環(huán)。6.1 任務(wù)注冊(cè)用SQL定義調(diào)度契約首先為日?qǐng)?bào)任務(wù)創(chuàng)建專用表遵循Octop慣例按領(lǐng)域建表-- 創(chuàng)建日?qǐng)?bào)任務(wù)表 CREATE TABLE login_report_tasks ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), report_date DATE NOT NULL, status TEXT NOT NULL CHECK (status IN (pending, running, success, failed, frozen)), created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(), started_at TIMESTAMPTZ NULL, completed_at TIMESTAMPTZ NULL, last_error TEXT NULL CHECK (length(last_error) 1024) ); -- 創(chuàng)建索引 CREATE INDEX idx_login_report_tasks_date_status ON login_report_tasks (report_date, status) WHERE status pending;然后注冊(cè)明日的日?qǐng)?bào)任務(wù)注意scheduled_at必須是UTC時(shí)間且早于實(shí)際執(zhí)行時(shí)間-- 注冊(cè)2024-06-16的日?qǐng)?bào)任務(wù)設(shè)定UTC時(shí)間01:00觸發(fā)北京時(shí)間09:00 INSERT INTO login_report_tasks (report_date, status, created_at) VALUES (2024-06-16, pending, NOW()); -- 同時(shí)在octop_tasks主表中插入調(diào)度元數(shù)據(jù)關(guān)鍵 INSERT INTO octop_tasks ( task_type, scheduled_at, payload, max_retries ) VALUES ( login_report_daily, 2024-06-16 01:00:0000, -- UTC時(shí)間 {report_date: 2024-06-16}, 2 );提示octop_tasks表是調(diào)度器的“中央任務(wù)池”所有任務(wù)類型無論業(yè)務(wù)表名都必須在此注冊(cè)。task_type字段用于路由payload中的report_date是業(yè)務(wù)參數(shù)兩者分離保證了調(diào)度邏輯與業(yè)務(wù)邏輯解耦。6.2 任務(wù)執(zhí)行器Python函數(shù)與SQL狀態(tài)的精準(zhǔn)咬合在octop_scheduler.py中擴(kuò)展任務(wù)執(zhí)行邏輯# 在文件頂部添加業(yè)務(wù)函數(shù) def generate_login_report(report_date: str) - None: Generate daily login report for given date. # 此處連接業(yè)務(wù)數(shù)據(jù)庫(kù)執(zhí)行統(tǒng)計(jì)SQL # 示例SELECT COUNT(*) FROM user_logins WHERE login_time::date %s pass # 在schedule_loop()的try塊中替換模擬業(yè)務(wù)邏輯部分 if task: logger.info(fProcessing task {task[id]} of type {task[task_type]}) cur.execute( UPDATE octop_tasks SET status running, started_at NOW() WHERE id %s, (task[id],) ) conn.commit() try: # 解析payload并執(zhí)行對(duì)應(yīng)業(yè)務(wù)函數(shù) payload task[payload] if task[task_type] login_report_daily: report_date payload.get(report_date) if not report_date: raise ValueError(Missing report_date in payload) generate_login_report(report_date) # 標(biāo)記成功 cur.execute( UPDATE octop_tasks SET status success, completed_at NOW() WHERE id %s, (task[id],) ) else: raise NotImplementedError(fUnknown task_type: {task[task_type]}) except Exception as e: # 處理失敗更新狀態(tài)并記錄錯(cuò)誤 error_msg str(e)[:1024] # 截?cái)喾酪绯?cur.execute( UPDATE octop_tasks SET status failed, last_error %s, retry_count retry_count 1 WHERE id %s AND retry_count max_retries, (error_msg, task[id]) ) # 檢查是否需凍結(jié) cur.execute( UPDATE octop_tasks SET status frozen WHERE id %s AND retry_count max_retries, (task[id],) ) conn.commit()關(guān)鍵點(diǎn)在于狀態(tài)更新與業(yè)務(wù)執(zhí)行的嚴(yán)格順序UPDATE ... SET status running必須在業(yè)務(wù)執(zhí)行前完成且在獨(dú)立事務(wù)中提交——這確保即使業(yè)務(wù)函數(shù)崩潰數(shù)據(jù)庫(kù)中狀態(tài)已是running避免任務(wù)被重復(fù)調(diào)度。generate_login_report()執(zhí)行完畢后才UPDATE ... SET status success。若此步失敗如網(wǎng)絡(luò)問題任務(wù)狀態(tài)卡在running調(diào)度器下次掃描會(huì)發(fā)現(xiàn)status running但completed_at IS NULL從而觸發(fā)超時(shí)檢測(cè)需在后續(xù)擴(kuò)展中加入。錯(cuò)誤處理中l(wèi)ast_error被截?cái)嘀?024字符這是對(duì)TEXT字段的物理約束防止單條錯(cuò)誤日志撐爆表空間。6.3 監(jiān)控與審計(jì)用原生SQL實(shí)現(xiàn)全鏈路可觀測(cè)性O(shè)ctop不提供Prometheus指標(biāo)或Grafana面板但PostgreSQL自帶的pg_stat_statements和自定義視圖足以構(gòu)建企業(yè)級(jí)監(jiān)控-- 創(chuàng)建任務(wù)狀態(tài)視圖實(shí)時(shí)反映調(diào)度健康度 CREATE OR REPLACE VIEW octop_task_summary AS SELECT status, COUNT(*) as count, MIN(scheduled_at) as earliest_scheduled, MAX(scheduled_at) as latest_scheduled, AVG(EXTRACT(EPOCH FROM (NOW() - scheduled_at))) as avg_delay_seconds FROM octop_tasks GROUP BY status; -- 查詢當(dāng)前狀態(tài) SELECT * FROM octop_task_summary; -- 輸出示例 -- status | count | earliest_scheduled | latest_scheduled | avg_delay_seconds -- --------------------------------------------------------------------------------------------- -- pending | 12 | 2024-06-15 01:00:0000 | 2024-06-20 01:00:0000 | 1245.32 -- success | 142 | 2024-06-14 01:00:0000 | 2024-06-15 01:00:0000 | 120.05 -- failed | 3 | 2024-06-14 01:00:0000 | 2024-06-14 01:00:0000 | 2340.11 -- 創(chuàng)建失敗任務(wù)詳情查詢供DBA快速定位 CREATE OR REPLACE VIEW octop_failed_tasks AS SELECT id, task_type, scheduled_at, created_at, last_error, EXTRACT(EPOCH FROM (NOW() - created_at)) as age_seconds FROM octop_tasks WHERE status IN (failed, frozen) ORDER BY created_at DESC LIMIT 10;DBA只需運(yùn)行SELECT * FROM octop_task_summary;就能立刻掌握系統(tǒng)負(fù)載運(yùn)行SELECT * FROM octop_failed_tasks;就能看到最近10個(gè)失敗任務(wù)的完整上下文。這種監(jiān)控方式的優(yōu)勢(shì)在于所有查詢結(jié)果可被審計(jì)日志記錄且無需額外部署監(jiān)控組件——符合MIT對(duì)“基礎(chǔ)設(shè)施透明性”的要求。我在實(shí)際項(xiàng)目中還增加了pg_cron自動(dòng)清理歷史任務(wù)--
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
久久网思思| 五月丁香六月激情在线| 国产成人av在线播放| 99热这里只有精品1| 天天添天天摸天天天天做| 丁香婷婷婷五月综合色情| 精品婷婷| 久婷婷色| 日本五月天网站| 亚州激情在线视频| 久久视网36| 伊人狠狠色婷婷综合丁香一区| 99热综合| a在线观看| 91久久色| 久久综合影院| 97资源欧美日韩大香蕉超碰一区| 可以看的AV| 99久久国产成人精品| 九九九九九九毛片| 99五月婷| 9久热在线视频精品| 国产真实乱对白精彩| 99精品在线播放| 99在线精品在线视频| 国内婷婷丁香社区在线播放| 深爱五月婷婷开心中文字幕| 99色婷婷视频| 成片免费观看视频大全| 综合亚洲六月婷婷在线| 五月婷婷六月丁香激情深爱| 激情婷婷色小说| 97视频久久| 婷婷色操| 婷婷激情综合| 思思热闹这里只有精品| 婷婷丁香77777| 久操福利| 综合色久| 色综合久久88色综合天天人守婷| 日韩六十路91性交电影| 色婷婷a三区麻| 婷五月天在线草| 丁香五月激情宗合| 亚洲乱码日产精品BD| 五月丁香操婷逼| 五月天伊人综合| 亚洲综合99| 国产一二三四五六七八视频| 激情小说视频图片| 久久92| 久久婷婷六月综合综合色| 开心激情站婷婷五月天| 婷婷在线精品| 99热这里只有精品98| 性色欲情 网站| 亚洲婷婷五月天综合| 亚洲欧美婷婷五月色综合| 99色五月| 亚洲第一色色色| 色播五月婷婷综合| 五月丁香婷婷成人网| 五月天啪啪啪| 激情四射五月天| 婷婷丁香六月| www.com.色色| 777久久综合视频| 天天草狠狠擦| 色综合激情| 欧美大香蕉视频| 婷婷九九| 久久久久久综合五月婷婷| 99热这里只有精品官网| 久九色| 五月婷婷激情综合| 99在线小视频| 天堂婷婷五月在线| 五月丁香色综合| 日韩av在线电影| 亚洲黄色影视| 超碰99热在线观看| 五月婷婷播| 色五月婷婷五月丁香五月| 五月婷婷六月丁香在线视频| 丁香五月色| 久久AV无码精品人妻系列试探| 五月天久久小说| 婷婷五月综合啪| 激情婷婷丁香五月天| 99精品偷自拍| 91色在线 | 日韩| 99热综合| 人妻aV在线| 夜夜操狠狠操| 五月丁香激情综合六月涩涩爱| 激情网第九色| 天堂网啪啪| 亚洲色综合| 狠狠婷婷日韩| Va另类视频| 天天综合精品| 日韩久操婷婷| www.狠狠干com| 超碰免费99| 国产欧美日韩综合精品一区二区| 激情久久久| 麻豆五月丁香婷婷| 最近中文字幕大全免费版在线 | 欧美色色日韩| 森林影视大全,最好看的2019年视频 | 五月天激情无码专区| 原琪琪色影院| 五月婷婷,狠狠操| 综合欧美五月婷婷| 天天日天天爽夜夜爽| 亚洲黄网AV| 另类视频一区| 伊人久久艹| 婷综合六月| 天天噜天天插| 亚洲天堂色色| 免费无码毛片一区二区A片| 五月婷婷综合天天操| 开心五月婷婷五月| 97干在线| 激情五月婷婷综合| 婷婷丁香六月| 九九色中文| 激情五月开心五月丁香五月| 国产欧美大香蕉一区| 少妇做爰免费视看片| 婷婷五月色影视先锋| 五月婷婷色情| www.ywav| 五月婷婷丁香网| 国产亚洲精品久久久久苍井松| AV在线免费播放| 丁香六月婷婷色XXXXX| 91男人操女人视频| 老妇操B| 无码婷婷五月天| 99热伊人| 人人看人人草人人摸| 五月天综合色| 天天综合.com| www.婷婷com| 丁香五月在线伊人| 逼特逼在线免费播放| 色综久久AV| 综合色播| 亚洲AAA| 国产精品天天狠天天看| www,av好吊操| 婷婷玖玖五月天| 激情五月天综合| 亚洲综合视频八| 日韩av网址大全| 日本91在线播放| 久草xx性爱视频| 黄色视频网站在线播放| 人人摸人人摸| 五月婷婷色色| WWW色五月| 四虎婷婷五月天| av九九| 天天射天天射一道本日本社区 | 欧美色欲色欲天天天www| 丁香五月天欧美在线| 亚洲乱码日产精品BD| 天天插夜夜爽| 国产肏屄大片| 亚洲精品又粗又大又爽A片| 日本天天综合| 久久免费丁香| 中国丰满熟女A片免费观| RenRenSe在线视频网站| 五月婷婷六月丁香首页| 午夜天堂啪啪| 26uuu成人网| 熟女网站久久| 国产玖玖资源| 狠狠色丁香| 色婷婷五月天| 日本九九网| 99热国产| 影音先锋综合网| 婷婷在线综合| 伊人9999| 欧美日韩一a.无| 中文中文在线| 综合五月婷婷| www.一起草av| 久久AAAA片一区二区| 婷婷六月情| 99九九精品视频| 九九色逼| 超碰色综合| 国产五月丁香在线| 99精品女人天堂| 狠狠干在线视频| 99精品丰满| 4399亚洲视频| Www.狠狠| 99秘 在线| 久久色天堂| 精国产品一区二区三区A片| 欧美成人精品老美女噜噜噜| 五月天激日本色情在线| 人妻久久婷婷| 亚洲AV无码成人精品区电影网| 亚州色色色| 久久99性爱| 激情久久久| 色色综合院| 99热只有| 婷婷丁香五月天激情| 狠狠综合色网| 综合九色| 91熟妇大香蕉| 级人人91| 久久九九99视频| 久久只有18视频| 亚洲aV写真天天综合网久久| 婷婷丁香五月噜噜噜| 五月丁香综合| 97AV在线视频| 久久作爱| 久久免费9| 97sese婷婷| 高清无码网址| 狠狠穞A片一區二區三區| 婷婷狠狠干| 狠狠搞综合色| 色色丁香五月婷婷| 大香蕉院线| 嫩草AV久久伊人妇女超级A| 亚洲综合草草| 亚洲区视频| 天天操婷婷| 激情久久综合网| 天天婷婷综合| 综合久色五月| 久久五月天黄色五月天色网址| 日韩啪啪视频| 日本精品在线噜噜噜| 午夜丁香六月婷| 婷婷丁香黄色| 无码动漫av| 婷婷五月欧美| 超碰国产AV| 97久操| 五六月婷婷久久| Blackedraw视频一区二区| 激情小说五月天| 另类视频综合| 91精品久久久久久77777| 六月99天天婷婷激情综合| 久久婷婷亚洲无码一起| 99日本黄站| 婷婷伊人久久| 欧美va国产va| 天天综合影院| 久久综合影院 | 色婷久| 丁香婷婷综合色五月激情国产基地| 播播网色播播| 五月丁香999| 9久久久久久久久久久| 99九九视频| 99这里只有精品| 久操激情| 拍真实国产伦偷精品| 99在线精品观看99| 日本44久久在线| 91啦丨九色丨刺激中文| 亚洲AV综合在线观看| 日本久久网| 婷婷五月丁香五月丁香| 久久婷婷五月天激情| 免费在线a| 丁香五月开心亚洲| 五月丁香网av| 天天插综合| 六月婷婷色色色| 91丨九色丨大屁股| 色五月天婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷婷 | 久re热视频| 狠狠爱激情网| 中文字幕日本最新乱码视频| 欧美三级级99久久| 久er7久热| 可以免费看AV网站| 99热国产免费| 久久久精品99| 97丁香五月天| 超碰资源在线| 激情操逼婷婷| 五月激情综合网| 色五月婷婷7777| 丁香五月综合无码趴趴| 色五月开心五月激情五月| 五区毛片七区毛片| 99性爱视频| 日操熟女| 日韩欧美四五区| 99热精品在线| 国产av第一专区| 中美日韩成人在线| 激情五月天小说|五月天开心激情网|亚洲精品国产自在现线|黄色五月天 | AA片在线观看视频在线播放| 日本色99| 五月丁香淫淫婷婷婷| 九九激情综合| 天天综合久久| 这里只有精品视频99| 久操婷婷| 狠狠色噜噜狠狠| 玖玖九九9999在线观看视频精品| 婷婷八月激情| 亚洲无码11| 欧美午夜乱妇午夜福利| 99视频色在线观看| 午夜成人AV在线| 丁香六月婷婷激情| 777精品成人a v久久| 色婷婷免费观看| 91 影音先锋| 97久久人人操| 欧美三级欧美一级| 国产九九一区二区三区| 国产日韩欧美| 亚洲婷婷综合视频| 啄木鸟丝袜美女福利视频| 精品久久人妻| 五月丁香啪啪啪| 99热激情| 丁香六月综合激| 日在线V视频在线播放| 色激情综合| 狠狠情色| z色五月播播久久| 亚洲AV成人一区二区在线观看| 激情综合婷婷五月| 午夜天堂一区人妻| 五月天婷婷爱丁香中文字幕| 婷婷五月天久久久| 五月花综合网| 色欲五月婷婷| 婷婷丁香五月天综合在线日韩| 日韩中文欧美| 三级三久久线久久99久目本WW| 91婷婷色五月| 色综合婷婷| 人人性久久| 婷婷五月丁香综合激情| 99色.com| 在线中文字幕av| 亚洲另类av| 婷婷婷婷色| 99视频综合网| 日本天堂免费99| 日亚二欧美| 天天做天天爱天天高潮| 五月丁香精品| 狠狠操狠狠爱| 日韩综合大黄| 色婷婷综合久久久久| av在线不卡播放| 久久99性爱| 九九综合88| 激情五月婷婷五月| 超碰免费成人| 777影视理论片大全在线观看| 色色色视频| 嫩草AV久久伊人妇女超级A| jiujiu无码五区| 精品一二三区久久AAA片| 婷婷五月天va| 婷婷六月久久| 久久98| 深爱五月激情网| 国产成人精品一区二三区熟女在线| www.爱操com.| 久久婷婷东京热大香樵| 六月激情婷婷| 亚洲最大五月天成人网| 棕合影院色色| AA片在线观看视频在线播放| 可以免费观看的AV| 色七色九九| 国产人妻777人伦精品HD| www.五月天社区| 色色五月婷婷久久| 中文字幕日产A片在线看| 成人丁香婷婷五月天| 丁香五月手机视频| 婷婷激情五月| 激情综合激情综合| 丁香久色| 婷婷六月视频| 婷婷的五月天另类视频| 五月色婷婷影院| 深爱婷婷基地| 丁香五月大香蕉AV| 老妇六区| 久久人人妻| 五月婷婷综合潮喷| 九九综合视频在线观看| 五月狠狠| 五月婷A V在线| 日本久热| 狠狠干夜夜干| 九九热99精品在线| 色性综合| 97人人搞| 91/九色黑人| 五月在线| 五月丁香婷草| 人人噜天天上| 日在线V视频在线播放| 久久jiuwww| 亚洲V国产V欧美V久久久久久 | www色色com| 亚州性爱99| 久久五月婷婷电影| 五月婷婷六月综合| 日本英国美国欧美亚洲国产精亚洲日韩精品在线观看 | 成人综合AV| 天天久久综合| 五月丁香激情五月天| 激情熟女网| 婷婷五月欧美综合| 色色热| 婷婷五月大香蕉| 99热这里只有精品国产首页| 亚洲精| 丁香久久| 五月丁香精品| 丁香五月婷婷av| 亚洲天堂制| 极品人妻VIDEOSSS人妻| 九月婷婷综合| 久久99热这里只频精品6学生| 天天爽天天| 天天爽天天做| 天天xxxxxx天天日| 伊人狠狠干| 色婷婷婷婷成人网| 777久久精品| 六月丁香深深爱综合网| 99碰碰| 99久久99久久| 亚韩在线视频| 色狠狠综合| 婷婷综合亚洲| AV在线中文| 婷婷久久性爱| 超碰免费人妻| 在线五月婷婷小电影| 日本色久| 91一起艹| WWW色综合| 激情五月婷黄版| 综合久久9| 曰曰久久| 综合欧美五月婷婷| 五月婷婷香蕉| 毛片毛片毛片毛片| 丁香五月激情五月| 九九99九九99偷拍视频免费看| 激情五月天在线免费美女视频| 99热在线观看精品| 超碰猛烈的性猛交| 亚洲操操| 开心五月深爱五月| 久久艹 五月天| 香港九九六区八区99| 日韩欧美成人网| 99精品久久久久久久久| 久婷久婷激情肉| 欧美精品啪啪| 婷婷丁香五| 森林影视大全,最好看的2019年视频 | 五月丁香婷婷成人版| 99热性色| 天天日日夜夜爽| ri电影在线| 伊人综合网4| 五月激情网综合| 五月婷婷丁香俺日污视频| 综合XX网| 色色婷| 精品热青草| 人人草碰| 久久九九视频网站| 中文字幕色色| 无码任你操| 国产国产乱老熟女视频网站97| 一本大道伊人AV久久综合| 亚洲正能量欧美| 六月婷婷综合久久| 精品九九视频| 性爱网五月天| 色五月丁香91| 午夜成人AV在线| 婷婷丁香六月激情综合| 97干综合网| 色婷婷激情| 婷婷酒色网| 久久久香| 欧州色色| 99超级碰免费视频| 91人人操人人看| 人人玩人人橾| 九色无码| 极品精品一区二区三区在线| 操逼毛片国语对白| 日本 @ va 免费| 五月激情偷拍| 久久色9| 99热6这里之有精品| 九九热最新地址| 色色综合网站| 7777激情基地| 精品色| 无码激情AAAAA片-区区| 开心五月婷婷婷美女| 开心婷婷五月花| 性视频久久| 久久性都花花世界成人免费视频| 久久色五月天| 九九碰九九爱97超| 成人在线观看一区| 久久这里只有精品16| 亚洲综合九九| 99.N在线视频| 丁香婷婷成人网| 色婷婷成人做爰A片免费看网站| 婷婷五月综合色中文字幕| 久久久久久草黄色片AV在线观看| 日韩 中文 欧美| 天天视频精品9| 色日本丁香婷婷| 大香蕉综合| 亚洲有码在线视频| 97久操视频| 亚洲无码成人性爰网| 亚洲人妻av| AV无码免费| 深爱激情五月婷婷| 色涩视频久久| 丁香婷五月| 大香蕉520| 大香蕉精品视频| 五月丁香在线| 亚洲综合另类| 国产精品美女| 婷婷欧美激情综合| 久久婷婷婷| 91人人操人人看| 色婷婷五月天激情在线观看| 亚洲图色五月天| 亚洲 六月 综合| 1024操逼| 五月婷婷五月天亚洲无码| 丁香网站| 狠狠狠狠狠草| 五月丁香天堂| 97色色色| 五月丁香久久久久| av中文在线| 婷婷五月天在线看| 日本一级一级一级一级| 天天爽天天日人人爱| 九九久久精品| 深爱丁香激情| 日韩成人无码片| 欧美一级操逼视频| 在线不卡中文字幕| 成人午夜无码视频| 综合婷婷六月| 激情婷婷狠狠干综合| 五月开心激情网| 91久女| 丁香五月激情在线| 亚洲综合视频网| 五月婷婷,六月丁香| 五月激情丁香五月| 国产,欧美,学生妹,视频| 九九婷婷五月天影视| 99久热视频在线| 激情欧美五月丁香| 第四色激情网| 国产69久久久欧美黑人A片| 五月丁香在线婷婷蜜桃| 亚洲AV永久无码影院黑人| 色五月涩涩婷婷| 九九人人操| 国产精品99久久久久久久女警| 狠色狠色综合久久| 人人97碰| 久久99最新地址| 天天摸天天透天天舔| 97视频91| 国产精品久久久久9999小说| 九九热精品| 狠狠艹狠狠艹| 99在线视频喷水| 亚洲无码播放| 。久久久久久久久久久久久久人妻| 9在线9在线婷婷在线国产| 色色激情网| 97婷婷丁香五月天激情图片| 日韩精品一品二区三区的使用体验 | 色国产五月| 97碰操| 五月丁香六月激情综合| 丁香婷婷视频| 国内裸舞二区| 涩涩婷婷五月| 五月丁香婷婷五月色| 99啪啪网| 99免费视频在线观看爱| 亚洲成人网无码| 91n啪啪| 五月激情综合网| 夜丁香五月婷婷| 无码四色色色| 久久婷网| 久久久香港| 97色色网| 久久激情五月| 亚洲色另类| 嫩草综合网| 五月婷啪啪| 色亭亭九月| 性爱综合网| 亚洲啪啪网| 三年高清大片免费观看国语| 精品人人操| 色久天| 婷婷深爱五月亚洲综合| 综合亚洲六月婷婷在线| 99狠狠| 色婷婷AV久久| 九九在线热九九在线热99热| 天天综合精品| 久久久中文| 婷婷综合成人| 天天日本夜夜谢| 五月丁香六月情婷婷久久| 久久只有精| 成人中文字幕在线| 丁香五月天堂网AV| 欧美日本99| 久久婷婷丁香花综合网| 在线观看免费人成视频无码| 六月婷婷色综合| 色99在线| av大香蕉| 五月花免费视频| 99自拍视频网站| 六月丁香五月婷婷| 五月婷婷丁香六月| 五月天播播中文字幕| 99久久亚洲国产| 色综合久久久综合久久网| 欧美电影在线播放| 国产全是老熟女太爽了| 成人国产欧美大片一区| 国产精品色情AAAAA片软件| 六月丁香啪啪| 无码激情AAAAA片-区区| 亚洲网在线观看| 懂色av粉嫩av蜜臀av| 99精品偷自拍| 日韩丁香涩| 婷婷在线五月综合| 色婷婷91激情小说| 九色在线观看91av| 色五月婷婷综合在线| 丁香婷婷色九月| 亚洲综合五月天婷婷丁香| 综合激情在线| 五月天无码| 丁香五月综合色婷婷| 五月丁香色色综合| 久热最新视频| 色在线视频网2025| 丁香五月情| 国产精品成人在线| 538在线精品| 色99综合色88| 91日视频| 亚洲性天天| 五月丁香网站在线播放| 日日狠狠久久偷偷四色综合免费| 激情图片五月天| 成人婷99最新| 久久99国产综合精品免费| 草草色情综合网| 五月婷婷色白丝| 综合大香蕉| 99re这里只有精品免费| 婷婷五月天激情五月天| 婷婷情色五月天| 久久五月天婷婷| 超碰九热| 91九色丨国产丨爆乳| 婷婷五月天成人动漫 | 99精品久久| 日本三级99人妇网站| 国产免费av在线| 思思热闹这里只有精品| 狠狠色噜噜狠狠| 九九热10| 99热有精品在线观看| enecarbon-materials.comWu染请涟系Bao护@wip1688 | 91热久88| 开心六月婷| 五月婷婷激情综合视频| 99天堂网| 色婷婷色五月综合| 思思久ren热| 天天色噜| 影音先锋男人女人| 五月丁香婷婷中文| 人妻VideOssS人妻高清| 狠狠草在线观看| 丁香九色不卡aaa| 欧美激情丁香五月| 久草热视频在线观看| 五月丁香六月成人| 欧美日韩五月婷婷| 六月丁香综合网| 超碰人人操在线| 91操黄| 久久这里只精品66| 9l视频自拍九色9l视频在线观看| 亚洲亚洲人成综合网络| 久久九九爽| 狠狠色综合网站久久久久| 99热婷婷| 色综合色五月| 梁铮版蜘蛛女在线观看| 五月色亭丁香| 五月婷网| 激情五月综合第一页| 五月天婷婷乱| 97人人射| 久久久人妻人伦| 日熟女| 激情五月天.色网| 综合色五月天| 激情五月天色色网| 久久人操| 久久久99久久| 夜夜躁婷婷AV| 色五月婷婷五月| 9色资源在线| 五月婷婷久久爱| 99热国产| 九九综合精品| 思思久久99| 国产激情视频在线观看| 色欲天天综合| 五月天久久网站| 婷婷播5月| av一区免费看| 人妻VideOssS人妻高清| 婷婷伊人五月天| 天天噪夜夜爽| 亚洲精品又粗又大又爽A片 | 99久久a线观| 99热免费| 91操色| 精品夜夜澡人妻无码AV| 色五月久久成人婷婷| 五月色网| 婷婷五月永远18免费久久久| 欧美人与性动交CCOO| 99高级会所久久| 午夜少妇在线观看视频| 天天粽合合合合| 性av| 色婷婷丁香五月天| 色综合色综合色综合| 综合久久伊人| 色欲一区二区三区精品A片| 97丁香视频| 激情丁香五月天| 丁香婷婷色情| 六月婷婷激情| eeuus五月婷| 51精品国自产在线| 日韩av网址大全| 999九九九久久久99HD| 深爱五月天| 五月天婷婷影院| 五月婷婷成人| 五月丁香六月合| 一区操| 免费AV在线| 色婷婷手机在线| 色婷婷成人做爰A片免费看网站 | 五月 成人 婷婷| 五月天开心激情综合网| 丁香五月婷婷成人综合| 伊人大香久久| 99自拍视频在线| 欧美丁香六月在线观看视频| 99色综合久久| www.色婷婷.com| 99色区| 黄色片avv| 久久超视频| 五月天婷婷一起草| 色婷婷成人色网| 成人在线综合| 丁香五月婷婷成人色区| 色五月五月婷婷| 色婷婷婷av| www.亚洲激情.com| 变态另类9| 色五月丁香一区在线| 激情五月狠狠喔| 综合久| 久久丁香五月婷婷| 99久在线精品| 极骚大香蕉伊人| 91黄操| 伊人五月人妻精品| 色吧五月婷婷| 五月婷婷丁香在线视频| 激情六月丁香| 20253AV| 99这里只有精品|v| 久久丁香五月婷| a色色色色色| 久久99日本精品视频免费观看| 日日综合网| 26UUU欧美| 开心久久五月天| 丁香花操逼| 天天射影院| 日本视频99| 丁香婷婷色五月天| 99热 这里只有精品 国产 日韩| 9l久久久视频| 色五月大香蕉| 色婷婷a v| 亚洲激情免费视频| VA日本视频| 在线中文亚洲| 国内久久婷婷| 202丰满熟女妇大| 国产操碰| 噜噜在线| 精品A√| 激情综合网激情五月网| 91久久久久久久久18| 日韩成人电影av| 黄急一级视频| 成人短视频在线观看| 在线观看亚洲视频影院| 激情五月天小说| 丁香花五月天| www.99热国产| 九九久久精品| 九九热啪啪| 干一干xxxx| 人妻中文字幕精品| 91在线精品一区二区| 女人高潮内射99精品| 久久伊人五月天| 五月婷婷欧美| 91九色无码日韩| 日亚二欧美| 色99色| 五月丁香成人视频| 婷婷五月婷| 色婷婷丁香五月综合| 色色aⅤ網| 激情合网婷婷| 丁香五月视频在线观看| 欧美天天五月丁香免费观看| 天天操夜夜爽天天操| 国产99久久久| 亚洲中文字幕网| 丁香五月香蕉| 久久九九综合| 天天色综合天天| 欧美日本VA| 99热大全在线观看| 日韩免费乱轮网站| 丁香婷婷五月天网站| 99热 这里只有精品 国产 日韩| 亚洲天堂热| 婷婷在线播放av| 久久欧洲久久| 丁香久色| 99惹精品视频| 开心婷婷五月天激情网| 婷婷五月天激情免费在线观看| 五月婷六月| 婷婷六月亚洲综合| 超碰在线免费9| 婷婷天堂综合| 久久激情网| 中文字幕按摩做爰| 五月婷婷 激情按摩| 91呦呦呦| 伊人网啪啪| 久久xxxx| 五月天婷婷丁香蜜桃91| 亚洲国产网站| 99久久视频| 激情五月天色色网| 男人天堂亚洲综合| 国产精品激情五月天色婷婷| 天天干天天操天天拍| 丁香六月激情四射| 激情五月天视频| 欧美大片免费观看| 五月婷婷精品视频| 8区视频在线| 国产精品五月丁香| 五月丁香六月婷婷的女人| 天天肏高清在线| 俺去也婷婷| 97一区二区| 2015超碰| 99超在线| 可以直接看的av| 婷婷九月| 天天激情站| jiujiujiuwuyuetian| 精a品a视a频| 久久婷婷五月天综合| av在线中文| 人与禽A片啪啪| 一区三区视频有限公司| 六月丁香啪啪啪| 精品一区二区三区三区| 五月六月播婷婷| 丁香五月五月婷婷五月天激情四射| 久大香蕉| 一二线视频 另类| 激情五月天的婷婷| 丁香五月亚洲无码| 日韩综合久| 风流少妇A片一区二区蜜桃| 中文字幕网站在线观看| 开心深爱五月天| 五月精品| 欧美色片中文字幕久久久久| 黄网免费观看| 五月婷婷之美女图片| 六月婷婷五月天| 99久久偷拍视频| 婷婷六月丁香综合| 欧美超级视频97| 伊人高清无码| 婷婷丁香五月亚洲欧美| 99爱这里只有精品免费视频| 激情小说五月天| 97人人操| 狠狠色狠狠色综合日日91| 五月色婷婷亚洲| 人人爱人人草| 成人久碰| henhencao国产在线| 99热免费精品| 激情综合另类| 天天做综合网色综合| www99热| 久久精品综合色| 丁香五月天啪啪激情综和网| 99操视频| 五月婷婷AV| www.色五月| 欧美人人草草| 热99久久这里只有精品| 狠狠搞狠狠操| 大香蕉伊人99| 九九热在线精品视频| 欧美天堂婷婷日韩| 情欲综合网| 综合色色网| 中文字幕永久免费| aaa久久| www.99热精品| 激情五月婷婷丁香| 性爱激情久久| 韩国久久少妇视屏| 99精品免费欧美小视频| 国产FREESEXVIDEOS性中国| 热99国产精品| 九九热只有精品| 91九色精品女同系列| 超碰二区| 色色色婷| 97碰碰在线看视频免费| 日韩黄色电影| 色婷婷五月综合在线| 九月婷婷综合网| 激情五月久久| 九九av在线| 夜色综合网| 婷婷激情人妻| 操操人人| 五月丁香色色网| 色综合99| 色久在| 午夜69成人做爰视频| 激情五月天无码| 日本欧美成人片AAAA| 天天综合色综合| 婷婷丁香激情五月天色色色| 五月停停丁香| 色婷婷五月综合色婷婷| 四月婷婷丁香五月| 亚洲午夜Av| 亚洲AV日韩无码| 五月婷婷激情综合| 99色热| 人妻在线中文字幕久久| JlZZJlZZ8JlZZ亚洲熟女| 五月丁香亚洲婷婷| 七七色色综合| 狠狠操狠狠爱| 婷婷五月丁香高清无码| 欧美 色婷婷| 99re8这里只有精品99re8热视频| 亚洲一级AV在线免费播放| 亚洲性爱电影| 蜜乳9188| 国产av一区二区三区| 五月综合缴情网| 久久嘟嘟丁香| 久久一热| 激情综合网激情五月欧美| 国产色色色色色| 国产成人高清| 七七九九色色| 人人操超碰| 超碰免费大香蕉| 亚洲色色图片| 婷婷五月综合基地| 噜噜操操| 婷婷久久五月天亚洲欧美国产日韩在线观看 | 丁香涩涩爱| 久久东京热婷婷五月| 亚洲欧洲另类| 九九热99热| 亚洲va欧美| 欧美黄色一级| 九九99精品| 日日懆天天懆| 五月婷婷欧美| 狠狠色丁香乆乆| 色五月婷婷操逼| 手机AVAV天堂看网| 天天综合网~91综合网| 五月天婷婷色| nvrentiantang av| 永久99免费视频网站| 色99www.| 成人做爰A片免费看视频| 色色色综合色| 《战争与艾拉》完整版| 成人短视频免费观看| 婷婷丁香五月综合| 五月天成人在线视频网站| 深爱五月激情综合| 伊人综合婷婷| 国产片XXXXA片国语对白| 五月天婷婷AV| 日本在线噜噜| a网站免费观看| 香蕉色色网| 婷婷在线播放| 久久资源网五月婷| 激情五月综合网最新 | 婷婷日本色| 国产暴力强伦轩1区二区小说| 丁香五月婷婷五月天| 天天综合天天玩夜夜玩天天玩夜夜玩 | 午夜成人综合| 淫视馆av三区| 亚洲色综合| 狼人婷婷久久| 色色综合色| 就爱操www com| 日韩亚洲视频| 亚洲成Av人片乱码色第1集| 欧美成人猛片AAAAAAA| 欧美色色色| 丁香五月先锋| 丁香五月天AV| 色五月成人网| 国产日韩欧美性生活| 人人操AV| 99九九视频| 精品九九婷婷| 第四色色色色色丁香五月天| 99久久国产宗和精品1上映| 久久婷色| 五月婷中文字幕| 丁香五月影院| 5月婷婷激情网| 五月婷婷手机在线| 五月激情婷婷六月丁香| 丁香五月自拍| www99热| 五月停亭六月,六月停亭的英语| 欧美日韩国产一区二区| 97超碰色| 婷婷久久爱| 国产97在线日韩亚洲女人被黑人巨大| 午夜天堂一区人妻| 伊人激情| 99色| 成人无码髙潮喷水A片| 色狠狠色| 99热精品在线| 婷婷激情五月| 国产又黄又爽又色的免费| 天天日天天操心| 做爰丰满少妇1313| 成人无码精品1区2区3区免费看| 天天天天干| 欧美交换配乱吟粗大25P| 无码人妻少妇色欲AV一区二区| 国产激情久久久| 嫩BBB槡BBBB搡BBBB| 噼里啪啦在线观看免费完整版视频| 五月激情小说| 国产毛多水多女人A片| 国产又爽又猛又粗的视频A片 | 亚洲激情免费久久| 久色成人| 日韩综合大黄| 婷婷五月激情视频在线| 99在线观看精品视频| 99色| 五月婷婷AV| 99色综合| 久久丁香综合香蕉| 青青艹b| 婷婷色啪| 婷婷五月天成人五月天| 成人色五月天| 韩国久久少妇视屏| 激情五月五月婷婷| 久热 91| 婷婷久久久| 九九成人电影婷婷| 色色色五月天激情资源| 99精品一二三四视频| 九九九这里只有精品| 国产六月婷婷| 五月婷天天搞视频| 大香蕉伊人爱在线| 人人爱人人草| av操逼网| 亚洲免费av在线| 久久网站免费亚洲| 黄页大全十八禁| 日本五月天网站| 久热只有精品| 好吊兆人妻| 成人网在线视频| 久久99热这里| 五月婷婷六月开心| 中文字幕综合网| 男女啪啪做爰高潮无遮挡| 日本三日本三级少妇三级66| 九久9精品| 色五月成人在线| 色五月五月婷婷| 亚洲精品久久久无码| 九月av在线| 丁香五月自拍| www.狠狠艹| 五月天激情网站| 97久久超视频| 婷激情五月天视频导航| 俺也去在线视频| 亚洲这里只有精品| www.9色色色| 99热超碰在线| 色婷五月天综合网| 色五月欧美| 久久中国毛毛片爱久久| 秋霞黄色一级久久| 综合AV在线| 五月天婷婷青青草| 精品成人在线观看| 日韩色色色色| 日本精品99| 99热精品在线免费观看| 六月婷婷五月丁香| 色月丁| 激情五月综亚网| 亚洲精品影视| 天天肏天天舔AV| 夜夜人妻五月天| 免费国产视频| 狠狠婷婷日韩| 蜜臀A∨在线水帘洞| 婷婷在线播放| 天天操天天干天天射| 六月丁香婷婷视频综合在线观看| 激情五婷网| 年轻的妺妺伦理HD中文| 欧美丁香五月97色| 四色AVwww| 欧美私人家庭影院| 婷婷六月色开| 亚洲婷婷欧美婷婷| 999热这里只有美国精品| 亚洲激情丁香五月天色| 综合久久高清| 96色婷婷| 五月丁香婷在线| 99色色| 日本99热| 久久久五月五丁香| 亚洲第一影院高清无码网站| 婷婷五月激情片| 99热在线观看| 婷婷五月天色色| 9热精品| 少妇婷婷五月天| 狠狠插日日干撸| 偷拍丁香九月激情| 五月婷久久| 欧美日韩91| 99热在线爱| 久久女婷| 大香蕉婷婷色| 伊人玖玖精品| 金品在线视频99| 久久99网| 男人視頻站| 婷婷五月丁香综合激情| 狠狠色综合久久久久| 久久机热这里只有精品| 九九综合九| 婷婷婷五月天最新综合你懂的| 免费视频无码| 激情丁香五月婷| av中文在线| 三区激情四射av| AA片在线观看视频在线播放| 秋霞午夜理论| 婷婷综合五月天| 狠狠操天天操天天操| 桃色成人网| 久久只这里有精品| 免费超碰在线观看| 亚洲综合狠狠艹| 婷婷五月日本| 久久天天| 日本精品99网站|