@@ -95,6 +95,7 @@ class SchedulingContext:
95
95
scheduled : list [BuildTrigger .ScheduledJob ]
96
96
scheduler_log : StreamLog
97
97
schedule_now : list [NixEvalJobSuccess ]
98
+ seen_drvs : dict [str , str ] # Maps drvPath to attr name of first occurrence
98
99
99
100
def __init__ (
100
101
self ,
@@ -530,7 +531,18 @@ async def _schedule_ready_jobs(
530
531
) -> list [NixEvalJobSuccess ]:
531
532
"""Schedule jobs that are ready to run. Returns list of skipped jobs."""
532
533
skipped_jobs = []
533
- for job in ctx .schedule_now :
534
+ for job in sorted (ctx .schedule_now , key = lambda j : j .attr ):
535
+ # Check if we've already scheduled a build for this derivation (alias detection)
536
+ if job .drvPath in ctx .seen_drvs :
537
+ original_attr = ctx .seen_drvs [job .drvPath ]
538
+ ctx .scheduler_log .addStdout (
539
+ f"\t - { job .attr } (skipped, alias of { original_attr } )\n "
540
+ )
541
+ skipped_jobs .append (job )
542
+ self ._skipped_count += 1
543
+ continue
544
+ ctx .seen_drvs [job .drvPath ] = job .attr
545
+
534
546
schedule_result = self .schedule_success (build_props , job )
535
547
if schedule_result is not None :
536
548
ctx .scheduler_log .addStdout (f"\t - { job .attr } \n " )
@@ -715,6 +727,7 @@ async def run(self) -> int:
715
727
scheduled = scheduled ,
716
728
schedule_now = [],
717
729
scheduler_log = scheduler_log ,
730
+ seen_drvs = {},
718
731
)
719
732
720
733
# Main scheduling loop
0 commit comments