feat(server): add OXICLOUD_REUSE_PORT env parameter (false by default)
initially server was accepting multiple instances on same port (Linux and MacOS only)
this can create issues during development (if a dev forget another running instance...)
Add OXICLOUD_REUSE_PORT variable to activate it, so only admins knowing this feature can activate itt
(permits multiple instance + let the OS schedduler to decide which process will handle a request)
if not enabled, other instance will receive exit with a:
`Error: Os { code: 48, kind: AddrInUse, message: "Address already in use" }`
This commit is contained in:
+2
-1
@@ -9,9 +9,10 @@ Most runtime variables use the `OXICLOUD_` prefix. A few build-time or allocator
|
|||||||
| `OXICLOUD_STORAGE_PATH` | `./storage` | Root storage directory |
|
| `OXICLOUD_STORAGE_PATH` | `./storage` | Root storage directory |
|
||||||
| `OXICLOUD_STATIC_PATH` | `./static` | Static files directory |
|
| `OXICLOUD_STATIC_PATH` | `./static` | Static files directory |
|
||||||
| `OXICLOUD_SERVER_PORT` | `8086` | Server port |
|
| `OXICLOUD_SERVER_PORT` | `8086` | Server port |
|
||||||
| `OXICLOUD_SERVER_HOST` | `127.0.0.1` | Server bind addressi (IPv4 or IPv6 allowed) |
|
| `OXICLOUD_SERVER_HOST` | `127.0.0.1` | Server bind address (IPv4 or IPv6 allowed) |
|
||||||
| `OXICLOUD_BASE_URL` | (auto) | Public base URL for share links; defaults to `http://{host}:{port}` |
|
| `OXICLOUD_BASE_URL` | (auto) | Public base URL for share links; defaults to `http://{host}:{port}` |
|
||||||
| `OXICLOUD_MAX_UPLOAD_SIZE` | `10737418240` | Maximum upload size in bytes (10 GB on 64-bit, 1 GB on 32-bit) |
|
| `OXICLOUD_MAX_UPLOAD_SIZE` | `10737418240` | Maximum upload size in bytes (10 GB on 64-bit, 1 GB on 32-bit) |
|
||||||
|
| `OXICLOUD_REUSE_PORT` | `false` | Enable `SO_REUSEPORT` so multiple processes can share the same port. **Disabled by default** — a second accidental instance will fail with "address already in use". Enable only for deliberate multi-worker setups (process supervisor, rolling restart). Not supported on Windows. |
|
||||||
|
|
||||||
## Database
|
## Database
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,14 @@ OXICLOUD_SERVER_HOST=127.0.0.1
|
|||||||
# Maximum upload size in bytes (default: 10 GB on 64-bit)
|
# Maximum upload size in bytes (default: 10 GB on 64-bit)
|
||||||
#OXICLOUD_MAX_UPLOAD_SIZE=10737418240
|
#OXICLOUD_MAX_UPLOAD_SIZE=10737418240
|
||||||
|
|
||||||
|
# Allow multiple processes to bind to the same port (SO_REUSEPORT).
|
||||||
|
# DISABLED by default — leaving this off means a second accidental instance
|
||||||
|
# will fail immediately with "address already in use", which is the safe behaviour.
|
||||||
|
# Enable ONLY when you deliberately run several worker processes in parallel
|
||||||
|
# (e.g. behind a process supervisor or during a zero-downtime rolling restart).
|
||||||
|
# Not supported on Windows.
|
||||||
|
#OXICLOUD_REUSE_PORT=false
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# DATABASE CONFIGURATION
|
# DATABASE CONFIGURATION
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|||||||
+25
-4
@@ -77,7 +77,7 @@ fn parse_addr(host: &str, port: u16) -> Result<SocketAddr, String> {
|
|||||||
.map_err(|e| format!("Invalid address '{}': {}", addr_str, e))
|
.map_err(|e| format!("Invalid address '{}': {}", addr_str, e))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_socket(addr: &SocketAddr) -> std::io::Result<Socket> {
|
fn make_socket(addr: &SocketAddr, reuse_port: bool) -> std::io::Result<Socket> {
|
||||||
let domain = if addr.is_ipv6() {
|
let domain = if addr.is_ipv6() {
|
||||||
Domain::IPV6
|
Domain::IPV6
|
||||||
} else {
|
} else {
|
||||||
@@ -85,9 +85,14 @@ fn make_socket(addr: &SocketAddr) -> std::io::Result<Socket> {
|
|||||||
};
|
};
|
||||||
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
|
let socket = Socket::new(domain, Type::STREAM, Some(Protocol::TCP))?;
|
||||||
socket.set_reuse_address(true)?;
|
socket.set_reuse_address(true)?;
|
||||||
// Allow multiple workers on the same port (future-ready)
|
// SO_REUSEPORT: opt-in only — must be explicitly enabled via
|
||||||
|
// OXICLOUD_REUSE_PORT=true. Disabled by default so that accidentally
|
||||||
|
// starting a second instance fails fast with "address already in use"
|
||||||
|
// rather than silently sharing the port.
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
socket.set_reuse_port(true)?;
|
if reuse_port {
|
||||||
|
socket.set_reuse_port(true)?;
|
||||||
|
}
|
||||||
// Disable Nagle's algorithm — send small responses (JSON, PROPFIND)
|
// Disable Nagle's algorithm — send small responses (JSON, PROPFIND)
|
||||||
// immediately instead of waiting up to 40ms for coalescing.
|
// immediately instead of waiting up to 40ms for coalescing.
|
||||||
socket.set_tcp_nodelay(true)?;
|
socket.set_tcp_nodelay(true)?;
|
||||||
@@ -566,9 +571,25 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
// Start server — tuned socket for low-latency responses
|
// Start server — tuned socket for low-latency responses
|
||||||
// TODO: suport multiple addresses ?
|
// TODO: suport multiple addresses ?
|
||||||
let addr = parse_addr(&config.server_host, config.server_port)?;
|
let addr = parse_addr(&config.server_host, config.server_port)?;
|
||||||
|
|
||||||
|
// SO_REUSEPORT: disabled by default — a second instance on the same port
|
||||||
|
// fails loudly instead of silently sharing the socket. Set
|
||||||
|
// OXICLOUD_REUSE_PORT=true only when you deliberately run multiple
|
||||||
|
// workers (e.g. behind a process supervisor or during a rolling restart).
|
||||||
|
let reuse_port = std::env::var("OXICLOUD_REUSE_PORT")
|
||||||
|
.map(|v| v.eq_ignore_ascii_case("true") || v == "1")
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if reuse_port {
|
||||||
|
tracing::warn!(
|
||||||
|
"OXICLOUD_REUSE_PORT is enabled — multiple processes may bind to port {}",
|
||||||
|
config.server_port
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
tracing::info!("Starting OxiCloud server on http://{}", addr);
|
tracing::info!("Starting OxiCloud server on http://{}", addr);
|
||||||
|
|
||||||
let socket = make_socket(&addr)?;
|
let socket = make_socket(&addr, reuse_port)?;
|
||||||
|
|
||||||
let listener = tokio::net::TcpListener::from_std(socket.into())?;
|
let listener = tokio::net::TcpListener::from_std(socket.into())?;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user