Skip to content

Commit 1b58c1a

Browse files
committed
feat: add --retries / PACT_BROKER_HTTP_RETRIES to pact_verifier_cli
Exposes broker HTTP retry count as --retries (env: PACT_BROKER_HTTP_RETRIES, default: 8) in pact_verifier_cli, matching the flag in pact-broker-cli. The retry count is threaded through VerificationOptions.broker_request_retries into the HALClient used for all broker calls: pact fetching (both legacy and dynamic) and publishing verification results. pact_verifier and cli bumped to 1.4.0 Signed-off-by: JP-Ellis <josh@jpellis.me>
1 parent 8f86cd9 commit 1b58c1a

11 files changed

Lines changed: 88 additions & 49 deletions

File tree

rust/Cargo.lock

Lines changed: 2 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/pact_ffi/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ pact_matching = { version = "~2.0.3", path = "../pact_matching" }
3333
pact_mock_server = "~2.2.1"
3434
pact_models = { version = "~1.3.10" }
3535
pact-plugin-driver = { version = "~0.7.5" }
36-
pact_verifier = { version = "~1.3.5", path = "../pact_verifier" }
36+
pact_verifier = { version = "~1.4.0", path = "../pact_verifier" }
3737
panic-message = "0.3.0"
3838
rand = "0.9.2"
3939
rand_regex = "0.18.1"

rust/pact_verifier/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pact_verifier"
3-
version = "1.3.6"
3+
version = "1.4.0"
44
authors = ["Ronald Holshausen <ronald.holshausen@gmail.com>"]
55
edition = "2024"
66
description = "Pact-Rust support library that implements provider verification functions"

rust/pact_verifier/src/callback_executors.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ pub struct HttpRequestProviderStateExecutor {
9999
/// If state change request data should be sent in the body (true) or as query parameters (false)
100100
pub state_change_body: bool,
101101
/// Number of times to retry the provider state request, zero means none
102-
pub reties: u8
102+
pub retries: u8
103103
}
104104

