@@ -80,6 +80,7 @@ pub struct ConsensusAdapterMetrics {
80
80
pub sequencing_in_flight_submissions : IntGauge ,
81
81
pub sequencing_estimated_latency : IntGauge ,
82
82
pub sequencing_resubmission_interval_ms : IntGauge ,
83
+ pub sequencing_best_effort_timeout : IntCounterVec ,
83
84
}
84
85
85
86
impl ConsensusAdapterMetrics {
@@ -188,6 +189,12 @@ impl ConsensusAdapterMetrics {
188
189
SEQUENCING_CERTIFICATE_POSITION_BUCKETS . to_vec( ) ,
189
190
registry,
190
191
) . unwrap ( ) ,
192
+ sequencing_best_effort_timeout : register_int_counter_vec_with_registry ! (
193
+ "sequencing_best_effort_timeout" ,
194
+ "The number of times the best effort submission has timed out." ,
195
+ & [ "tx_type" ] ,
196
+ registry,
197
+ ) . unwrap ( ) ,
191
198
}
192
199
}
193
200
@@ -210,6 +217,13 @@ pub trait SubmitToConsensus: Sync + Send + 'static {
210
217
transactions : & [ ConsensusTransaction ] ,
211
218
epoch_store : & Arc < AuthorityPerEpochStore > ,
212
219
) -> SuiResult ;
220
+
221
+ fn submit_best_effort (
222
+ & self ,
223
+ transaction : & ConsensusTransaction ,
224
+ epoch_store : & Arc < AuthorityPerEpochStore > ,
225
+ timeout : Duration ,
226
+ ) -> SuiResult ;
213
227
}
214
228
215
229
#[ mockall:: automock]
@@ -249,7 +263,7 @@ pub struct ConsensusAdapter {
249
263
/// A structure to register metrics
250
264
metrics : ConsensusAdapterMetrics ,
251
265
/// Semaphore limiting parallel submissions to consensus
252
- submit_semaphore : Semaphore ,
266
+ submit_semaphore : Arc < Semaphore > ,
253
267
latency_observer : LatencyObserver ,
254
268
protocol_config : ProtocolConfig ,
255
269
}
@@ -300,7 +314,7 @@ impl ConsensusAdapter {
300
314
connection_monitor_status,
301
315
low_scoring_authorities,
302
316
metrics,
303
- submit_semaphore : Semaphore :: new ( max_pending_local_submissions) ,
317
+ submit_semaphore : Arc :: new ( Semaphore :: new ( max_pending_local_submissions) ) ,
304
318
latency_observer : LatencyObserver :: new ( ) ,
305
319
consensus_throughput_profiler : ArcSwapOption :: empty ( ) ,
306
320
protocol_config,
@@ -1287,6 +1301,55 @@ impl SubmitToConsensus for Arc<ConsensusAdapter> {
1287
1301
self . submit_batch ( transactions, None , epoch_store)
1288
1302
. map ( |_| ( ) )
1289
1303
}
1304
+
1305
+ fn submit_best_effort (
1306
+ & self ,
1307
+ transaction : & ConsensusTransaction ,
1308
+ epoch_store : & Arc < AuthorityPerEpochStore > ,
1309
+ // timeout is required, or the spawned task can run forever
1310
+ timeout : Duration ,
1311
+ ) -> SuiResult {
1312
+ let permit = match self . submit_semaphore . clone ( ) . try_acquire_owned ( ) {
1313
+ Ok ( permit) => permit,
1314
+ Err ( _) => {
1315
+ return Err ( SuiError :: TooManyTransactionsPendingConsensus ) ;
1316
+ }
1317
+ } ;
1318
+
1319
+ let _in_flight_submission_guard =
1320
+ GaugeGuard :: acquire ( & self . metrics . sequencing_in_flight_submissions ) ;
1321
+
1322
+ let key = SequencedConsensusTransactionKey :: External ( transaction. key ( ) ) ;
1323
+ let tx_type = classify ( transaction) ;
1324
+
1325
+ let async_stage = {
1326
+ let transaction = transaction. clone ( ) ;
1327
+ let epoch_store = epoch_store. clone ( ) ;
1328
+ let this = self . clone ( ) ;
1329
+
1330
+ async move {
1331
+ let _permit = permit; // Hold permit for lifetime of task
1332
+
1333
+ let result = tokio:: time:: timeout (
1334
+ timeout,
1335
+ this. submit_inner ( & [ transaction] , & epoch_store, & [ key] , tx_type, false ) ,
1336
+ )
1337
+ . await ;
1338
+
1339
+ if let Err ( e) = result {
1340
+ warn ! ( "Consensus submission timed out: {e:?}" ) ;
1341
+ this. metrics
1342
+ . sequencing_best_effort_timeout
1343
+ . with_label_values ( & [ tx_type] )
1344
+ . inc ( ) ;
1345
+ }
1346
+ }
1347
+ } ;
1348
+
1349
+ let epoch_store = epoch_store. clone ( ) ;
1350
+ spawn_monitored_task ! ( epoch_store. within_alive_epoch( async_stage) ) ;
1351
+ Ok ( ( ) )
1352
+ }
1290
1353
}
1291
1354
1292
1355
pub fn position_submit_certificate (
0 commit comments