@@ -95,6 +95,7 @@ class SchedulingContext:
9595 scheduled : list [BuildTrigger .ScheduledJob ]
9696 scheduler_log : StreamLog
9797 schedule_now : list [NixEvalJobSuccess ]
98+ seen_drvs : dict [str , str ] # Maps drvPath to attr name of first occurrence
9899
99100 def __init__ (
100101 self ,
@@ -530,7 +531,18 @@ async def _schedule_ready_jobs(
530531 ) -> list [NixEvalJobSuccess ]:
531532 """Schedule jobs that are ready to run. Returns list of skipped jobs."""
532533 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+
534546 schedule_result = self .schedule_success (build_props , job )
535547 if schedule_result is not None :
536548 ctx .scheduler_log .addStdout (f"\t - { job .attr } \n " )
@@ -715,6 +727,7 @@ async def run(self) -> int:
715727 scheduled = scheduled ,
716728 schedule_now = [],
717729 scheduler_log = scheduler_log ,
730+ seen_drvs = {},
718731 )
719732
720733 # Main scheduling loop
0 commit comments