105105
impl Default for HttpRequestProviderStateExecutor {
@@ -109,7 +109,7 @@ impl Default for HttpRequestProviderStateExecutor {
109109
state_change_url: None,
110110
state_change_teardown: false,
111111
state_change_body: true,
112-
reties: 3
112+
retries: 8
113113
}
114114
}
115115
}
@@ -153,7 +153,7 @@ impl ProviderStateExecutor for HttpRequestProviderStateExecutor {
153153
}
154154
state_change_request.query = Some(query);
155155
}
156-
make_state_change_request(client.unwrap_or(&reqwest::Client::default()), &state_change_url, &state_change_request, self.reties).await
156+
make_state_change_request(client.unwrap_or(&reqwest::Client::default()), &state_change_url, &state_change_request, self.retries).await
157157
.map_err(|err| ProviderStateError { description: err.to_string(), interaction_id }.into())
158158
},
159159
None => {

rust/pact_verifier/src/lib.rs

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -994,7 +994,10 @@ pub struct VerificationOptions<F> where F: RequestFilterExecutor {
994994
/// Only execute the interactions that failed on the previous verifier run
995995
pub run_last_failed_only: bool,
996996
/// If redirects should be automatically followed
997-
pub follow_redirects: bool
997+
pub follow_redirects: bool,
998+
/// Number of times to retry failed HTTP requests to the Pact Broker
999+
/// (retries on 5xx, 408, and 429). Default is 8.
1000+
pub broker_request_retries: u8,
9981001
}
9991002

10001003
impl <F: RequestFilterExecutor> Default for VerificationOptions<F> {
@@ -1008,7 +1011,8 @@ impl <F: RequestFilterExecutor> Default for VerificationOptions<F> {
10081011
no_pacts_is_error: true,
10091012
exit_on_first_failure: false,
10101013
run_last_failed_only: false,
1011-
follow_redirects: true
1014+
follow_redirects: true,
1015+
broker_request_retries: 8,
10121016
}
10131017
}
10141018
}
@@ -1067,7 +1071,7 @@ pub async fn verify_provider_async<F: RequestFilterExecutor, S: ProviderStateExe
10671071
) -> anyhow::Result<VerificationExecutionResult> {
10681072
pact_matching::matchingrules::configure_core_catalogue();
10691073
async {
1070-
let pact_results = fetch_pacts(source, consumers, &provider_info).await;
1074+
let pact_results = fetch_pacts(source, consumers, &provider_info, verification_options.broker_request_retries).await;
10711075

10721076
let mut total_results = 0;
10731077
let mut pending_errors: Vec<(String, MismatchResult)> = vec![];
@@ -1167,7 +1171,7 @@ pub async fn verify_provider_async<F: RequestFilterExecutor, S: ProviderStateExe
11671171
}
11681172

11691173
if let Some(publish) = publish_options {
1170-
publish_result(results.as_slice(), &pact_source, &publish, metrics_data.as_ref()).await;
1174+
publish_result(results.as_slice(), &pact_source, &publish, metrics_data.as_ref(), verification_options.broker_request_retries).await;
11711175

11721176
if !errors.is_empty() || !pending_errors.is_empty() {
11731177
process_notices(&context, VERIFICATION_NOTICE_AFTER_ERROR_RESULT_AND_PUBLISH, &mut verification_result);
@@ -1296,7 +1300,8 @@ pub fn interaction_mismatch_output(
12961300
#[tracing::instrument(level = "trace")]
12971301
async fn fetch_pact(
12981302
source: PactSource,
1299-
provider: &ProviderInfo
1303+
provider: &ProviderInfo,
1304+
retries: u8,
13001305
) -> Vec<anyhow::Result<(Box<dyn Pact + Send + Sync + RefUnwindSafe>, Option<PactVerificationContext>, PactSource, Duration)>> {
13011306
trace!("fetch_pact(source={})", source);
13021307

@@ -1344,7 +1349,8 @@ async fn fetch_pact(
13441349
let result = timeit_async(pact_broker::fetch_pacts_from_broker(
13451350
broker_url.as_str(),
13461351
provider_name.as_str(),
1347-
auth.clone()
1352+
auth.clone(),
1353+
retries,
13481354
)).await;
13491355

13501356
match result {
@@ -1387,7 +1393,8 @@ async fn fetch_pact(
13871393
provider_tags.clone(),
13881394
provider_branch.clone(),
13891395
selectors.clone(),
1390-
auth.clone()
1396+
auth.clone(),
1397+
retries,
13911398
)).await;
13921399

13931400
match result {
@@ -1464,13 +1471,14 @@ fn is_pact_broker_source(links: &Vec<Link>) -> bool {
14641471
async fn fetch_pacts(
14651472
source: Vec<PactSource>,
14661473
consumers: Vec<String>,
1467-
provider: &ProviderInfo
1474+
provider: &ProviderInfo,
1475+
retries: u8,
14681476
) -> Vec<anyhow::Result<(Box<dyn Pact + Send + Sync + RefUnwindSafe>, Option<PactVerificationContext>, PactSource, Duration)>> {
14691477
trace!("fetch_pacts(source={}, consumers={:?})", source.iter().map(|s| s.to_string()).join(", "), consumers);
14701478

14711479
futures::stream::iter(source)
14721480
.then(|pact_source| async {
1473-
futures::stream::iter(fetch_pact(pact_source, provider).await)
1481+
futures::stream::iter(fetch_pact(pact_source, provider, retries).await)
14741482
})
14751483
.flatten()
14761484
.filter(|res| futures::future::ready(filter_consumers(&consumers, res)))
@@ -1675,18 +1683,19 @@ async fn publish_result(
16751683
results: &[VerificationInteractionResult],
16761684
source: &PactSource,
16771685
options: &PublishOptions,
1678-
metrics_data: Option<&VerificationMetrics>
1686+
metrics_data: Option<&VerificationMetrics>,
1687+
retries: u8,
16791688
) {
16801689
let publish_result = match source {
16811690
PactSource::BrokerUrl(_, broker_url, auth, links) => {
16821691
publish_to_broker(results, source, &options.build_url, &options.provider_tags,
16831692
&options.provider_branch, &options.provider_version, links.clone(), broker_url.clone(),
1684-
auth.clone(), metrics_data
1693+
auth.clone(), metrics_data, retries
16851694
).await
16861695
}
16871696
PactSource::BrokerWithDynamicConfiguration { broker_url, auth, links, provider_branch, provider_tags, .. } => {
16881697
publish_to_broker(results, source, &options.build_url, &provider_tags, &provider_branch,
1689-
&options.provider_version, links.clone(), broker_url.clone(), auth.clone(), metrics_data
1698+
&options.provider_version, links.clone(), broker_url.clone(), auth.clone(), metrics_data, retries
16901699
).await
16911700
}
16921701
_ => {
@@ -1710,7 +1719,8 @@ async fn publish_to_broker(
17101719
links: Vec<Link>,
17111720
broker_url: String,
17121721
auth: Option<HttpAuth>,
1713-
metrics_data: Option<&VerificationMetrics>
1722+
metrics_data: Option<&VerificationMetrics>,
1723+
retries: u8,
17141724
) -> Result<Value, pact_broker::PactBrokerError> {
17151725
info!("Publishing verification results back to the Pact Broker");
17161726
let result = if results.iter().all(|r| r.result.is_ok()) {
@@ -1733,7 +1743,8 @@ async fn publish_to_broker(
17331743
build_url.clone(),
17341744
provider_tags.clone(),
17351745
provider_branch.clone(),
1736-
metrics_data
1746+
metrics_data,
1747+
retries,
17371748
).await
17381749
}
17391750

rust/pact_verifier/src/pact_broker.rs

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ impl HALClientBuilder {
203203
HALClientBuilder {
204204
url: "".to_string(),
205205
auth: None,
206-
retries: 3,
206+
retries: 8,
207207
client: None
208208
}
209209
}
@@ -215,7 +215,7 @@ impl HALClientBuilder {
215215
self
216216
}
217217

218-
/// Sets the number of retries on certain HTTP errors (5xx, 408, 429). Default is 3.
218+
/// Sets the number of retries on certain HTTP errors (5xx, 408, 429). Default is 8.
219219
pub fn with_retries(&mut self, retries: u8) -> &mut Self {
220220
self.retries = retries;
221221
self
@@ -634,12 +634,13 @@ fn links_from_json(json: &Value) -> Vec<Link> {
634634
pub async fn fetch_pacts_from_broker(
635635
broker_url: &str,
636636
provider_name: &str,
637-
auth: Option<HttpAuth>
637+
auth: Option<HttpAuth>,
638+
retries: u8,
638639
) -> anyhow::Result<Vec<anyhow::Result<(Box<dyn Pact + Send + Sync + RefUnwindSafe>, Option<PactVerificationContext>, Vec<Link>)>>> {
639640
trace!("fetch_pacts_from_broker(broker_url='{}', provider_name='{}', auth={})", broker_url,
640641
provider_name, auth.clone().unwrap_or_default());
641642

642-
let mut hal_client = HALClientBuilder::builder().with_url(broker_url, auth).build();
643+
let mut hal_client = HALClientBuilder::builder().with_url(broker_url, auth).with_retries(retries).build();
643644
let template_values = hashmap!{ "provider".to_string() => provider_name.to_string() };
644645

645646
hal_client = hal_client.navigate("pb:latest-provider-pacts", &template_values)
@@ -705,14 +706,15 @@ pub async fn fetch_pacts_dynamically_from_broker(
705706
provider_tags: Vec<String>,
706707
provider_branch: Option<String>,
707708
consumer_version_selectors: Vec<ConsumerVersionSelector>,
708-
auth: Option<HttpAuth>
709+
auth: Option<HttpAuth>,
710+
retries: u8,
709711
) -> anyhow::Result<Vec<Result<(Box<dyn Pact + Send + Sync + RefUnwindSafe>, Option<PactVerificationContext>, Vec<Link>), PactBrokerError>>> {
710712
trace!("fetch_pacts_dynamically_from_broker(broker_url='{}', provider_name='{}', pending={}, \
711713
include_wip_pacts_since={:?}, provider_tags: {:?}, consumer_version_selectors: {:?}, auth={})",
712714
broker_url, provider_name, pending, include_wip_pacts_since, provider_tags,
713715
consumer_version_selectors, auth.clone().unwrap_or_default());
714716

715-
let mut hal_client = HALClientBuilder::builder().with_url(broker_url, auth).build();
717+
let mut hal_client = HALClientBuilder::builder().with_url(broker_url, auth).with_retries(retries).build();
716718
let template_values = hashmap!{ "provider".to_string() => provider_name.clone() };
717719

718720
hal_client = hal_client.navigate("pb:provider-pacts-for-verification", &template_values)
@@ -874,9 +876,10 @@ pub async fn publish_verification_results(
874876
build_url: Option<String>,
875877
provider_tags: Vec<String>,
876878
branch: Option<String>,
877-
metrics_data: Option<&VerificationMetrics>
879+
metrics_data: Option<&VerificationMetrics>,
880+
retries: u8,
878881
) -> Result<serde_json::Value, PactBrokerError> {
879-
let hal_client = HALClientBuilder::builder().with_url(broker_url, auth.clone()).build();
882+
let hal_client = HALClientBuilder::builder().with_url(broker_url, auth.clone()).with_retries(retries).build();
880883

881884
if branch.is_some() {
882885
publish_provider_branch(&hal_client, &links, &branch.unwrap(), &version).await?;
@@ -1380,7 +1383,7 @@ mod tests {
13801383
})
13811384
.start_mock_server(None, None);
13821385

1383-
let client = HALClientBuilder::builder().with_url(pact_broker.url(), None).build();
1386+
let client = HALClientBuilder::builder().with_url(pact_broker.url(), None).with_retries(3).build();
13841387
let expected_requests = client.retries as usize;
13851388
let result = client.fetch("/").await;
13861389
expect!(result).to(be_err());
@@ -1431,7 +1434,7 @@ mod tests {
14311434
})
14321435
.start_mock_server(None, None);
14331436

1434-
let client = HALClientBuilder::builder().with_url(pact_broker.url(), None).build();
1437+
let client = HALClientBuilder::builder().with_url(pact_broker.url(), None).with_retries(3).build();
14351438
let expected_requests = client.retries as usize;
14361439
let result = client.post_json(pact_broker.url().as_str(), "{}").await;
14371440

@@ -1452,7 +1455,7 @@ mod tests {
14521455
})
14531456
.start_mock_server(None, None);
14541457

1455-
let client = HALClientBuilder::builder().with_url(pact_broker.url(), None).build();
1458+
let client = HALClientBuilder::builder().with_url(pact_broker.url(), None).with_retries(3).build();
14561459
let expected_requests = client.retries as usize;
14571460
let result = client.put_json(pact_broker.url().as_str(), "{}").await;
14581461

@@ -1741,7 +1744,7 @@ mod tests {
17411744
.start_mock_server(None, Some(MockServerConfig::with_keep_alive(true)));
17421745

17431746
let result = fetch_pacts_from_broker(pact_broker.url().as_str(),
1744-
"sad_provider", None).await;
1747+
"sad_provider", None, 3).await;
17451748
match result {
17461749
Ok(_) => {
17471750
panic!("Expected an error result, but got OK");
@@ -1829,7 +1832,7 @@ mod tests {
18291832
.start_mock_server(None, Some(MockServerConfig::with_keep_alive(true)));
18301833

18311834
let result = fetch_pacts_from_broker(pact_broker.url().as_str(),
1832-
"happy_provider", None).await;
1835+
"happy_provider", None, 3).await;
18331836
match &result {
18341837
Ok(_) => (),
18351838
Err(err) => panic!("Expected an Ok result, got a error {}", err)
@@ -1971,7 +1974,7 @@ mod tests {
19711974
matching_branch: None,
19721975
environment: None,
19731976
fallback_branch: None,
1974-
}), None).await;
1977+
}), None, 3).await;
19751978

19761979
match &result {
19771980
Ok(_) => (),
@@ -2071,7 +2074,7 @@ mod tests {
20712074
matching_branch: None,
20722075
environment: None,
20732076
fallback_branch: None,
2074-
}), None).await;
2077+
}), None, 3).await;
20752078

20762079
match result {
20772080
Ok(_) => {
@@ -2174,7 +2177,8 @@ mod tests {
21742177
environment: None,
21752178
fallback_branch: None,
21762179
}),
2177-
None
2180+
None,
2181+
3,
21782182
).await;
21792183

21802184
match result {

0 commit comments

Comments
 (0)