hyperactor_remote/proto.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//! Message types for remote supervision sessions.
10//!
11//! A remote supervision relationship is represented by one worker actor
12//! supervising one child actor on behalf of one supervisor. The supervisor
13//! initiates the relationship by sending [`Supervise`] to the worker. The
14//! `supervisor` port in [`Supervise`] identifies the session endpoint that the
15//! worker uses for all replies and supervision events. The `liveness` spec in
16//! [`Supervise`] identifies the implementation actor that the worker spawns as
17//! the session liveness mechanism. Later supervisor commands are sent to the
18//! worker as [`WorkerCommand`] messages and carry the same `session_id`; the
19//! worker accepts only the active session.
20
21use hyperactor::ActorAddr;
22use hyperactor::ActorEnvironment;
23use hyperactor::Data;
24use hyperactor::HandleClient;
25use hyperactor::Handler;
26use hyperactor::PortRef;
27use hyperactor::RefClient;
28use hyperactor::RemoteSpawn;
29use hyperactor::actor::StopMode;
30use hyperactor::context;
31use hyperactor::id::Uid;
32use hyperactor::supervision::ActorSupervisionEvent;
33use hyperactor_config::Flattrs;
34use serde::Deserialize;
35use serde::Serialize;
36use typeuri::Named;
37
38use crate::link::LinkSpec;
39
40/// Global actor spawn (gspawn) specification.
41#[derive(Clone, Debug, Serialize, Deserialize, Named, PartialEq, Eq)]
42pub struct Gspawn {
43 actor_type: String,
44 uid: Uid,
45 params: Data,
46 environment: ActorEnvironment,
47}
48wirevalue::register_type!(Gspawn);
49
50impl Gspawn {
51 /// Create a spawn specification for the registered actor type with a fresh
52 /// uid and the caller's persistent environment.
53 pub fn for_actor<A>(cx: &impl context::Actor, params: A::Params) -> anyhow::Result<Self>
54 where
55 A: RemoteSpawn + Named,
56 {
57 Self::for_actor_uid::<A>(cx, Uid::anonymous(), params)
58 }
59
60 /// Create a spawn specification for the registered actor type with an
61 /// explicit uid and the caller's persistent environment.
62 pub fn for_actor_uid<A>(
63 cx: &impl context::Actor,
64 uid: Uid,
65 params: A::Params,
66 ) -> anyhow::Result<Self>
67 where
68 A: RemoteSpawn + Named,
69 {
70 Self::for_actor_uid_in_environment::<A>(
71 uid,
72 params,
73 cx.instance().actor_environment().clone(),
74 )
75 }
76
77 /// Create a spawn specification for the registered actor type with an
78 /// explicit uid and a caller-shaped persistent environment (AENV-4).
79 pub(crate) fn for_actor_uid_in_environment<A>(
80 uid: Uid,
81 params: A::Params,
82 environment: ActorEnvironment,
83 ) -> anyhow::Result<Self>
84 where
85 A: RemoteSpawn + Named,
86 {
87 Ok(Self::with_uid(
88 A::typename(),
89 uid,
90 bincode::serde::encode_to_vec(params, bincode::config::legacy())?,
91 environment,
92 ))
93 }
94
95 pub(crate) fn with_uid(
96 actor_type: impl Into<String>,
97 uid: Uid,
98 params: Data,
99 environment: ActorEnvironment,
100 ) -> Self {
101 Self {
102 actor_type: actor_type.into(),
103 uid,
104 params,
105 environment,
106 }
107 }
108
109 /// Registered name of the actor to spawn.
110 pub fn actor_type(&self) -> &str {
111 &self.actor_type
112 }
113
114 /// The uid that will identify the spawned actor.
115 pub fn uid(&self) -> &Uid {
116 &self.uid
117 }
118
119 /// The serialized parameters passed to the actor.
120 pub fn params(&self) -> &[u8] {
121 &self.params
122 }
123
124 /// The persistent environment to install on the spawned actor.
125 pub fn actor_environment(&self) -> &ActorEnvironment {
126 &self.environment
127 }
128
129 /// Spawn the actor as a supervised child of `parent`.
130 pub async fn spawn_child<C: hyperactor::context::Actor>(
131 self,
132 parent: &C,
133 ) -> anyhow::Result<hyperactor::AnyActorHandle> {
134 let Self {
135 actor_type,
136 uid,
137 params,
138 environment,
139 } = self;
140 parent
141 .instance()
142 .gspawn_uid_in_environment(&actor_type, uid, params, environment)
143 .await
144 }
145}
146
147/// Request sent to an actor spawner to spawn and supervise one registered actor.
148#[derive(
149 Clone,
150 Debug,
151 Serialize,
152 Deserialize,
153 Named,
154 PartialEq,
155 Eq,
156 Handler,
157 HandleClient,
158 RefClient
159)]
160pub struct SpawnActor {
161 /// Registered actor spawn specification.
162 pub gspawn: Gspawn,
163 /// Supervise request to send back.
164 pub supervise: Supervise,
165}
166wirevalue::register_type!(SpawnActor);
167
168/// Request sent to a proc-spawner endpoint to spawn and supervise one proc.
169#[derive(
170 Clone,
171 Debug,
172 Serialize,
173 Deserialize,
174 Named,
175 PartialEq,
176 Eq,
177 Handler,
178 HandleClient,
179 RefClient
180)]
181pub struct SpawnProc {
182 /// Proc uid to spawn.
183 pub uid: Uid,
184 /// Supervise request to send back.
185 pub supervise: Supervise,
186}
187wirevalue::register_type!(SpawnProc);
188
189/// Request sent by a supervisor proxy to a worker actor.
190#[derive(
191 Clone,
192 Debug,
193 Serialize,
194 Deserialize,
195 Named,
196 PartialEq,
197 Eq,
198 Handler,
199 HandleClient,
200 RefClient
201)]
202pub struct Supervise {
203 /// Unique identifier for this supervision session.
204 pub session_id: Uid,
205 /// Supervisor session port used by the worker to report outcomes.
206 pub supervisor: PortRef<SupervisorEvent>,
207 /// The actor that owns the supervisor proxy.
208 pub parent: ActorAddr,
209 /// Liveness implementation actor to spawn on the worker side.
210 pub liveness: LinkSpec,
211 /// Session policy requested by the supervisor.
212 pub options: SupervisionOptions,
213 /// Labels the worker sets on every supervision event it reports in this
214 /// session. They are opaque to remote supervision.
215 pub labels: Flattrs,
216}
217wirevalue::register_type!(Supervise);
218
219/// Options that govern a remote supervision session.
220#[derive(Clone, Debug, Serialize, Deserialize, Named, PartialEq, Eq)]
221pub struct SupervisionOptions {
222 /// Policy to apply when the supervisor session is unlinked or expires.
223 pub orphan_policy: OrphanPolicy,
224}
225wirevalue::register_type!(SupervisionOptions);
226
227impl Default for SupervisionOptions {
228 fn default() -> Self {
229 Self {
230 orphan_policy: OrphanPolicy::Stop,
231 }
232 }
233}
234
235/// Worker behavior when its supervisor session is orphaned.
236#[derive(Clone, Copy, Debug, Serialize, Deserialize, Named, PartialEq, Eq)]
237pub enum OrphanPolicy {
238 /// Stop the supervised child if the supervisor unlinks or expires.
239 Stop,
240 /// Leave the supervised child running after supervisor unlink.
241 Detach,
242}
243wirevalue::register_type!(OrphanPolicy);
244
245/// Commands sent by the supervisor proxy to the supervised worker actor.
246#[derive(
247 Clone,
248 Debug,
249 Serialize,
250 Deserialize,
251 Named,
252 PartialEq,
253 Eq,
254 Handler,
255 HandleClient,
256 RefClient
257)]
258pub enum WorkerCommand {
259 /// Stop the supervised child.
260 Stop {
261 /// Unique identifier for this supervision session.
262 session_id: Uid,
263 /// Stop mode to mirror from the parent side.
264 mode: StopMode,
265 /// Reason for stopping the supervised child.
266 reason: String,
267 },
268 /// Unlink the supervisor session.
269 Unlink {
270 /// Unique identifier for this supervision session.
271 session_id: Uid,
272 /// Reason for unlinking the session.
273 reason: String,
274 },
275}
276wirevalue::register_type!(WorkerCommand);
277
278hyperactor::behavior!(WorkerLike, Supervise, WorkerCommand);
279
280/// Messages sent by the worker actor to the supervisor session port.
281#[derive(Clone, Debug, Serialize, Deserialize, Named, PartialEq, Eq)]
282pub enum SupervisorEvent {
283 /// The worker accepted the session and identified its supervised child.
284 Linked {
285 /// Unique identifier for this supervision session.
286 session_id: Uid,
287 /// Worker actor that owns the supervised child.
288 worker: PortRef<WorkerCommand>,
289 /// Actor address for the supervised child.
290 child: ActorAddr,
291 /// Friendly display name for the supervised child, if available.
292 display_name: Option<String>,
293 },
294 /// The worker rejected the supervise request.
295 SuperviseRejected {
296 /// Unique identifier for this supervision session.
297 session_id: Uid,
298 /// Reason the supervise request failed.
299 reason: String,
300 },
301 /// A supervision event observed by, or synthesized for, the worker.
302 SupervisionEvent {
303 /// Unique identifier for this supervision session.
304 session_id: Uid,
305 /// Event to deliver to the supervisor side.
306 event: ActorSupervisionEvent,
307 /// What the worker knows about the remote actor state.
308 disposition: RemoteActorDisposition,
309 },
310 /// The worker unlinked the session without reporting a supervision event.
311 Unlinked {
312 /// Unique identifier for this supervision session.
313 session_id: Uid,
314 /// Reason for unlinking the session.
315 reason: String,
316 },
317}
318wirevalue::register_type!(SupervisorEvent);
319
320/// What a worker-side event establishes about the supervised child.
321#[derive(Clone, Copy, Debug, Serialize, Deserialize, Named, PartialEq, Eq)]
322pub enum RemoteActorDisposition {
323 /// The supervised child reached a terminal local lifecycle state.
324 Terminal,
325 /// The child is unreachable from the supervisor side and may still be running.
326 Unreachable,
327}
328wirevalue::register_type!(RemoteActorDisposition);