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