@@ -4,6 +4,8 @@ import { SearchService } from "@anycrawl/search/SearchService";
44import { log } from "@anycrawl/libs/log" ;
55import { searchSchema } from "../../types/SearchSchema.js" ;
66import { RequestWithAuth } from "../../types/Types.js" ;
7+ import { randomUUID } from "crypto" ;
8+ import { STATUS , createJob , insertJobResult , completedJob , failedJob , updateJobCounts , JOB_RESULT_STATUS } from "@anycrawl/db" ;
79export class SearchController {
810 private searchService : SearchService ;
911
@@ -26,21 +28,86 @@ export class SearchController {
2628 }
2729
2830 public handle = async ( req : RequestWithAuth , res : Response ) : Promise < void > => {
31+ let jobId : string | null = null ;
32+ let engineName : string | null = null ;
2933 try {
3034 // Validate request body against searchSchema
3135 const validatedData = searchSchema . parse ( req . body ) ;
3236
3337 // Execute search and wait for results
34- const results = await this . searchService . search ( validatedData . engine ?? "google" , {
38+ engineName = validatedData . engine ?? "google" ;
39+
40+ // Create job for search request (pending)
41+ jobId = randomUUID ( ) ;
42+ await createJob ( {
43+ job_id : jobId ,
44+ job_type : "search" ,
45+ job_queue_name : `search-${ engineName } ` ,
46+ url : `search:${ validatedData . query } ` ,
47+ req,
48+ status : STATUS . PENDING ,
49+ } ) ;
50+ req . jobId = jobId ;
51+
52+ const expectedPages = validatedData . pages || 1 ;
53+ let pagesProcessed = 0 ;
54+ let failedPages = 0 ;
55+ let successPages = 0 ;
56+
57+ const results = await this . searchService . search ( engineName , {
3558 query : validatedData . query ,
3659 limit : validatedData . limit || 10 ,
3760 offset : validatedData . offset || 0 ,
38- pages : validatedData . pages || 1 ,
61+ pages : expectedPages ,
3962 lang : validatedData . lang ,
4063 // country: validatedData.country,
64+ } , async ( page , pageResults , _uniqueKey , success ) => {
65+ try {
66+ pagesProcessed += 1 ;
67+ if ( ! success ) {
68+ failedPages += 1 ;
69+ // Record a failed page entry (single record per page)
70+ await insertJobResult (
71+ jobId ! ,
72+ `search:${ engineName } :${ validatedData . query } :page:${ page } ` ,
73+ { page, query : validatedData . query , results : [ ] } ,
74+ JOB_RESULT_STATUS . FAILED
75+ ) ;
76+ } else {
77+ successPages += 1 ;
78+ // Insert a single record for this page with aggregated results
79+ await insertJobResult (
80+ jobId ! ,
81+ `search:${ engineName } :${ validatedData . query } :page:${ page } ` ,
82+ { page, query : validatedData . query , results : pageResults } ,
83+ JOB_RESULT_STATUS . SUCCESS
84+ ) ;
85+ }
86+
87+ // Update job counts based on pages for progress
88+ await updateJobCounts ( jobId ! , { total : expectedPages , completed : successPages , failed : failedPages } ) ;
89+ } catch ( e ) {
90+ log . error ( `Per-page handler error for job_id=${ jobId } : ${ e instanceof Error ? e . message : String ( e ) } ` ) ;
91+ }
4192 } ) ;
4293 // credits used is the number of pages.
43- req . creditsUsed = validatedData . pages ;
94+ req . creditsUsed = validatedData . pages ?? 1 ;
95+
96+ // Mark job status based on page results
97+ try {
98+ if ( failedPages >= expectedPages ) {
99+ await failedJob (
100+ jobId ,
101+ `All pages failed (${ failedPages } /${ expectedPages } )` ,
102+ false ,
103+ { total : expectedPages , completed : successPages , failed : failedPages }
104+ ) ;
105+ } else {
106+ await completedJob ( jobId , true , { total : expectedPages , completed : successPages , failed : failedPages } ) ;
107+ }
108+ } catch ( e ) {
109+ log . error ( `Failed to mark job final status for job_id=${ jobId } : ${ e instanceof Error ? e . message : String ( e ) } ` ) ;
110+ }
44111 res . json ( {
45112 success : true ,
46113 data : results ,
@@ -62,6 +129,13 @@ export class SearchController {
62129 } ,
63130 } ) ;
64131 } else {
132+ if ( jobId ) {
133+ try {
134+ await failedJob ( jobId , error instanceof Error ? error . message : "Unknown error" , false , { total : 0 , completed : 0 , failed : 0 } ) ;
135+ } catch ( e ) {
136+ log . error ( `Failed to mark job failed for job_id=${ jobId } : ${ e instanceof Error ? e . message : String ( e ) } ` ) ;
137+ }
138+ }
65139 res . status ( 500 ) . json ( {
66140 success : false ,
67141 error : "Internal server error" ,
0 commit comments