SearchAdd Special Flows
快速結論
special flows 不是單一流程。不同 payload 會在不同時間點介入:
- pre auto quote:booking prepare、direct user、authorized match、direct reserve
- post finalize:booking enqueue、authorized contact、direct reserve finalize
- preserve:仍留在一般 auto / narrow 主線,由 matcher 依 legacy 規則處理
current 入口:
SearchAddHandler::handle()
-> SpecialFlowDispatcher::handlePreAutoQuote()
-> AutoQuoteDispatcher / QuoteBidFinalizer
-> SpecialFlowDispatcher::handlePostFinalize()新舊程式對應
Legacy PHP 5.6(current baseline)
主要入口:
/Users/mattsu/Documents/Site/get-lancer-docker-2/get-lancer/app/Plugin/Quotes/Controller/QuoteRequestsController.php::search_add()| legacy flow | 職責 |
|---|---|
| authorized | 指定 provider 建 bid,後續直接進 contact / payment 主線。 |
| preserve | 優先保留指定 provider,但仍在一般 auto / narrow 主線內處理。 |
| direct reserve | 直接預約;可能 direct match 成功,也可能 fallback 成 new leads。 |
| direct user | 平台規則指定 provider,命中後建立 auto quote bid 並進 contact 主線。 |
| booking | booking request-side 資料與後續 task。 |
Current PHP 8.2
| current 位置 | 職責 |
|---|---|
Lib/SearchAdd/SearchAddHandler.php:289-304 | 建單後先跑 handlePreAutoQuote(),並讀取 skip_auto_quote。 |
Lib/SearchAdd/SearchAddHandler.php:322-336 | bid finalize 後跑 handlePostFinalize()。 |
Lib/SearchAdd/SpecialFlowDispatcher.php:50-69 | pre-flow 分流:booking prepare、direct user、authorized match、direct reserve。 |
Lib/SearchAdd/SpecialFlowDispatcher.php:77-100 | post-flow 分流:booking enqueue、authorized contact、direct reserve finalize。 |
Lib/SearchAdd/SpecialFlowDispatcher.php:126-133 | special flow 以落表後 quote_requests.match_type 為準,不只看 raw input。 |
Lib/SearchAdd/AuthorizedMatchProcessor.php | authorized 指定 provider 建 bid。 |
Lib/SearchAdd/AuthorizedContactProcessor.php | authorized contact / payment / notify,走 QuoteBid::processWantToContactProvider() 主線。 |
Lib/SearchAdd/DirectReserveProcessor.php | direct reserve 建立、fallback、finalize。 |
Lib/SearchAdd/DirectUserProcessor.php | direct user 命中與直接送案。 |
Lib/SearchAdd/BookingRequestProcessor.php | booking request-side 與 task。 |
行號對照
| new 行號 | 對應 legacy | 職責 |
|---|---|---|
SearchAddHandler.php:289-304 | QuoteRequestsController.php:3222-3337 | auto quote 前先跑 special flow;必要時 skip 一般 auto quote。 |
SpecialFlowDispatcher.php:50-69 | QuoteRequestsController.php:3222-3337 | pre-flow 分流並 reload request / bids。 |
SpecialFlowDispatcher.php:55 | QuoteRequestsController.php:3031-3034, 3224-3280 | booking request-side prepare。 |
SpecialFlowDispatcher.php:57-58 | QuoteRequestsController.php:3322-3326 | direct user match;命中時由 direct user flow 接管。 |
SpecialFlowDispatcher.php:59-60 | QuoteRequestsController.php:1926-1935, 3328-3332 | authorized 需以正規化後 match type 判斷,再建立指定 provider bid。 |
SpecialFlowDispatcher.php:61-62 | QuoteRequestsController.php:1980-1997, 3282-3311 | direct reserve validate / request 改寫 / reserve row / direct match。 |
SearchAddHandler.php:322-336 | QuoteRequestsController.php:3278-3280, 3303-3310, 3389-3405 | finalize 後跑 post-flow,再 reload response 資料。 |
SpecialFlowDispatcher.php:77-100 | QuoteRequestsController.php:3278-3280, 3303-3310 | post-flow:booking task、authorized contact、direct reserve finalize。 |
SpecialFlowDispatcher.php:126-133 | QuoteRequestsController.php:1926-1935 | special flow 判斷以落表後 match_type 為準,避免 raw input 繞過 category clamp。 |
Side Effects
依 flow 不同,可能同步寫入:
quote_bidsquote_activitiestransactionsquote_user_subscription_logs- reserve 相關資料表
- direct user / match 相關資料表
- booking 相關資料或 task
- event queue / task queue
不可改變的契約
- special flow 判斷要以 request row 的正規化
match_type為準。 - category 不允許 authorized 時,raw payload 硬送
match_type=2不應繞過 category clamp。 - authorized contact 必須回到
QuoteBid::processWantToContactProvider()主線,不能手補一半 side effect。 - authorized bid 的 initial
quote_bids.total_site_fee必須用quote_requests.direct_fee,不是auto_fee。contact 成功後的quote_user_subscription_logs.amount與transactions.amount也必須對齊同一筆 direct fee。 - authorized 無 bid / no-match 時,legacy 是 Operation log +
bdEmailListemail,不是 event queue。current 不應寫沒有 worker contract 的Authorized_Mode_No_Matchevent。 - authorized contact 的
quote_bids.quote_user_subscription_log_id必須指向quote_user_subscription_logs.id,不能用transactions.id代替;既有transaction_type_id=40也不能代表本次 contact charge 已完成。完整 payment/contact parity 以want_to_contact_provider.md為準。 - current Legacy 的
QuoteBid::processWantToContactProvider()沒有 Redis payoff lock;search_add的 authorized、direct reserve、direct user 不可因 PHP 8 額外 lock 被占用而先回 code 11。 quote_request_life_tokens是 Step8 / external integration 建立的 request-side 資料;但 contact 成功後的 Life55688EVENT_EXPERT_QUOTING是QuoteBid::processWantToContactProvider()的 downstream side effect,special flow processor 不應自行手補。- preserve 不是獨立 contact flow。
- direct reserve fallback 到 new leads 時,要分清楚主流程成功與通知副作用失敗。
Payoff lock 對齊(已完成,commit c3abd3aa)
Legacy 實際路徑
| flow | caller | 行為 |
|---|---|---|
| authorized | QuoteService.php:3257-3260,3360-3362 | 直接呼叫 contact 主線,未傳 lock option。 |
| direct reserve | ReserveMatchUtil.php:226-255 | 呼叫 contact 主線;只有 DB deadlock/lock timeout retry,沒有 Redis payoff lock。 |
| direct user | DirectUser.php:178-196 | 呼叫 contact 主線;只有 DB deadlock/lock timeout retry,沒有 Redis payoff lock。 |
| shared contact | QuoteBid.php:4009-4363 | 執行 payment、activity、queue、notification;沒有 acquirePayoffLock()/releasePayoffLock()。 |
PHP 8 實作
| 位置 | 實作 |
|---|---|
Lib/Model/QuoteBid.php:683-708,966-969 | use_payoff_lock 預設為 true;只有啟用時才取得/釋放 Redis payoff lock。 |
AuthorizedContactProcessor.php:42-51 | authorized 明確傳 use_payoff_lock=false。 |
DirectReserveProcessor.php:116-129 | direct reserve 明確傳 use_payoff_lock=false。 |
DirectUserProcessor.php:123-135 | direct user 明確傳 use_payoff_lock=false。 |
其他 caller 不改:Endpoint/V1/QuoteBids.php:2803-2812,2837-2845,3415-3424 與 Lib/Model/QuoteBid.php:5706-5714 繼續使用預設 lock。processCallFee() 的獨立 lock 也不在本次範圍。
本組不改 DB write、payment、activity、queue、notification、response、config、ALB,也不增減 Legacy 的 DB retry。風險是三條 search_add 特殊流程失去 PHP 8 額外的 Redis 並行保護;這是為了對齊 current Legacy,不擴散到其他 PHP 8 caller。
測試重點
- Core:payoff lock 已被占用時,三條
search_add特殊流程仍成功,並保留原本 DB/payment/queue side effects;3 tests / 100 assertions通過。 - Other:未傳 scoped option 的
/quote_bids/want_to_contact_provider/{id}.json仍回 code 11,且不寫 contact/transaction;1 test / 9 assertions通過。 - 共用 contact regression:
QuoteBidsWantToContactProviderTest全部12 tests / 184 assertions通過。 - PHP 8.2 syntax:6 個異動 PHP 檔案全部通過。
Verification
主要測試:
tests/SearchAddStep7IntegrationTest.php
tests/SearchAddStep8IntegrationTest.php
tests/TapPayCreditCardApiTest.phpbaseline 比對依 flow 增加表:
- authorized:
quote_bids、transactions、quote_activities、event queue / log、payment log - authorized fee:
SearchAddStep7IntegrationTest::testAuthorizedModeContactsFirstMatchedProvider以auto_fee != direct_fee驗證 request、bid、subscription log、transaction 金額都使用direct_fee - authorized no-match:
SearchAddStep7IntegrationTest::testAuthorizedModeNoMatchWritesOperationLogAndBdEmail驗證沒有 bid 時寫 Operation log 與 BD email - direct reserve:reserve row、pause event、narrow bid、direct reserve event
- direct user:direct user match table、bid、contact side effects
- booking:booking row / task / bid count
待確認 / 風險
- authorized payment sequence 若再補新 case,必須覆蓋「無 prime 失敗、有 prime 成功、foreign card fail」這類前後流程,不可只測 happy path。
AuthorizedMatchProcessor、AuthorizedContactProcessor、DirectReserveProcessor、DirectUserProcessor內部仍需再各自補一層精確行號對照。