Skip to main content

reifydb_runtime/actor/
context.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4//! Actor execution context.
5//!
6//! The context provides actors with access to:
7//! - Self reference for receiving messages
8//! - Actor system for spawning child actors
9//! - Cancellation status for graceful shutdown
10//! - Timer scheduling (when enabled)
11
12use std::{
13	sync::{
14		Arc,
15		atomic::{AtomicBool, Ordering},
16	},
17	time::Duration,
18};
19
20#[cfg(reifydb_target = "wasm")]
21use crate::actor::timers::wasm::{schedule_once_fn, schedule_repeat};
22use crate::actor::{mailbox::ActorRef, system::ActorSystem, timers::TimerHandle};
23
24/// A cancellation token for signaling shutdown.
25///
26/// This is a simple atomic boolean that can be shared across actors.
27#[derive(Clone)]
28pub struct CancellationToken {
29	cancelled: Arc<AtomicBool>,
30}
31
32impl CancellationToken {
33	/// Create a new cancellation token.
34	pub fn new() -> Self {
35		Self {
36			cancelled: Arc::new(AtomicBool::new(false)),
37		}
38	}
39
40	/// Signal cancellation.
41	pub fn cancel(&self) {
42		self.cancelled.store(true, Ordering::SeqCst);
43	}
44
45	/// Check if cancellation was requested.
46	pub fn is_cancelled(&self) -> bool {
47		self.cancelled.load(Ordering::SeqCst)
48	}
49}
50
51impl Default for CancellationToken {
52	fn default() -> Self {
53		Self::new()
54	}
55}
56
57/// Context provided to actors during execution.
58///
59/// Provides access to:
60/// - Self reference (to give to other actors)
61/// - Actor system (to spawn child actors and run compute)
62/// - Cancellation (for graceful shutdown)
63pub struct Context<M> {
64	self_ref: ActorRef<M>,
65	system: ActorSystem,
66	cancel: CancellationToken,
67}
68
69impl<M: Send + 'static> Context<M> {
70	/// Create a new context.
71	pub(crate) fn new(self_ref: ActorRef<M>, system: ActorSystem, cancel: CancellationToken) -> Self {
72		Self {
73			self_ref,
74			system,
75			cancel,
76		}
77	}
78
79	/// Get a reference to send messages to self.
80	pub fn self_ref(&self) -> ActorRef<M> {
81		self.self_ref.clone()
82	}
83
84	/// Get the actor system (for spawning child actors).
85	pub fn system(&self) -> &ActorSystem {
86		&self.system
87	}
88
89	/// Check if shutdown was requested.
90	pub fn is_cancelled(&self) -> bool {
91		self.cancel.is_cancelled()
92	}
93
94	/// Get the cancellation token.
95	pub fn cancellation_token(&self) -> CancellationToken {
96		self.cancel.clone()
97	}
98}
99
100impl<M: Send + 'static> Context<M> {
101	/// Schedule a message to be sent to this actor after a delay.
102	///
103	/// Uses a factory function to create the message, so `M` doesn't need to be `Clone`.
104	/// Returns a handle that can be used to cancel the timer.
105	#[cfg(reifydb_target = "native")]
106	pub fn schedule_once<F: FnOnce() -> M + Send + 'static>(&self, delay: Duration, factory: F) -> TimerHandle {
107		let actor_ref = self.self_ref.clone();
108		self.system.scheduler().schedule_once(delay, move || {
109			let _ = actor_ref.send(factory());
110		})
111	}
112
113	/// Schedule a message to be sent to this actor after a delay.
114	///
115	/// Uses a factory function to create the message, so `M` doesn't need to be `Clone`.
116	/// Returns a handle that can be used to cancel the timer.
117	#[cfg(reifydb_target = "wasm")]
118	pub fn schedule_once<F: FnOnce() -> M + Send + 'static>(&self, delay: Duration, factory: F) -> TimerHandle {
119		schedule_once_fn(self.self_ref.clone(), delay, factory)
120	}
121}
122
123impl<M: Send + Sync + Clone + 'static> Context<M> {
124	/// Schedule a message to be sent to this actor repeatedly at an interval.
125	///
126	/// The timer continues until cancelled or the actor is dropped.
127	/// Returns a handle that can be used to cancel the timer.
128	#[cfg(reifydb_target = "native")]
129	pub fn schedule_repeat(&self, interval: Duration, msg: M) -> TimerHandle {
130		let actor_ref = self.self_ref.clone();
131		self.system.scheduler().schedule_repeat(interval, move || actor_ref.send(msg.clone()).is_ok())
132	}
133
134	/// Schedule a message to be sent to this actor repeatedly at an interval.
135	///
136	/// The timer continues until cancelled or the actor is dropped.
137	/// Returns a handle that can be used to cancel the timer.
138	#[cfg(reifydb_target = "wasm")]
139	pub fn schedule_repeat(&self, interval: Duration, msg: M) -> TimerHandle {
140		schedule_repeat(self.self_ref.clone(), interval, msg)
141	}
142}
143
144impl<M> Clone for Context<M> {
145	fn clone(&self) -> Self {
146		Self {
147			self_ref: self.self_ref.clone(),
148			system: self.system.clone(),
149			cancel: self.cancel.clone(),
150		}
151	}
152}