Funnels 同觸發器
Funnel 係一個 graph。一次 run 係一行 row。一個 wait 係一段時間。
成個 model 就係咁多,而呢個產品所有難搞嘅特性都係由呢三句嚟。就係因為咁,改一條行緊嘅 funnel 先會安全。就係因為咁,retry 先唔會重複發送。就係因為咁,星期二取消訂閱嘅人,星期四就乜都收唔到。
實際 run 起上嚟會發生乜
發佈一個 funnel 會寫入一個不可變版本。有人入嚟,就多咗一行紀錄:一次 run,屬於呢個聯絡人,釘住嗰個版本,記住而家喺邊個節點、幾時醒返,同埋佢自己嘅 context。
Worker 會租用醒咗嘅 run,用 SKIP LOCKED 認領,令兩個 worker 唔會攞同一個。佢會一路執行節點,直到遇到等待或者終點,然後寫低下一個醒嘅時間,再放手。
一個節點係 run、聯絡人同節點嘅純函數——而且佢嘅效果同 run 自己嘅推進喺同一個交易入面提交。就係呢一個特性令重試安全。一個 worker 喺「發送」同「推進」之間嗰半秒被殺,結果就係兩樣都有或者兩樣都冇,唔會淨係得一樣。
而且因為時間係 app 畀而唔係資料庫畀,而家寫入嘅一行,而家就到期。如果排程欄用資料庫時鐘做預設值,寫入嗰一刻仲未到期,就會錯過創造佢嗰一下 tick——呢種 bug 睇落冇嘢,直到有訊息遲咗一個鐘先知。
- 1租用
wake_at <= now(),FOR UPDATE SKIP LOCKED。冇租用機制嘅 queue 預設會重複發送。 - 2執行按次序執行節點,直到遇到等待或者終點。每個節點都寫低一步:佢決定咗乜、發出咗乜。
- 3提交效果同推進,一個交易。成個竅門就係呢度。
- 4瞓覺寫入下一個
wake_at。下游仲未有任何紀錄,亦都唔需要有。
每個聯絡人每個版本一次 run
十四個觸發器
乜嘢可以啟動一個 run
呢啲入面有啲係你做嘅嘢。大部分係你嘅客做嘅,或者冇做嘅——而冇採取行動,同採取行動一樣係好嘅觸發器。
佢哋嚟到
form_submit、list_join、contact_created、tag_added 同 segment_enter。一個 segment 係一個即時判斷條件,所以「入咗個 segment」已經涵蓋你表達到嘅每一個「變成咗」——落咗三張單、靜咗九十日、消費超過某個門檻。
佢哋做咗啲嘢
由網站 snippet 嚟嘅 page_visit、message_opened、link_clicked、booking_made 同 payment_made。訊息被打開本身就係聯絡人身上嘅一個事件,所以一個 funnel 可以等佢上次發出嘅嘢嘅反應。
時間,或者你
date_field 加偏移——生日、續約、「一年之後」、之前七日或者之後三日。schedule 用嚟做週期性嗰啲。manual 用嚟做你自己決定發出嘅公告。
你自己嘅應用程式
api_event 係一個自訂事件,你用自己嘅 token 由自己嘅 code 發出。你嘅產品知道嘅任何嘢都可以變成觸發器:啟用咗、邀請咗同事、撞到上限、取消咗、匯出咗。呢個就係令一個發訊息工具變成你產品一部分嘅嘢。
重新進入,一次過決定
一個 funnel 一係可以重新進入,一係唔可以,資料庫會強制執行:每個聯絡人每個 funnel 一次 run,除非你另外講明。同一個觸發器喺同一秒觸發兩次,唔會意外產生兩個 run。
進入條件
觸發器觸發之後,進入規格會決定呢個聯絡人合唔合資格——門口前面嘅一個 segment 條件。慳過喺第一步加一個條件節點,而且令個圖集中講會發生乜,而唔係邊個入得。

