Skip to content

Commit 60566f2

Browse files
committed
bugfix batch
1 parent 50440e4 commit 60566f2

File tree

5 files changed

+79
-24
lines changed

5 files changed

+79
-24
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ members = [
1818
]
1919

2020
[workspace.package]
21-
version = "0.3.16"
21+
version = "0.3.17"
2222
edition = "2021"
2323
license = "Apache-2.0 OR MIT"
2424
repository = "https://github.com/RightNow-AI/openfang"
@@ -122,6 +122,9 @@ argon2 = "0.5"
122122
# Lightweight regex
123123
regex-lite = "0.1"
124124

125+
# Socket options (SO_REUSEADDR)
126+
socket2 = "0.5"
127+
125128
# Zip archive extraction
126129
zip = { version = "2", default-features = false, features = ["deflate"] }
127130

crates/openfang-api/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ governor = { workspace = true }
3333
tokio-stream = { workspace = true }
3434
subtle = { workspace = true }
3535
base64 = { workspace = true }
36+
socket2 = { workspace = true }
3637

3738
[dev-dependencies]
3839
tokio-test = { workspace = true }

crates/openfang-api/src/server.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -740,7 +740,8 @@ pub async fn run_daemon(
740740
if info_path.exists() {
741741
if let Ok(existing) = std::fs::read_to_string(info_path) {
742742
if let Ok(info) = serde_json::from_str::<DaemonInfo>(&existing) {
743-
if is_process_alive(info.pid) {
743+
// PID alive AND the health endpoint responds → truly running
744+
if is_process_alive(info.pid) && is_daemon_responding(&info.listen_addr) {
744745
return Err(format!(
745746
"Another daemon (PID {}) is already running at {}",
746747
info.pid, info.listen_addr
@@ -749,7 +750,8 @@ pub async fn run_daemon(
749750
}
750751
}
751752
}
752-
// Stale PID file, remove it
753+
// Stale PID file (process dead or different process reused PID), remove it
754+
info!("Removing stale daemon info file");
753755
let _ = std::fs::remove_file(info_path);
754756
}
755757

@@ -771,7 +773,22 @@ pub async fn run_daemon(
771773
info!("WebChat UI available at http://{addr}/",);
772774
info!("WebSocket endpoint: ws://{addr}/api/agents/{{id}}/ws",);
773775

774-
let listener = tokio::net::TcpListener::bind(addr).await?;
776+
// Use SO_REUSEADDR to allow binding immediately after reboot (avoids TIME_WAIT).
777+
let socket = socket2::Socket::new(
778+
if addr.is_ipv4() {
779+
socket2::Domain::IPV4
780+
} else {
781+
socket2::Domain::IPV6
782+
},
783+
socket2::Type::STREAM,
784+
None,
785+
)?;
786+
socket.set_reuse_address(true)?;
787+
socket.set_nonblocking(true)?;
788+
socket.bind(&addr.into())?;
789+
socket.listen(1024)?;
790+
let listener =
791+
tokio::net::TcpListener::from_std(std::net::TcpListener::from(socket))?;
775792

776793
// Run server with graceful shutdown.
777794
// SECURITY: `into_make_service_with_connect_info` injects the peer
@@ -891,3 +908,26 @@ fn is_process_alive(pid: u32) -> bool {
891908
false
892909
}
893910
}
911+
912+
/// Check if an OpenFang daemon is actually responding at the given address.
913+
/// This avoids false positives where a different process reused the same PID
914+
/// after a system reboot.
915+
fn is_daemon_responding(addr: &str) -> bool {
916+
// Quick TCP connect check — don't make a full HTTP request to avoid delays
917+
let addr_only = addr
918+
.strip_prefix("http://")
919+
.or_else(|| addr.strip_prefix("https://"))
920+
.unwrap_or(addr);
921+
if let Ok(sock_addr) = addr_only.parse::<std::net::SocketAddr>() {
922+
std::net::TcpStream::connect_timeout(
923+
&sock_addr,
924+
std::time::Duration::from_millis(500),
925+
)
926+
.is_ok()
927+
} else {
928+
// Fallback: try connecting to hostname
929+
std::net::TcpStream::connect(addr_only)
930+
.map(|_| true)
931+
.unwrap_or(false)
932+
}
933+
}

crates/openfang-runtime/src/model_catalog.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3080,7 +3080,7 @@ mod tests {
30803080
#[test]
30813081
fn test_catalog_has_providers() {
30823082
let catalog = ModelCatalog::new();
3083-
assert_eq!(catalog.list_providers().len(), 31);
3083+
assert_eq!(catalog.list_providers().len(), 33);
30843084
}
30853085

30863086
#[test]

0 commit comments

Comments
 (0)