@@ -205,16 +205,6 @@ impl SubgraphTriggerProcessor {
205205 }
206206 }
207207
208- /// Try to extract deployment hash from the trigger context
209- /// This is implementation-specific and may need adjustment
210- fn try_extract_deployment < C : Blockchain > (
211- & self ,
212- _triggers : & [ HostedTrigger < ' _ , C > ] ,
213- ) -> Option < DeploymentHash > {
214- // This would need to be implemented based on your specific context
215- // For now, return None to use fallback
216- None
217- }
218208
219209 /// Get comprehensive metrics for monitoring
220210 pub async fn get_metrics ( & self ) -> HashMap < String , usize > {
@@ -322,16 +312,12 @@ where
322312 return Ok ( state) ;
323313 }
324314
325- // Try to extract deployment hash from the context
326- // This is a best-effort approach - if we can't get it, fall back to data source name
327- let deployment_hash = if let Some ( deployment) = self . try_extract_deployment ( & triggers) {
328- deployment
329- } else {
330- // Fallback: create a synthetic deployment hash from data source
331- let data_source_name = triggers. first ( ) . unwrap ( ) . host . data_source ( ) . name ( ) ;
332- DeploymentHash :: new ( data_source_name)
333- . unwrap_or_else ( |_| DeploymentHash :: new ( "unknown" ) . unwrap ( ) )
334- } ;
315+ // Create a synthetic deployment hash from data source name for consistent sharding.
316+ // This ensures triggers from the same data source/subgraph are always routed to
317+ // the same shard, maintaining cache locality.
318+ let data_source_name = triggers[ 0 ] . host . data_source ( ) . name ( ) ;
319+ let deployment_hash = DeploymentHash :: new ( data_source_name)
320+ . unwrap_or_else ( |_| DeploymentHash :: new ( "unknown" ) . unwrap ( ) ) ;
335321
336322 // Determine shard assignment
337323 let shard_id = if self . config . enable_sharding {
@@ -345,19 +331,19 @@ where
345331 // Get subgraph state for backpressure
346332 let subgraph_state = self . get_or_create_subgraph_state ( & deployment_hash) ;
347333
348- // Track queue depth
349- let current_queue_depth = subgraph_state
334+ // Check current queue depth before adding new triggers (avoid increment-then-check)
335+ let current_queue_depth = subgraph_state. queue_depth . load ( Ordering :: Relaxed ) ;
336+ let projected_queue_depth = current_queue_depth + triggers. len ( ) ;
337+
338+ // Apply backpressure if needed BEFORE incrementing queue depth
339+ self . apply_backpressure ( logger, & deployment_hash, projected_queue_depth)
340+ . await ;
341+
342+ // Only increment queue depth after backpressure check passes
343+ subgraph_state
350344 . queue_depth
351345 . fetch_add ( triggers. len ( ) , Ordering :: Relaxed ) ;
352346
353- // Apply backpressure if needed
354- self . apply_backpressure (
355- logger,
356- & deployment_hash,
357- current_queue_depth + triggers. len ( ) ,
358- )
359- . await ;
360-
361347 debug ! ( logger, "Processing triggers" ;
362348 "deployment" => deployment_hash. to_string( ) ,
363349 "shard" => shard_id,
@@ -367,59 +353,78 @@ where
367353
368354 proof_of_indexing. start_handler ( causality_region) ;
369355
370- for HostedTrigger {
371- host,
372- mapping_trigger,
373- } in triggers
374- {
375- // Acquire permit and hold it during processing
376- let permit = semaphore. acquire ( ) . await . unwrap ( ) ;
377-
378- // Track active permits
379- self . shard_metrics [ shard_id]
380- . active_permits
381- . fetch_add ( 1 , Ordering :: Relaxed ) ;
382-
383- let start = Instant :: now ( ) ;
384-
385- // Process with permit held
386- state = host
387- . process_mapping_trigger (
388- logger,
389- mapping_trigger,
390- state,
391- proof_of_indexing. cheap_clone ( ) ,
392- debug_fork,
393- instrument,
394- )
395- . await ?;
396-
397- // Permit is automatically dropped here, releasing it
398- drop ( permit) ;
399-
400- // Update metrics
401- self . shard_metrics [ shard_id]
402- . active_permits
403- . fetch_sub ( 1 , Ordering :: Relaxed ) ;
404- self . shard_metrics [ shard_id]
405- . total_processed
406- . fetch_add ( 1 , Ordering :: Relaxed ) ;
407-
408- // Decrement queue depth after processing
409- subgraph_state. queue_depth . fetch_sub ( 1 , Ordering :: Relaxed ) ;
410-
411- let elapsed = start. elapsed ( ) ;
412- subgraph_metrics. observe_trigger_processing_duration ( elapsed. as_secs_f64 ( ) ) ;
413-
414- if elapsed > Duration :: from_secs ( 30 ) {
415- debug ! ( logger, "Trigger processing took a long time" ;
416- "duration_ms" => elapsed. as_millis( ) ,
417- "shard" => shard_id
418- ) ;
356+ // Track processed triggers to ensure proper queue depth cleanup
357+ let mut processed_count = 0 ;
358+
359+ // Use a closure to ensure queue depth is properly decremented on any exit path
360+ let process_result = async {
361+ for HostedTrigger {
362+ host,
363+ mapping_trigger,
364+ } in triggers
365+ {
366+ // Acquire permit and hold it during processing
367+ let permit = semaphore. acquire ( ) . await . unwrap ( ) ;
368+
369+ // Track active permits
370+ self . shard_metrics [ shard_id]
371+ . active_permits
372+ . fetch_add ( 1 , Ordering :: Relaxed ) ;
373+
374+ let start = Instant :: now ( ) ;
375+
376+ // Process with permit held
377+ let result = host
378+ . process_mapping_trigger (
379+ logger,
380+ mapping_trigger,
381+ state,
382+ proof_of_indexing. cheap_clone ( ) ,
383+ debug_fork,
384+ instrument,
385+ )
386+ . await ;
387+
388+ // Permit is automatically dropped here, releasing it
389+ drop ( permit) ;
390+
391+ // Update metrics
392+ self . shard_metrics [ shard_id]
393+ . active_permits
394+ . fetch_sub ( 1 , Ordering :: Relaxed ) ;
395+ self . shard_metrics [ shard_id]
396+ . total_processed
397+ . fetch_add ( 1 , Ordering :: Relaxed ) ;
398+
399+ // Increment processed count for queue cleanup
400+ processed_count += 1 ;
401+
402+ // Handle result
403+ state = result?;
404+
405+ let elapsed = start. elapsed ( ) ;
406+ subgraph_metrics. observe_trigger_processing_duration ( elapsed. as_secs_f64 ( ) ) ;
407+
408+ if elapsed > Duration :: from_secs ( 30 ) {
409+ debug ! ( logger, "Trigger processing took a long time" ;
410+ "duration_ms" => elapsed. as_millis( ) ,
411+ "shard" => shard_id
412+ ) ;
413+ }
419414 }
415+ Ok ( state)
416+ } ;
417+
418+ // Execute processing and ensure queue depth cleanup regardless of outcome
419+ let result = process_result. await ;
420+
421+ // Always decrement queue depth by the number of processed triggers
422+ // This ensures cleanup even if processing failed partway through
423+ if processed_count > 0 {
424+ subgraph_state. queue_depth . fetch_sub ( processed_count, Ordering :: Relaxed ) ;
420425 }
421426
422- Ok ( state )
427+ result
423428 }
424429}
425430
0 commit comments