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 主線。
bookingbooking request-side 資料與後續 task。

Current PHP 8.2

current 位置職責
Lib/SearchAdd/SearchAddHandler.php:289-304建單後先跑 handlePreAutoQuote(),並讀取 skip_auto_quote
Lib/SearchAdd/SearchAddHandler.php:322-336bid finalize 後跑 handlePostFinalize()
Lib/SearchAdd/SpecialFlowDispatcher.php:50-69pre-flow 分流:booking prepare、direct user、authorized match、direct reserve。
Lib/SearchAdd/SpecialFlowDispatcher.php:77-100post-flow 分流:booking enqueue、authorized contact、direct reserve finalize。
Lib/SearchAdd/SpecialFlowDispatcher.php:126-133special flow 以落表後 quote_requests.match_type 為準,不只看 raw input。
Lib/SearchAdd/AuthorizedMatchProcessor.phpauthorized 指定 provider 建 bid。
Lib/SearchAdd/AuthorizedContactProcessor.phpauthorized contact / payment / notify,走 QuoteBid::processWantToContactProvider() 主線。
Lib/SearchAdd/DirectReserveProcessor.phpdirect reserve 建立、fallback、finalize。
Lib/SearchAdd/DirectUserProcessor.phpdirect user 命中與直接送案。
Lib/SearchAdd/BookingRequestProcessor.phpbooking request-side 與 task。

行號對照

new 行號對應 legacy職責
SearchAddHandler.php:289-304QuoteRequestsController.php:3222-3337auto quote 前先跑 special flow;必要時 skip 一般 auto quote。
SpecialFlowDispatcher.php:50-69QuoteRequestsController.php:3222-3337pre-flow 分流並 reload request / bids。
SpecialFlowDispatcher.php:55QuoteRequestsController.php:3031-3034, 3224-3280booking request-side prepare。
SpecialFlowDispatcher.php:57-58QuoteRequestsController.php:3322-3326direct user match;命中時由 direct user flow 接管。
SpecialFlowDispatcher.php:59-60QuoteRequestsController.php:1926-1935, 3328-3332authorized 需以正規化後 match type 判斷,再建立指定 provider bid。
SpecialFlowDispatcher.php:61-62QuoteRequestsController.php:1980-1997, 3282-3311direct reserve validate / request 改寫 / reserve row / direct match。
SearchAddHandler.php:322-336QuoteRequestsController.php:3278-3280, 3303-3310, 3389-3405finalize 後跑 post-flow,再 reload response 資料。
SpecialFlowDispatcher.php:77-100QuoteRequestsController.php:3278-3280, 3303-3310post-flow:booking task、authorized contact、direct reserve finalize。
SpecialFlowDispatcher.php:126-133QuoteRequestsController.php:1926-1935special flow 判斷以落表後 match_type 為準,避免 raw input 繞過 category clamp。

Side Effects

依 flow 不同,可能同步寫入:

  • quote_bids
  • quote_activities
  • transactions
  • quote_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.amounttransactions.amount 也必須對齊同一筆 direct fee。
  • authorized 無 bid / no-match 時,legacy 是 Operation log + bdEmailList email,不是 event queue。current 不應寫沒有 worker contract 的 Authorized_Mode_No_Match event。
  • 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 成功後的 Life55688 EVENT_EXPERT_QUOTINGQuoteBid::processWantToContactProvider() 的 downstream side effect,special flow processor 不應自行手補。
  • preserve 不是獨立 contact flow。
  • direct reserve fallback 到 new leads 時,要分清楚主流程成功與通知副作用失敗。

Payoff lock 對齊(已完成,commit c3abd3aa

Legacy 實際路徑

flowcaller行為
authorizedQuoteService.php:3257-3260,3360-3362直接呼叫 contact 主線,未傳 lock option。
direct reserveReserveMatchUtil.php:226-255呼叫 contact 主線;只有 DB deadlock/lock timeout retry,沒有 Redis payoff lock。
direct userDirectUser.php:178-196呼叫 contact 主線;只有 DB deadlock/lock timeout retry,沒有 Redis payoff lock。
shared contactQuoteBid.php:4009-4363執行 payment、activity、queue、notification;沒有 acquirePayoffLock()releasePayoffLock()

PHP 8 實作

位置實作
Lib/Model/QuoteBid.php:683-708,966-969use_payoff_lock 預設為 true;只有啟用時才取得/釋放 Redis payoff lock。
AuthorizedContactProcessor.php:42-51authorized 明確傳 use_payoff_lock=false
DirectReserveProcessor.php:116-129direct reserve 明確傳 use_payoff_lock=false
DirectUserProcessor.php:123-135direct user 明確傳 use_payoff_lock=false

其他 caller 不改:Endpoint/V1/QuoteBids.php:2803-2812,2837-2845,3415-3424Lib/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.php

baseline 比對依 flow 增加表:

  • authorized:quote_bidstransactionsquote_activities、event queue / log、payment log
  • authorized fee:SearchAddStep7IntegrationTest::testAuthorizedModeContactsFirstMatchedProviderauto_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。
  • AuthorizedMatchProcessorAuthorizedContactProcessorDirectReserveProcessorDirectUserProcessor 內部仍需再各自補一層精確行號對照。