Skip to main content

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);