@@ -8,12 +8,14 @@ use crate::{cdn, BuildPackageSummary};
8
8
use crate :: { Config , Index , InstanceMetrics , RustwideBuilder } ;
9
9
use anyhow:: Context as _;
10
10
use fn_error_context:: context;
11
- use futures_util:: stream:: TryStreamExt ;
11
+ use futures_util:: { stream:: TryStreamExt , StreamExt } ;
12
12
use sqlx:: Connection as _;
13
13
use std:: collections:: HashMap ;
14
14
use std:: sync:: Arc ;
15
15
use tokio:: runtime:: Runtime ;
16
- use tracing:: { debug, error, info} ;
16
+ use tracing:: { debug, error, info, instrument} ;
17
+
18
+ pub ( crate ) const REBUILD_PRIORITY : i32 = 20 ;
17
19
18
20
// Threshold priority to decide whether a crate will in the rebuild-queue-list.
19
21
// If crate is in the rebuild-queue-list it won't in the build-queue-list.
@@ -656,12 +658,191 @@ impl BuildQueue {
656
658
}
657
659
}
658
660
661
+ /// Queue rebuilds as configured.
662
+ ///
663
+ /// The idea is to rebuild:
664
+ /// * the latest release of each crate
665
+ /// * when the nightly version is older than our configured threshold
666
+ /// * and there was a successful build for that release, that included documentation.
667
+ /// * starting with the oldest nightly versions.
668
+ /// * also checking if there is already a build queued.
669
+ ///
670
+ /// This might exclude releases from rebuilds that
671
+ /// * previously failed but would succeed with a newer nightly version
672
+ /// * previously failed but would succeed just with a retry.
673
+ #[ instrument( skip_all) ]
674
+ pub async fn queue_rebuilds (
675
+ conn : & mut sqlx:: PgConnection ,
676
+ config : & Config ,
677
+ build_queue : & AsyncBuildQueue ,
678
+ ) -> Result < ( ) > {
679
+ let already_queued_rebuilds = sqlx:: query_scalar!(
680
+ r#"SELECT COUNT(*) as "count!" FROM queue WHERE priority >= $1"# ,
681
+ REBUILD_PRIORITY
682
+ )
683
+ . fetch_one ( & mut * conn)
684
+ . await ?;
685
+
686
+ let rebuilds_to_queue = config
687
+ . max_queued_rebuilds
688
+ . expect ( "config.max_queued_rebuilds not set" ) as i64
689
+ - already_queued_rebuilds;
690
+
691
+ if rebuilds_to_queue <= 0 {
692
+ info ! ( "not queueing rebuilds; queue limit reached" ) ;
693
+ return Ok ( ( ) ) ;
694
+ }
695
+
696
+ let mut results = sqlx:: query!(
697
+ "SELECT i.* FROM (
698
+ SELECT
699
+ c.name,
700
+ r.version,
701
+ max(b.rustc_nightly_date) as rustc_nightly_date
702
+
703
+ FROM crates AS c
704
+ INNER JOIN releases AS r ON c.latest_version_id = r.id
705
+ INNER JOIN builds AS b ON r.id = b.rid
706
+
707
+ WHERE
708
+ r.rustdoc_status = TRUE
709
+
710
+ GROUP BY c.name, r.version
711
+ ) as i
712
+ WHERE i.rustc_nightly_date < $1
713
+ ORDER BY i.rustc_nightly_date ASC
714
+ LIMIT $2" ,
715
+ config
716
+ . rebuild_up_to_date
717
+ . expect( "config.rebuild_up_to_date not set" ) ,
718
+ rebuilds_to_queue,
719
+ )
720
+ . fetch ( & mut * conn) ;
721
+
722
+ while let Some ( row) = results. next ( ) . await {
723
+ let row = row?;
724
+
725
+ if !build_queue
726
+ . has_build_queued ( & row. name , & row. version )
727
+ . await ?
728
+ {
729
+ info ! ( "queueing rebuild for {} {}..." , & row. name, & row. version) ;
730
+ build_queue
731
+ . add_crate ( & row. name , & row. version , REBUILD_PRIORITY , None )
732
+ . await ?;
733
+ }
734
+ }
735
+
736
+ Ok ( ( ) )
737
+ }
738
+
659
739
#[ cfg( test) ]
660
740
mod tests {
741
+ use crate :: test:: FakeBuild ;
742
+
661
743
use super :: * ;
662
- use chrono:: Utc ;
744
+ use chrono:: { NaiveDate , Utc } ;
663
745
use std:: time:: Duration ;
664
746
747
+ #[ test]
748
+ fn test_dont_rebuild_when_new ( ) {
749
+ crate :: test:: async_wrapper ( |env| async move {
750
+ env. override_config ( |config| {
751
+ config. max_queued_rebuilds = Some ( 100 ) ;
752
+ config. rebuild_up_to_date = Some ( NaiveDate :: from_ymd_opt ( 2020 , 1 , 1 ) . unwrap ( ) ) ;
753
+ } ) ;
754
+
755
+ env. async_fake_release ( )
756
+ . await
757
+ . name ( "foo" )
758
+ . version ( "0.1.0" )
759
+ . builds ( vec ! [ FakeBuild :: default ( )
760
+ . rustc_version( "rustc 1.84.0-nightly (e7c0d2750 2020-10-15)" ) ] )
761
+ . create_async ( )
762
+ . await ?;
763
+
764
+ let build_queue = env. async_build_queue ( ) . await ;
765
+ assert ! ( build_queue. queued_crates( ) . await ?. is_empty( ) ) ;
766
+
767
+ let mut conn = env. async_db ( ) . await . async_conn ( ) . await ;
768
+ queue_rebuilds ( & mut conn, & env. config ( ) , & build_queue) . await ?;
769
+
770
+ assert ! ( build_queue. queued_crates( ) . await ?. is_empty( ) ) ;
771
+
772
+ Ok ( ( ) )
773
+ } )
774
+ }
775
+
776
+ #[ test]
777
+ fn test_rebuild_when_old ( ) {
778
+ crate :: test:: async_wrapper ( |env| async move {
779
+ env. override_config ( |config| {
780
+ config. max_queued_rebuilds = Some ( 100 ) ;
781
+ config. rebuild_up_to_date = Some ( NaiveDate :: from_ymd_opt ( 2024 , 1 , 1 ) . unwrap ( ) ) ;
782
+ } ) ;
783
+
784
+ env. async_fake_release ( )
785
+ . await
786
+ . name ( "foo" )
787
+ . version ( "0.1.0" )
788
+ . builds ( vec ! [ FakeBuild :: default ( )
789
+ . rustc_version( "rustc 1.84.0-nightly (e7c0d2750 2020-10-15)" ) ] )
790
+ . create_async ( )
791
+ . await ?;
792
+
793
+ let build_queue = env. async_build_queue ( ) . await ;
794
+ assert ! ( build_queue. queued_crates( ) . await ?. is_empty( ) ) ;
795
+
796
+ let mut conn = env. async_db ( ) . await . async_conn ( ) . await ;
797
+ queue_rebuilds ( & mut conn, & env. config ( ) , & build_queue) . await ?;
798
+
799
+ let queue = build_queue. queued_crates ( ) . await ?;
800
+ assert_eq ! ( queue. len( ) , 1 ) ;
801
+ assert_eq ! ( queue[ 0 ] . name, "foo" ) ;
802
+ assert_eq ! ( queue[ 0 ] . version, "0.1.0" ) ;
803
+ assert_eq ! ( queue[ 0 ] . priority, REBUILD_PRIORITY ) ;
804
+
805
+ Ok ( ( ) )
806
+ } )
807
+ }
808
+
809
+ #[ test]
810
+ fn test_dont_rebuild_when_full ( ) {
811
+ crate :: test:: async_wrapper ( |env| async move {
812
+ env. override_config ( |config| {
813
+ config. max_queued_rebuilds = Some ( 1 ) ;
814
+ config. rebuild_up_to_date = Some ( NaiveDate :: from_ymd_opt ( 2024 , 1 , 1 ) . unwrap ( ) ) ;
815
+ } ) ;
816
+
817
+ let build_queue = env. async_build_queue ( ) . await ;
818
+ build_queue
819
+ . add_crate ( "foo1" , "0.1.0" , REBUILD_PRIORITY , None )
820
+ . await ?;
821
+ build_queue
822
+ . add_crate ( "foo2" , "0.1.0" , REBUILD_PRIORITY , None )
823
+ . await ?;
824
+
825
+ env. async_fake_release ( )
826
+ . await
827
+ . name ( "foo" )
828
+ . version ( "0.1.0" )
829
+ . builds ( vec ! [ FakeBuild :: default ( )
830
+ . rustc_version( "rustc 1.84.0-nightly (e7c0d2750 2020-10-15)" ) ] )
831
+ . create_async ( )
832
+ . await ?;
833
+
834
+ let build_queue = env. async_build_queue ( ) . await ;
835
+ assert_eq ! ( build_queue. queued_crates( ) . await ?. len( ) , 2 ) ;
836
+
837
+ let mut conn = env. async_db ( ) . await . async_conn ( ) . await ;
838
+ queue_rebuilds ( & mut conn, & env. config ( ) , & build_queue) . await ?;
839
+
840
+ assert_eq ! ( build_queue. queued_crates( ) . await ?. len( ) , 2 ) ;
841
+
842
+ Ok ( ( ) )
843
+ } )
844
+ }
845
+
665
846
#[ test]
666
847
fn test_add_duplicate_doesnt_fail_last_priority_wins ( ) {
667
848
crate :: test:: async_wrapper ( |env| async move {
0 commit comments