SearchAdd 主流程

對應入口:

主流程順序

SearchAddHandlersearch_add 的 orchestration 入口,主線可以拆成這 10 步:

  1. request normalize 與 input 建模
  2. actor resolve / session user / signup fallback
  3. 建單前主線風控與 early return
  4. 建立 quote_requests
  5. request-side writers
  6. auto quote / narrow 配對
  7. bid finalize
  8. special flows
  9. reload 最新 request / bid 結果
  10. 必要時補排 legacy newQuoteRequest task

主要 class

Input / orchestration

  • SearchAddRequestNormalizer
  • SearchAddInput
  • SearchAddHandler
  • SearchAddResult

Actor / signup

  • CredentialActorResolver
  • AutoSignupService

Guard / tracking

  • RiskControlGuard
  • SameCategoryServiceConflictGuard
  • RequestTrackingWriter
  • AbuseCheckWriter
  • AbnormalScanWriter

Request create / write

  • QuoteRequestCreator
  • FormSubmissionWriter
  • LandingPageWriter
  • RequestLogWriter
  • RequestActivityWriter
  • FormTimeWriter
  • RequestSummaryUpdater
  • RequestFeeUpdater

Match / finalize

  • AutoQuoteDispatcher
  • AutoQuoteMatcher
  • NarrowMatchBuilder
  • QuoteBidFinalizer
  • BidPricingResolver

Async fallback

  • QuoteRequest::checkR1ManualMatchStartNoAutoQuote()
  • NewQuoteRequestHandler

這是 search_add 裡最容易讓人誤會的 legacy 規則之一。

先用白話講:

  • R1 是前一筆 request
  • R2 是後一筆、和 R1 有關聯的 request
  • 它們不是完全獨立的兩件案件
  • 比較像「同一組需求的第一輪與第二輪」

不要把它理解成:

  • payload 每個欄位都完全相同,所以系統單純判定是重複送兩次

比較接近的理解是:

  • 同一組需求脈絡,系統前後建立了兩張有關聯的 request
  • 所以後一張 R2 不是純新案,而是和前一張 R1 綁在一起

為什麼要記這個關聯:

  • 如果 R2 這輪沒有成功拿到 auto quote
  • 系統可能要回頭把 R1 再丟進後續 manual / related flow
  • 這就是為什麼 legacy 會補排前一筆 newQuoteRequest

對應資料與流程:

  • quote_request_second_links
  • QuoteRequestSecondLink
  • QuoteRequest::checkR1ManualMatchStartNoAutoQuote()
  • task_queue -> newQuoteRequest

所以在排查時,如果看到:

  • 第二張 request 沒有 auto quote
  • 但前一張 request 後來又有新的 downstream 動作

不要先當成髒資料或重複執行。
先確認是不是命中了這條 second-link legacy 流程。

Early Return 觀念

這條 API 不是只有一個成功出口,也不是只有建單失敗才會提前結束。

常見 early return 類型:

  • actor 無法確立
  • category / form 驗證失敗
  • 風控命中
  • 同分類 provider conflict
  • 其他 legacy public error

所以排查時不要直接跳到 matcher,先確認 request 是否真的進入建單與 downstream。

同步主線與後續非同步流程

search_addSuccess 時,代表同步主線已完成,但不代表所有相關資料表都已進入最終狀態。

可以把 lifecycle 分成兩層:

1. 同步主線

這一層通常發生在 search_add request 內,應視為主要 parity 契約。

會穩定影響的內容:

  • quote_requests 核心建單欄位
  • quote_form_submissions
  • quote_form_submission_fields
  • quote_request_landing_pages
  • quote_request_match_infos
  • quote_bids
  • cache_queues
  • 部分 request / bid activity

這一層做 baseline compare 時,應優先確認:

  • request materialization 是否與 legacy 一致
  • provider 名單是否一致
  • bid flags / fee / pricing unit 是否一致
  • legacy match info 寫法是否一致

2. 後續非同步流程

這一層發生在 request return 之後,可能由 queue worker、task event、語音流程或其他 endpoint 繼續改寫資料。

已知常見入口:

  • task_queue -> newQuoteRequest
  • task_event_queue -> request_sent_count
  • task_event_queue -> request_closed
  • Twilio
  • Infobip
  • VoiceContact
  • 其他 close / archive / report issue 類流程

常見影響:

  • quote_requests.sent_count
  • quote_requests.is_notification_mail_sent
  • quote_requests.contact_call_status
  • quote_requests.contact_call_x_count / y_count / z_count
  • quote_requests.is_closed
  • quote_requests.is_archived
  • quote_activities
  • quote_bid_calls

因此,如果舊版與新版在這些欄位不同,不能直接判定為 search_add 同步主線不一致。

目前已知的後續責任點

task_queue -> newQuoteRequest

對應:

  • Task.php
  • NewQuoteRequestHandler

常見影響:

  • quote_requests.is_notification_mail_sent
  • quote_activities
  • event_queue
  • cache_queues

task_event_queue -> request_sent_count

對應:

  • TaskEventQueue.php
  • RequestSentCountHandler

常見影響:

  • 重新計算 quote_requests.sent_count

Twilio / Infobip / VoiceContact

對應:

  • QuoteRequest::countTimeout()
  • QuoteRequest::refuseCall()

常見影響:

  • quote_requests.contact_call_status
  • quote_requests.contact_call_y_count
  • quote_bid_calls
  • quote_activities

task_event_queue -> request_closed

對應:

  • RequestClosedHandler

這支通常不是把 request 關掉的起點,而是 request 已被其他流程關閉後的收尾處理。

文件與驗證上的使用原則

  • 把同步主線與後續非同步流程分開判讀
  • 不要把 quote_activitiescontact_call_status 直接當成同步 parity 欄位
  • 如果舊版 baseline 比新版多出 close / archive / report issue 類 activity,先查後續流程,不要先懷疑 search_add
  • 若要確認某個 downstream 欄位是誰改的,需往下查 task_queuetask_event_queue、相關 endpoint 與 log