@@ -34,79 +34,161 @@ use std::sync::LazyLock;
34
34
use std:: sync:: RwLock ;
35
35
use std:: time:: Duration ;
36
36
37
+ use serde:: Deserialize ;
38
+ use serde:: Serialize ;
37
39
use shell_quote:: QuoteRefExt ;
38
40
41
+ use crate as hyperactor;
39
42
use crate :: attrs:: AttrKeyInfo ;
43
+ use crate :: attrs:: AttrValue ;
40
44
use crate :: attrs:: Attrs ;
41
45
use crate :: attrs:: SerializableValue ;
42
46
use crate :: attrs:: declare_attrs;
43
- use crate :: data:: Encoding ;
47
+ use crate :: data:: Encoding ; // for macros
48
+
49
+ /// Metadata describing how a configuration key is exposed across
50
+ /// environments.
51
+ ///
52
+ /// Each `ConfigAttr` entry defines how a Rust configuration key maps
53
+ /// to external representations:
54
+ /// - `env_name`: the environment variable consulted by
55
+ /// [`init_from_env()`] when loading configuration.
56
+ /// - `py_name`: the Python keyword argument accepted by
57
+ /// `monarch.configure(...)` and returned by `get_configuration()`.
58
+ ///
59
+ /// All configuration keys should carry this meta-attribute via
60
+ /// `@meta(CONFIG = ConfigAttr { ... })`.
61
+ #[ derive( Clone , Debug , Serialize , Deserialize , hyperactor:: Named ) ]
62
+ pub struct ConfigAttr {
63
+ /// Environment variable consulted by `init_from_env()`.
64
+ pub env_name : Option < String > ,
65
+
66
+ /// Python kwarg name used by `monarch.configure(...)` and
67
+ /// `get_configuration()`.
68
+ pub py_name : Option < String > ,
69
+ }
70
+
71
+ impl AttrValue for ConfigAttr {
72
+ fn display ( & self ) -> String {
73
+ serde_json:: to_string ( self ) . unwrap_or_else ( |_| "<invalid ConfigAttr>" . into ( ) )
74
+ }
75
+ fn parse ( s : & str ) -> Result < Self , anyhow:: Error > {
76
+ Ok ( serde_json:: from_str ( s) ?)
77
+ }
78
+ }
44
79
45
80
// Declare configuration keys using the new attrs system with defaults
46
81
declare_attrs ! {
47
- /// This is a meta-attribute specifying the environment variable used by the configuration
48
- /// key.
49
- pub attr CONFIG_ENV_VAR : String ;
50
-
51
- /// This is a meta-attribute specifying the name of the kwarg to pass to monarch.configure()
52
- /// to set the attribute value in the global config.
53
- pub attr PYTHON_CONFIG_KEY : String ;
82
+ /// This is a meta-attribute marking a configuration key.
83
+ ///
84
+ /// It carries metadata used to bridge Rust, environment
85
+ /// variables, and Python:
86
+ /// - `env_name`: environment variable name consulted by
87
+ /// `init_from_env()`.
88
+ /// - `py_name`: keyword argument name recognized by
89
+ /// `monarch.configure(...)`.
90
+ ///
91
+ /// All configuration keys should be annotated with this
92
+ /// attribute.
93
+ pub attr CONFIG : ConfigAttr ;
54
94
55
95
/// Maximum frame length for codec
56
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_CODEC_MAX_FRAME_LENGTH" . to_string( ) )
96
+ @meta( CONFIG = ConfigAttr {
97
+ env_name: Some ( "HYPERACTOR_CODEC_MAX_FRAME_LENGTH" . to_string( ) ) ,
98
+ py_name: None ,
99
+ } )
57
100
pub attr CODEC_MAX_FRAME_LENGTH : usize = 10 * 1024 * 1024 * 1024 ; // 10 GiB
58
101
59
102
/// Message delivery timeout
60
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_MESSAGE_DELIVERY_TIMEOUT" . to_string( ) )
103
+ @meta( CONFIG = ConfigAttr {
104
+ env_name: Some ( "HYPERACTOR_MESSAGE_DELIVERY_TIMEOUT" . to_string( ) ) ,
105
+ py_name: None ,
106
+ } )
61
107
pub attr MESSAGE_DELIVERY_TIMEOUT : Duration = Duration :: from_secs( 30 ) ;
62
108
63
109
/// Timeout used by allocator for stopping a proc.
64
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_PROCESS_EXIT_TIMEOUT" . to_string( ) )
110
+ @meta( CONFIG = ConfigAttr {
111
+ env_name: Some ( "HYPERACTOR_PROCESS_EXIT_TIMEOUT" . to_string( ) ) ,
112
+ py_name: None ,
113
+ } )
65
114
pub attr PROCESS_EXIT_TIMEOUT : Duration = Duration :: from_secs( 10 ) ;
66
115
67
116
/// Message acknowledgment interval
68
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_MESSAGE_ACK_TIME_INTERVAL" . to_string( ) )
117
+ @meta( CONFIG = ConfigAttr {
118
+ env_name: Some ( "HYPERACTOR_MESSAGE_ACK_TIME_INTERVAL" . to_string( ) ) ,
119
+ py_name: None ,
120
+ } )
69
121
pub attr MESSAGE_ACK_TIME_INTERVAL : Duration = Duration :: from_millis( 500 ) ;
70
122
71
123
/// Number of messages after which to send an acknowledgment
72
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_MESSAGE_ACK_EVERY_N_MESSAGES" . to_string( ) )
124
+ @meta( CONFIG = ConfigAttr {
125
+ env_name: Some ( "HYPERACTOR_MESSAGE_ACK_EVERY_N_MESSAGES" . to_string( ) ) ,
126
+ py_name: None ,
127
+ } )
73
128
pub attr MESSAGE_ACK_EVERY_N_MESSAGES : u64 = 1000 ;
74
129
75
130
/// Default hop Time-To-Live for message envelopes.
76
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_MESSAGE_TTL_DEFAULT" . to_string( ) )
131
+ @meta( CONFIG = ConfigAttr {
132
+ env_name: Some ( "HYPERACTOR_MESSAGE_TTL_DEFAULT" . to_string( ) ) ,
133
+ py_name: None ,
134
+ } )
77
135
pub attr MESSAGE_TTL_DEFAULT : u8 = 64 ;
78
136
79
137
/// Maximum buffer size for split port messages
80
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_SPLIT_MAX_BUFFER_SIZE" . to_string( ) )
138
+ @meta( CONFIG = ConfigAttr {
139
+ env_name: Some ( "HYPERACTOR_SPLIT_MAX_BUFFER_SIZE" . to_string( ) ) ,
140
+ py_name: None ,
141
+ } )
81
142
pub attr SPLIT_MAX_BUFFER_SIZE : usize = 5 ;
82
143
83
144
/// The maximum time an update can be buffered before being reduced.
84
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_SPLIT_MAX_BUFFER_AGE" . to_string( ) )
145
+ @meta( CONFIG = ConfigAttr {
146
+ env_name: Some ( "HYPERACTOR_SPLIT_MAX_BUFFER_AGE" . to_string( ) ) ,
147
+ py_name: None ,
148
+ } )
85
149
pub attr SPLIT_MAX_BUFFER_AGE : Duration = Duration :: from_millis( 50 ) ;
86
150
87
151
/// Timeout used by proc mesh for stopping an actor.
88
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_STOP_ACTOR_TIMEOUT" . to_string( ) )
152
+ @meta( CONFIG = ConfigAttr {
153
+ env_name: Some ( "HYPERACTOR_STOP_ACTOR_TIMEOUT" . to_string( ) ) ,
154
+ py_name: None ,
155
+ } )
89
156
pub attr STOP_ACTOR_TIMEOUT : Duration = Duration :: from_secs( 1 ) ;
90
157
91
158
/// Heartbeat interval for remote allocator
92
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_REMOTE_ALLOCATOR_HEARTBEAT_INTERVAL" . to_string( ) )
159
+ @meta( CONFIG = ConfigAttr {
160
+ env_name: Some ( "HYPERACTOR_REMOTE_ALLOCATOR_HEARTBEAT_INTERVAL" . to_string( ) ) ,
161
+ py_name: None ,
162
+ } )
93
163
pub attr REMOTE_ALLOCATOR_HEARTBEAT_INTERVAL : Duration = Duration :: from_secs( 5 ) ;
94
164
95
165
/// The default encoding to be used.
96
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_DEFAULT_ENCODING" . to_string( ) )
166
+ @meta( CONFIG = ConfigAttr {
167
+ env_name: Some ( "HYPERACTOR_DEFAULT_ENCODING" . to_string( ) ) ,
168
+ py_name: None ,
169
+ } )
97
170
pub attr DEFAULT_ENCODING : Encoding = Encoding :: Multipart ;
98
171
99
172
/// Whether to use multipart encoding for network channel communications.
100
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_CHANNEL_MULTIPART" . to_string( ) )
173
+ @meta( CONFIG = ConfigAttr {
174
+ env_name: Some ( "HYPERACTOR_CHANNEL_MULTIPART" . to_string( ) ) ,
175
+ py_name: None ,
176
+ } )
101
177
pub attr CHANNEL_MULTIPART : bool = true ;
102
178
103
179
/// How often to check for full MSPC channel on NetRx.
104
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_CHANNEL_NET_RX_BUFFER_FULL_CHECK_INTERVAL" . to_string( ) )
180
+ @meta( CONFIG = ConfigAttr {
181
+ env_name: Some ( "HYPERACTOR_CHANNEL_NET_RX_BUFFER_FULL_CHECK_INTERVAL" . to_string( ) ) ,
182
+ py_name: None ,
183
+ } )
105
184
pub attr CHANNEL_NET_RX_BUFFER_FULL_CHECK_INTERVAL : Duration = Duration :: from_secs( 5 ) ;
106
185
107
186
/// Sampling rate for logging message latency
108
187
/// Set to 0.01 for 1% sampling, 0.1 for 10% sampling, 0.90 for 90% sampling, etc.
109
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_MESSAGE_LATENCY_SAMPLING_RATE" . to_string( ) )
188
+ @meta( CONFIG = ConfigAttr {
189
+ env_name: Some ( "HYPERACTOR_MESSAGE_LATENCY_SAMPLING_RATE" . to_string( ) ) ,
190
+ py_name: None ,
191
+ } )
110
192
pub attr MESSAGE_LATENCY_SAMPLING_RATE : f32 = 0.01 ;
111
193
112
194
/// Whether to enable client sequence assignment.
@@ -116,7 +198,10 @@ declare_attrs! {
116
198
///
117
199
/// Default: 10 seconds. If set to zero, disables the timeout and
118
200
/// waits indefinitely.
119
- @meta( CONFIG_ENV_VAR = "HYPERACTOR_HOST_SPAWN_READY_TIMEOUT" . to_string( ) )
201
+ @meta( CONFIG = ConfigAttr {
202
+ env_name: Some ( "HYPERACTOR_HOST_SPAWN_READY_TIMEOUT" . to_string( ) ) ,
203
+ py_name: None ,
204
+ } )
120
205
pub attr HOST_SPAWN_READY_TIMEOUT : Duration = Duration :: from_secs( 10 ) ;
121
206
}
122
207
@@ -134,9 +219,17 @@ pub fn from_env() -> Attrs {
134
219
}
135
220
136
221
for key in inventory:: iter :: < AttrKeyInfo > ( ) {
137
- let Some ( env_var) = key. meta . get ( CONFIG_ENV_VAR ) else {
222
+ // Skip keys that are not marked as CONFIG or that do not
223
+ // declare an environment variable mapping. Only CONFIG-marked
224
+ // keys with an `env_name` participate in environment
225
+ // initialization.
226
+ let Some ( cfg_meta) = key. meta . get ( CONFIG ) else {
138
227
continue ;
139
228
} ;
229
+ let Some ( env_var) = cfg_meta. env_name . as_deref ( ) else {
230
+ continue ;
231
+ } ;
232
+
140
233
let Ok ( val) = env:: var ( env_var) else {
141
234
// Default value
142
235
output. push_str ( "# " ) ;
0 commit comments