1
1
use chrono:: { DateTime , Utc } ;
2
2
use std:: collections:: HashMap ;
3
+ use std:: sync:: Arc ;
3
4
4
5
use async_trait:: async_trait;
5
6
use reqwest:: Client ;
@@ -10,7 +11,7 @@ use crate::github::{self, GithubClient, Repository};
10
11
11
12
#[ async_trait]
12
13
pub trait Action {
13
- async fn call ( & self ) -> String ;
14
+ async fn call ( & self ) -> anyhow :: Result < String > ;
14
15
}
15
16
16
17
pub struct Step < ' a > {
@@ -24,6 +25,7 @@ pub struct Query<'a> {
24
25
pub queries : Vec < QueryMap < ' a > > ,
25
26
}
26
27
28
+ #[ derive( Copy , Clone ) ]
27
29
pub enum QueryKind {
28
30
List ,
29
31
Count ,
@@ -32,7 +34,7 @@ pub enum QueryKind {
32
34
pub struct QueryMap < ' a > {
33
35
pub name : & ' a str ,
34
36
pub kind : QueryKind ,
35
- pub query : Box < dyn github:: IssuesQuery + Send + Sync > ,
37
+ pub query : Arc < dyn github:: IssuesQuery + Send + Sync > ,
36
38
}
37
39
38
40
#[ derive( Debug , serde:: Serialize ) ]
@@ -81,58 +83,65 @@ pub fn to_human(d: DateTime<Utc>) -> String {
81
83
82
84
#[ async_trait]
83
85
impl < ' a > Action for Step < ' a > {
84
- async fn call ( & self ) -> String {
86
+ async fn call ( & self ) -> anyhow :: Result < String > {
85
87
let gh = GithubClient :: new_with_default_token ( Client :: new ( ) ) ;
86
88
87
89
let mut context = Context :: new ( ) ;
88
90
let mut results = HashMap :: new ( ) ;
89
91
92
+ let mut handles: Vec < tokio:: task:: JoinHandle < anyhow:: Result < ( String , QueryKind , Vec < _ > ) > > > =
93
+ Vec :: new ( ) ;
94
+ let semaphore = std:: sync:: Arc :: new ( tokio:: sync:: Semaphore :: new ( 5 ) ) ;
95
+
90
96
for Query { repos, queries } in & self . actions {
91
97
for repo in repos {
92
98
let repository = Repository {
93
99
full_name : format ! ( "{}/{}" , repo. 0 , repo. 1 ) ,
94
100
} ;
95
101
96
102
for QueryMap { name, kind, query } in queries {
97
- let issues = query. query ( & repository, name == & "proposed_fcp" , & gh) . await ;
98
-
99
- match issues {
100
- Ok ( issues_decorator) => match kind {
101
- QueryKind :: List => {
102
- results
103
- . entry ( * name)
104
- . or_insert ( Vec :: new ( ) )
105
- . extend ( issues_decorator) ;
106
- }
107
- QueryKind :: Count => {
108
- let count = issues_decorator. len ( ) ;
109
- let result = if let Some ( value) = context. get ( * name) {
110
- value. as_u64 ( ) . unwrap ( ) + count as u64
111
- } else {
112
- count as u64
113
- } ;
114
-
115
- context. insert ( * name, & result) ;
116
- }
117
- } ,
118
- Err ( err) => {
119
- eprintln ! ( "ERROR: {}" , err) ;
120
- err. chain ( )
121
- . skip ( 1 )
122
- . for_each ( |cause| eprintln ! ( "because: {}" , cause) ) ;
123
- std:: process:: exit ( 1 ) ;
124
- }
125
- }
103
+ let semaphore = semaphore. clone ( ) ;
104
+ let name = String :: from ( * name) ;
105
+ let kind = * kind;
106
+ let repository = repository. clone ( ) ;
107
+ let gh = gh. clone ( ) ;
108
+ let query = query. clone ( ) ;
109
+ handles. push ( tokio:: task:: spawn ( async move {
110
+ let _permit = semaphore. acquire ( ) . await ?;
111
+ let issues = query
112
+ . query ( & repository, name == "proposed_fcp" , & gh)
113
+ . await ?;
114
+ Ok ( ( name, kind, issues) )
115
+ } ) ) ;
116
+ }
117
+ }
118
+ }
119
+
120
+ for handle in handles {
121
+ let ( name, kind, issues) = handle. await . unwrap ( ) ?;
122
+ match kind {
123
+ QueryKind :: List => {
124
+ results. entry ( name) . or_insert ( Vec :: new ( ) ) . extend ( issues) ;
125
+ }
126
+ QueryKind :: Count => {
127
+ let count = issues. len ( ) ;
128
+ let result = if let Some ( value) = context. get ( & name) {
129
+ value. as_u64 ( ) . unwrap ( ) + count as u64
130
+ } else {
131
+ count as u64
132
+ } ;
133
+
134
+ context. insert ( name, & result) ;
126
135
}
127
136
}
128
137
}
129
138
130
139
for ( name, issues) in & results {
131
- context. insert ( * name, issues) ;
140
+ context. insert ( name, issues) ;
132
141
}
133
142
134
- TEMPLATES
143
+ Ok ( TEMPLATES
135
144
. render ( & format ! ( "{}.tt" , self . name) , & context)
136
- . unwrap ( )
145
+ . unwrap ( ) )
137
146
}
138
147
}
0 commit comments