@@ -28,16 +28,22 @@ pub use standalone::new_standalone_scheduler;
28
28
#[ cfg( test) ]
29
29
pub mod test_utils;
30
30
31
+ // include the generated protobuf source as a submodule
32
+ #[ allow( clippy:: all) ]
33
+ pub mod externalscaler {
34
+ include ! ( concat!( env!( "OUT_DIR" ) , "/externalscaler.rs" ) ) ;
35
+ }
36
+
31
37
use std:: { convert:: TryInto , sync:: Arc } ;
32
38
use std:: { fmt, net:: IpAddr } ;
33
39
34
40
use ballista_core:: serde:: protobuf:: {
35
41
execute_query_params:: Query , executor_registration:: OptionalHost , job_status,
36
- scheduler_grpc_server:: SchedulerGrpc , ExecuteQueryParams , ExecuteQueryResult ,
37
- FailedJob , FilePartitionMetadata , FileType , GetFileMetadataParams ,
38
- GetFileMetadataResult , GetJobStatusParams , GetJobStatusResult , JobStatus ,
39
- PartitionId , PollWorkParams , PollWorkResult , QueuedJob , RunningJob , TaskDefinition ,
40
- TaskStatus ,
42
+ scheduler_grpc_server:: SchedulerGrpc , task_status , ExecuteQueryParams ,
43
+ ExecuteQueryResult , FailedJob , FilePartitionMetadata , FileType ,
44
+ GetFileMetadataParams , GetFileMetadataResult , GetJobStatusParams , GetJobStatusResult ,
45
+ JobStatus , PartitionId , PollWorkParams , PollWorkResult , QueuedJob , RunningJob ,
46
+ TaskDefinition , TaskStatus ,
41
47
} ;
42
48
use ballista_core:: serde:: scheduler:: ExecutorMeta ;
43
49
@@ -62,6 +68,10 @@ impl parse_arg::ParseArgFromStr for ConfigBackend {
62
68
}
63
69
}
64
70
71
+ use crate :: externalscaler:: {
72
+ external_scaler_server:: ExternalScaler , GetMetricSpecResponse , GetMetricsRequest ,
73
+ GetMetricsResponse , IsActiveResponse , MetricSpec , MetricValue , ScaledObjectRef ,
74
+ } ;
65
75
use crate :: planner:: DistributedPlanner ;
66
76
67
77
use log:: { debug, error, info, warn} ;
@@ -103,6 +113,55 @@ impl SchedulerServer {
103
113
}
104
114
}
105
115
116
+ const INFLIGHT_TASKS_METRIC_NAME : & str = "inflight_tasks" ;
117
+
118
+ #[ tonic:: async_trait]
119
+ impl ExternalScaler for SchedulerServer {
120
+ async fn is_active (
121
+ & self ,
122
+ _request : Request < ScaledObjectRef > ,
123
+ ) -> Result < Response < IsActiveResponse > , tonic:: Status > {
124
+ let tasks = self . state . get_all_tasks ( ) . await . map_err ( |e| {
125
+ let msg = format ! ( "Error reading tasks: {}" , e) ;
126
+ error ! ( "{}" , msg) ;
127
+ tonic:: Status :: internal ( msg)
128
+ } ) ?;
129
+ let result = tasks. iter ( ) . any ( |( _key, task) | {
130
+ !matches ! (
131
+ task. status,
132
+ Some ( task_status:: Status :: Completed ( _) )
133
+ | Some ( task_status:: Status :: Failed ( _) )
134
+ )
135
+ } ) ;
136
+ debug ! ( "Are there active tasks? {}" , result) ;
137
+ Ok ( Response :: new ( IsActiveResponse { result } ) )
138
+ }
139
+
140
+ async fn get_metric_spec (
141
+ & self ,
142
+ _request : Request < ScaledObjectRef > ,
143
+ ) -> Result < Response < GetMetricSpecResponse > , tonic:: Status > {
144
+ Ok ( Response :: new ( GetMetricSpecResponse {
145
+ metric_specs : vec ! [ MetricSpec {
146
+ metric_name: INFLIGHT_TASKS_METRIC_NAME . to_string( ) ,
147
+ target_size: 1 ,
148
+ } ] ,
149
+ } ) )
150
+ }
151
+
152
+ async fn get_metrics (
153
+ & self ,
154
+ _request : Request < GetMetricsRequest > ,
155
+ ) -> Result < Response < GetMetricsResponse > , tonic:: Status > {
156
+ Ok ( Response :: new ( GetMetricsResponse {
157
+ metric_values : vec ! [ MetricValue {
158
+ metric_name: INFLIGHT_TASKS_METRIC_NAME . to_string( ) ,
159
+ metric_value: 10000000 , // A very high number to saturate the HPA
160
+ } ] ,
161
+ } ) )
162
+ }
163
+ }
164
+
106
165
#[ tonic:: async_trait]
107
166
impl SchedulerGrpc for SchedulerServer {
108
167
async fn poll_work (
0 commit comments