hyperactor_mesh/
config.rs

1/*
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * LICENSE file in the root directory of this source tree.
7 */
8
9//! Configuration for Hyperactor Mesh.
10//!
11//! This module provides hyperactor_mesh-specific configuration attributes that extend
12//! the base hyperactor configuration system.
13
14use std::net::SocketAddr;
15use std::time::Duration;
16
17use hyperactor_config::AttrValue;
18use hyperactor_config::CONFIG;
19use hyperactor_config::ConfigAttr;
20use hyperactor_config::attrs::declare_attrs;
21use serde::Deserialize;
22use serde::Serialize;
23use typeuri::Named;
24
25/// A socket address string usable as a `declare_attrs!` default.
26///
27/// Follows the [`hyperactor::config::Pem`] pattern: the `Static`
28/// variant holds a `&'static str` so it can appear in a `static`
29/// item, while `Value` holds a runtime `String` from environment
30/// variables or Python `configure()`.
31#[derive(Clone, Debug, Serialize, Named)]
32#[named("hyperactor_mesh::config::SocketAddrStr")]
33pub enum SocketAddrStr {
34    /// Compile-time default (const-constructible).
35    Static(&'static str),
36    /// Runtime value from env / config.
37    Value(String),
38}
39
40impl<'de> Deserialize<'de> for SocketAddrStr {
41    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
42    where
43        D: serde::Deserializer<'de>,
44    {
45        #[derive(Deserialize)]
46        enum Helper {
47            Static(String),
48            Value(String),
49        }
50        match Helper::deserialize(deserializer)? {
51            Helper::Static(s) | Helper::Value(s) => Ok(SocketAddrStr::Value(s)),
52        }
53    }
54}
55
56impl From<String> for SocketAddrStr {
57    fn from(s: String) -> Self {
58        SocketAddrStr::Value(s)
59    }
60}
61
62impl From<SocketAddrStr> for String {
63    fn from(s: SocketAddrStr) -> Self {
64        s.as_ref().to_owned()
65    }
66}
67
68impl AsRef<str> for SocketAddrStr {
69    fn as_ref(&self) -> &str {
70        match self {
71            SocketAddrStr::Static(s) => s,
72            SocketAddrStr::Value(s) => s,
73        }
74    }
75}
76
77impl std::fmt::Display for SocketAddrStr {
78    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79        f.write_str(self.as_ref())
80    }
81}
82
83impl AttrValue for SocketAddrStr {
84    fn display(&self) -> String {
85        self.as_ref().to_owned()
86    }
87
88    fn parse(value: &str) -> Result<Self, anyhow::Error> {
89        value.parse::<SocketAddr>()?;
90        Ok(SocketAddrStr::Value(value.to_string()))
91    }
92}
93
94impl SocketAddrStr {
95    /// Parse the contained string as a `SocketAddr`.
96    pub fn parse_socket_addr(&self) -> Result<SocketAddr, std::net::AddrParseError> {
97        self.as_ref().parse()
98    }
99}
100
101// Declare hyperactor_mesh-specific configuration keys
102declare_attrs! {
103    /// The maximium for a dimension size allowed for a folded shape
104    /// when reshaping during casting to limit fanout.
105    /// usize::MAX means no reshaping as any shape will always be below
106    /// the limit so no dimension needs to be folded.
107    @meta(CONFIG = ConfigAttr::new(
108        Some("HYPERACTOR_MESH_MAX_CAST_DIMENSION_SIZE".to_string()),
109        Some("max_cast_dimension_size".to_string()),
110    ))
111    pub attr MAX_CAST_DIMENSION_SIZE: usize = usize::MAX;
112
113    /// Which builtin process launcher backend to use.
114    /// Accepted values: "native" (default), "systemd".
115    /// Trimmed and lowercased before matching.
116    ///
117    /// **Precedence:** Python spawner (via SetProcSpawner) overrides this.
118    @meta(CONFIG = ConfigAttr::new(
119        Some("HYPERACTOR_MESH_PROC_LAUNCHER_KIND".to_string()),
120        Some("proc_launcher_kind".to_string()),
121    ))
122    pub attr MESH_PROC_LAUNCHER_KIND: String = String::new();
123
124    /// Default socket address for the mesh admin HTTP server.
125    ///
126    /// Parsed as a `SocketAddr` (e.g. `[::]:1729`, `0.0.0.0:8080`).
127    /// Used as the bind address when no explicit address is provided
128    /// to `MeshAdminAgent`, and as the default address assumed by
129    /// admin clients connecting via `mast_conda:///`.
130    @meta(CONFIG = ConfigAttr::new(
131        Some("HYPERACTOR_MESH_ADMIN_ADDR".to_string()),
132        Some("mesh_admin_addr".to_string()),
133    ))
134    pub attr MESH_ADMIN_ADDR: SocketAddrStr = SocketAddrStr::Static("[::]:1729");
135
136    /// Timeout for fallback queries to actors/procs that may have been
137    /// recently destroyed. The second-chance paths in `resolve_proc_node`
138    /// and `resolve_actor_node` fire after the fast QueryChild lookup
139    /// fails. A short budget here prevents dead actors from blocking the
140    /// single-threaded MeshAdminAgent message loop.
141    @meta(CONFIG = ConfigAttr::new(
142        Some("HYPERACTOR_MESH_ADMIN_RESOLVE_ACTOR_TIMEOUT".to_string()),
143        Some("mesh_admin_resolve_actor_timeout".to_string()),
144    ))
145    pub attr MESH_ADMIN_RESOLVE_ACTOR_TIMEOUT: Duration = Duration::from_millis(200);
146
147    /// Maximum number of concurrent resolve requests the HTTP bridge
148    /// forwards to the MeshAdminAgent. Excess requests receive 503
149    /// immediately. Protects the shared tokio runtime from query floods
150    /// (e.g. multiple TUI clients, rapid polling). Increase if the admin
151    /// server serves many concurrent clients that need low-latency
152    /// responses; decrease if introspection queries interfere with the
153    /// actor workload under churn.
154    @meta(CONFIG = ConfigAttr::new(
155        Some("HYPERACTOR_MESH_ADMIN_MAX_CONCURRENT_RESOLVES".to_string()),
156        Some("mesh_admin_max_concurrent_resolves".to_string()),
157    ))
158    pub attr MESH_ADMIN_MAX_CONCURRENT_RESOLVES: usize = 2;
159
160    /// Timeout for the config-push barrier during `HostMesh::attach()`.
161    ///
162    /// When attaching to pre-existing workers (simple bootstrap), the
163    /// client pushes its propagatable config to each host agent and
164    /// waits for confirmation. If the barrier does not complete within
165    /// this duration, a warning is logged and attach continues without
166    /// blocking — config push is best-effort.
167    @meta(CONFIG = ConfigAttr::new(
168        Some("HYPERACTOR_MESH_ATTACH_CONFIG_TIMEOUT".to_string()),
169        Some("mesh_attach_config_timeout".to_string()),
170    ))
171    pub attr MESH_ATTACH_CONFIG_TIMEOUT: Duration = Duration::from_secs(10);
172}