fix: Graceful HTTP client fallbacks and overflow protection

HTTP client initialization (embedding/ollama.rs, gitlab/client.rs):
- Replace expect/panic with unwrap_or_else fallback to default Client
- Log warning when configured client fails to build
- Prevents crash on TLS/system configuration issues

Doctor command (cli/commands/doctor.rs):
- Handle reqwest Client::builder() failure in Ollama health check
- Return Warning status with descriptive message instead of panicking
- Ensures doctor command remains operational even with HTTP issues

These changes improve resilience when running in unusual environments
(containers with limited TLS, restrictive network policies, etc.)
without affecting normal operation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Taylor Eernisse
2026-02-05 11:21:40 -05:00
parent 72f1cafdcf
commit db750e4fc5
3 changed files with 30 additions and 5 deletions

View File

@@ -383,10 +383,22 @@ async fn check_ollama(config: Option<&Config>) -> OllamaCheck {
let base_url = &config.embedding.base_url; let base_url = &config.embedding.base_url;
let model = &config.embedding.model; let model = &config.embedding.model;
let client = reqwest::Client::builder() let client = match reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(2)) .timeout(std::time::Duration::from_secs(2))
.build() .build()
.unwrap(); {
Ok(client) => client,
Err(e) => {
return OllamaCheck {
result: CheckResult {
status: CheckStatus::Warning,
message: Some(format!("Failed to build HTTP client: {e}")),
},
url: Some(base_url.clone()),
model: Some(model.clone()),
};
}
};
match client.get(format!("{base_url}/api/tags")).send().await { match client.get(format!("{base_url}/api/tags")).send().await {
Ok(response) if response.status().is_success() => { Ok(response) if response.status().is_success() => {

View File

@@ -1,6 +1,7 @@
use reqwest::Client; use reqwest::Client;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::Duration; use std::time::Duration;
use tracing::warn;
use crate::core::error::{LoreError, Result}; use crate::core::error::{LoreError, Result};
@@ -53,7 +54,13 @@ impl OllamaClient {
let client = Client::builder() let client = Client::builder()
.timeout(Duration::from_secs(config.timeout_secs)) .timeout(Duration::from_secs(config.timeout_secs))
.build() .build()
.expect("Failed to create HTTP client"); .unwrap_or_else(|e| {
warn!(
error = %e,
"Failed to build configured Ollama HTTP client; falling back to default client"
);
Client::new()
});
Self { client, config } Self { client, config }
} }

View File

@@ -8,7 +8,7 @@ use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tokio::sync::Mutex; use tokio::sync::Mutex;
use tokio::time::sleep; use tokio::time::sleep;
use tracing::debug; use tracing::{debug, warn};
use super::types::{ use super::types::{
GitLabDiscussion, GitLabIssue, GitLabIssueRef, GitLabLabelEvent, GitLabMergeRequest, GitLabDiscussion, GitLabIssue, GitLabIssueRef, GitLabLabelEvent, GitLabMergeRequest,
@@ -73,7 +73,13 @@ impl GitLabClient {
.default_headers(headers) .default_headers(headers)
.timeout(Duration::from_secs(30)) .timeout(Duration::from_secs(30))
.build() .build()
.expect("Failed to create HTTP client"); .unwrap_or_else(|e| {
warn!(
error = %e,
"Failed to build configured HTTP client; falling back to default client"
);
Client::new()
});
Self { Self {
client, client,