十四樣嘢可以啟動佢。十六樣嘢可以跟住發生。
十六個動作同七個流程節點
一個 funnel 做到乜,同佢點樣決定
發送啲嘢
send_email、send_sms、send_push、send_letter——四個渠道,一個圖——另外仲有 notify_team,用喺要通知嗰個人係你嘅員工嗰陣。
改動聯絡人
add_tag、remove_tag、add_to_list、remove_from_list、set_field。一路行一路標記人,就係令下一個 funnel 嘅 segment 簡單嘅原因。
伸出去外面
http_request 打去任何你鍾意嘅地方、create_payment 用你自己連接嘅帳戶,仲有 book_slot 用預約資源。畀錢嗰個仍然係你嘅客;冇人會變成我哋嘅客。
喺 funnel 之間移動
enter_funnel 同 exit_funnel。起一條歡迎序列,喺四個地方叫佢,而唔係維持四份到三月就各自走樣嘅副本。
喺發送時先產生
ai_generate 為每個聯絡人填合併變數,計入你嘅 quota,並且用創意內容同聯絡人屬性嘅 hash 做快取——唔係嘅話你每一次發送、每一個收件人都要畀錢。
等等、分支、分岔、合流
wait 可以接受一段時長、一個日期時間、一個星期幾加時間,或者一個帶偏移的日期欄位。condition 是一個有「是」同「否」嘅分眾判斷。split 係 A/B/n 加權重。join 就將啲分支重新合返埋一齊。
goal — 最重要嗰個
一個 goal 會為任何到達佢嘅人終止成個流程。佢訂咗、佢買咗、佢覆咗:淨低嘅序列就專登為佢取消。唔會有人啱啱返返嚟第二日就收到「我哋好掛住你」,而呢個節點就係防止呢件事嘅。
throttle 同 quiet_hours
Throttle 會為一輪爆發限速,等一個速率上限低嘅郵箱唔會被轟到停擺。Quiet hours 會將訊息押後到一個合理時間先發 — 呢個係喺訊息層面套用,唔使喺圖入面每個分支都抄一次。
執行前會先檢查
驗證器對你同對 AI 都係拒絕同樣嘅嘢
一個圖喺可以發布之前會先被檢查,而個檢查唔係得個建議。無論係人手畫個 funnel 定係模型生成嘅,行嘅都係同一條程式碼路徑,呢個先係生成嘅 funnel 可以信嘅唯一原因。
只有一個入口
兩個入口節點係一種冇人會留意到嘅含糊,直到名單入面錯嘅嗰半收到錯嘅序列先知。
每個節點都去得到
一條孤兒分支,一係係錯誤,一係係你以為會發出但其實冇發出嘅訊息。兩種都值得有人話你知。
循環入面必須有 wait
一個冇 wait 嘅循環,就係中間帶住發送嘅無限循環。呢條規則就係 funnel 同事故之間嘅分別。
每次發送都有佢嘅 creative
一個冇 creative 同冇主旨嘅 send_email 節點係唔可以發布嘅。主旨啱但內容空空嘅訊息係真實會發生嘅失敗模式;喺度會被拒絕。
每個變數都認得
合併變數會喺發布時驗證。{{frist_name}} 係你編輯嗰陣就見到嘅錯字,而唔係「Hi ,」飛入四萬個收件箱。
跟住模擬佢
將一個真實聯絡人乾跑成個圖,然後讀返行過嘅路徑同每一封會發出嘅訊息,連佢幾時發都睇到。乜都唔會走出門。
麻煩嘅情況
七樣嘢會整死一個天真嘅引擎
每一項背後都有一個用確定性時鐘嘅測試,因為每一項都會整死一個睇落完全正確、直到撞上現實先出事嘅實作。
- 1一個自己循環返自己嘅 funnel合理、常見、冇問題 — 只要個循環入面有 wait,而驗證器係堅持要嘅。
- 2有人喺半路退訂封鎖名單係喺發送嗰刻檢查,唔係喺入隊嗰刻。喺入隊嗰刻檢查,就會寄俾喺 wait 期間離開咗嘅人。
- 3一萬人喺入面嗰陣編輯個 funnel佢哋會行完佢哋入嚟嗰陣嗰個版本,行到尾。新入嚟嘅人行新嗰個。
- 4同一個觸發器一秒內觸發兩次只會得一個 run,因為唯一性係一個索引,而唔係先檢查再插入。
- 5聯絡人喺 run 中途被刪除個 run 就完。一個刪除如果仲留低一條序列繼續寄俾某個人,就唔算係刪除。
- 6一個 wait 橫跨夏令時切換「朝早九點,三日」即係時鐘轉前轉後兩邊都係朝早九點。
- 7一個 worker 喺發送同推進之間被殺效果同推進係同一個交易。一係兩樣都發生咗,一係兩樣都冇。
可重現時鐘每個測試都會整冧一個看似合理嘅實作
活動係另外嗰一半
漏斗係有反應嘅。活動係一次性廣播:一個受眾、一個時間表、一個節流,同一次發送。佢係另一種形態嘅嘢,所以我哋刻意將佢分開,而唔係扮成一個得一個節點嘅漏斗。
兩條規則令佢安全。受眾會一次性固化,拒絕行第二次——重新解析會靜靜雞加入發送開始之後先嚟嘅所有人,而去重索引會靠擋住佢自己整出嚟嘅重複嚟掩飾呢件事。另外,計數器係由送達事件重新計出嚟,唔會原地累加,所以一個重試嘅 webhook 冇得谷大報告。
用邊個:如果件事係因為嗰個人做咗啲乜而發生,就係漏斗。如果係因為你某個星期二決定咗啲乜,就係活動。好多行銷自動化出事,就係硬將後者塞入前者個形度。