1- /// Inter-Database Communication (IDC) Runtime
1+ /// Inter-Database Communication (IDC) Actor
22///
33/// Background tokio task that:
44/// 1. Loads undelivered entries from `st_outbound_msg` on startup, resolving delivery data from outbox tables.
@@ -29,47 +29,47 @@ const MAX_BACKOFF: Duration = Duration::from_secs(30);
2929/// How long to wait before polling again when there is no work.
3030const POLL_INTERVAL : Duration = Duration :: from_millis ( 500 ) ;
3131
32- /// A sender that notifies the IDC runtime of a new outbox row.
32+ /// A sender that notifies the IDC actor of a new outbox row.
3333///
34- /// Sending `()` wakes the runtime to deliver pending messages immediately
34+ /// Sending `()` wakes the actor to deliver pending messages immediately
3535/// rather than waiting for the next poll cycle.
36- pub type IdcSender = mpsc:: UnboundedSender < ( ) > ;
36+ pub type IdcActorSender = mpsc:: UnboundedSender < ( ) > ;
3737
38- /// The identity of this (sender) database, set when the IDC runtime is started.
39- pub struct IdcRuntimeConfig {
38+ /// The identity of this (sender) database, set when the IDC actor is started.
39+ pub struct IdcActorConfig {
4040 pub sender_identity : Identity ,
4141}
4242
43- /// A handle that, when dropped, stops the IDC runtime background task.
44- pub struct IdcRuntime {
43+ /// A handle that, when dropped, stops the IDC actor background task.
44+ pub struct IdcActor {
4545 _abort : tokio:: task:: AbortHandle ,
4646}
4747
48- /// Holds the receiver side of the notification channel until the runtime is started.
48+ /// Holds the receiver side of the notification channel until the actor is started.
4949///
5050/// Mirrors the `SchedulerStarter` pattern: create the channel before the module is
51- /// loaded (so the sender can be stored in `InstanceEnv`), then call [`IdcRuntimeStarter ::start`]
51+ /// loaded (so the sender can be stored in `InstanceEnv`), then call [`IdcActorStarter ::start`]
5252/// once the DB is ready.
53- pub struct IdcRuntimeStarter {
53+ pub struct IdcActorStarter {
5454 rx : mpsc:: UnboundedReceiver < ( ) > ,
5555}
5656
57- impl IdcRuntimeStarter {
58- /// Spawn the IDC runtime background task.
59- pub fn start ( self , db : Arc < RelationalDB > , config : IdcRuntimeConfig , module_host : WeakModuleHost ) -> IdcRuntime {
57+ impl IdcActorStarter {
58+ /// Spawn the IDC actor background task.
59+ pub fn start ( self , db : Arc < RelationalDB > , config : IdcActorConfig , module_host : WeakModuleHost ) -> IdcActor {
6060 let abort = tokio:: spawn ( run_idc_loop ( db, config, module_host, self . rx ) ) . abort_handle ( ) ;
61- IdcRuntime { _abort : abort }
61+ IdcActor { _abort : abort }
6262 }
6363}
6464
65- impl IdcRuntime {
65+ impl IdcActor {
6666 /// Open the IDC channel, returning a starter and a sender.
6767 ///
6868 /// Store the sender in `ModuleCreationContext` so it reaches `InstanceEnv`.
69- /// After the module is ready, call [`IdcRuntimeStarter ::start`] to spawn the loop.
70- pub fn open ( ) -> ( IdcRuntimeStarter , IdcSender ) {
69+ /// After the module is ready, call [`IdcActorStarter ::start`] to spawn the loop.
70+ pub fn open ( ) -> ( IdcActorStarter , IdcActorSender ) {
7171 let ( tx, rx) = mpsc:: unbounded_channel ( ) ;
72- ( IdcRuntimeStarter { rx } , tx)
72+ ( IdcActorStarter { rx } , tx)
7373 }
7474}
7575
@@ -138,10 +138,10 @@ enum DeliveryOutcome {
138138 TransportError ( String ) ,
139139}
140140
141- /// Main IDC loop: maintain per-target queues and deliver messages.
141+ /// Main IDC actor loop: maintain per-target queues and deliver messages.
142142async fn run_idc_loop (
143143 db : Arc < RelationalDB > ,
144- config : IdcRuntimeConfig ,
144+ config : IdcActorConfig ,
145145 module_host : WeakModuleHost ,
146146 mut notify_rx : mpsc:: UnboundedReceiver < ( ) > ,
147147) {
@@ -169,7 +169,7 @@ async fn run_idc_loop(
169169 match outcome {
170170 DeliveryOutcome :: TransportError ( reason) => {
171171 log:: warn!(
172- "idc_runtime : transport error delivering msg_id={} to {}: {reason}" ,
172+ "idc_actor : transport error delivering msg_id={} to {}: {reason}" ,
173173 msg. msg_id,
174174 hex:: encode( msg. target_db_identity. to_byte_array( ) ) ,
175175 ) ;
@@ -224,6 +224,9 @@ fn outcome_to_result(outcome: &DeliveryOutcome) -> (u8, String) {
224224}
225225
226226/// Finalize a delivered message: call the on_result reducer (if any), then delete from ST_OUTBOUND_MSG.
227+ ///
228+ /// On the happy path, `on_result_reducer` success and deletion of `st_outbound_msg`
229+ /// are committed atomically in the same reducer transaction.
227230async fn finalize_message (
228231 db : & RelationalDB ,
229232 module_host : & WeakModuleHost ,
@@ -235,7 +238,7 @@ async fn finalize_message(
235238 if let Some ( on_result_reducer) = & msg. on_result_reducer {
236239 let Some ( host) = module_host. upgrade ( ) else {
237240 log:: warn!(
238- "idc_runtime : module host gone, cannot call on_result reducer '{}' for msg_id={}" ,
241+ "idc_actor : module host gone, cannot call on_result reducer '{}' for msg_id={}" ,
239242 on_result_reducer,
240243 msg. msg_id,
241244 ) ;
@@ -249,7 +252,7 @@ async fn finalize_message(
249252 Ok ( b) => b,
250253 Err ( e) => {
251254 log:: error!(
252- "idc_runtime : failed to encode on_result args for msg_id={}: {e}" ,
255+ "idc_actor : failed to encode on_result args for msg_id={}: {e}" ,
253256 msg. msg_id
254257 ) ;
255258 delete_message ( db, msg. msg_id ) ;
@@ -259,28 +262,30 @@ async fn finalize_message(
259262
260263 let caller_identity = Identity :: ZERO ; // system call
261264 let result = host
262- . call_reducer (
265+ . call_reducer_delete_outbound_on_success (
263266 caller_identity,
264267 None , // no connection_id
265268 None , // no client sender
266269 None , // no request_id
267270 None , // no timer
268271 on_result_reducer,
269272 FunctionArgs :: Bsatn ( bytes:: Bytes :: from ( args_bytes) ) ,
273+ msg. msg_id ,
270274 )
271275 . await ;
272276
273277 match result {
274278 Ok ( _) => {
275279 log:: debug!(
276- "idc_runtime : on_result reducer '{}' called for msg_id={}" ,
280+ "idc_actor : on_result reducer '{}' called for msg_id={}" ,
277281 on_result_reducer,
278282 msg. msg_id,
279283 ) ;
284+ return ;
280285 }
281286 Err ( e) => {
282287 log:: error!(
283- "idc_runtime : on_result reducer '{}' failed for msg_id={}: {e:?}" ,
288+ "idc_actor : on_result reducer '{}' failed for msg_id={}: {e:?}" ,
284289 on_result_reducer,
285290 msg. msg_id,
286291 ) ;
@@ -307,7 +312,7 @@ fn load_pending_into_targets(db: &RelationalDB, targets: &mut HashMap<Identity,
307312 . collect ( )
308313 } )
309314 . unwrap_or_else ( |e| {
310- log:: error!( "idc_runtime : failed to read st_outbound_msg: {e}" ) ;
315+ log:: error!( "idc_actor : failed to read st_outbound_msg: {e}" ) ;
311316 Vec :: new ( )
312317 } ) ;
313318
@@ -321,7 +326,7 @@ fn load_pending_into_targets(db: &RelationalDB, targets: &mut HashMap<Identity,
321326 Ok ( s) => s,
322327 Err ( e) => {
323328 log:: error!(
324- "idc_runtime : cannot find schema for outbox table {:?} (msg_id={}): {e}" ,
329+ "idc_actor : cannot find schema for outbox table {:?} (msg_id={}): {e}" ,
325330 outbox_table_id,
326331 st_row. msg_id,
327332 ) ;
@@ -333,7 +338,7 @@ fn load_pending_into_targets(db: &RelationalDB, targets: &mut HashMap<Identity,
333338 Some ( o) => o,
334339 None => {
335340 log:: error!(
336- "idc_runtime : table {:?} (msg_id={}) is not an outbox table" ,
341+ "idc_actor : table {:?} (msg_id={}) is not an outbox table" ,
337342 schema. table_name,
338343 st_row. msg_id,
339344 ) ;
@@ -351,7 +356,7 @@ fn load_pending_into_targets(db: &RelationalDB, targets: &mut HashMap<Identity,
351356
352357 let Some ( outbox_row_ref) = outbox_row else {
353358 log:: error!(
354- "idc_runtime : outbox row not found in table {:?} for row_id={} (msg_id={})" ,
359+ "idc_actor : outbox row not found in table {:?} for row_id={} (msg_id={})" ,
355360 outbox_table_id,
356361 st_row. row_id,
357362 st_row. msg_id,
@@ -366,7 +371,7 @@ fn load_pending_into_targets(db: &RelationalDB, targets: &mut HashMap<Identity,
366371 Some ( AlgebraicValue :: U256 ( u) ) => Identity :: from_u256 ( * * u) ,
367372 other => {
368373 log:: error!(
369- "idc_runtime : outbox row col 1 expected U256 (Identity), got {other:?} (msg_id={})" ,
374+ "idc_actor : outbox row col 1 expected U256 (Identity), got {other:?} (msg_id={})" ,
370375 st_row. msg_id,
371376 ) ;
372377 continue ;
@@ -409,7 +414,7 @@ fn load_pending_into_targets(db: &RelationalDB, targets: &mut HashMap<Identity,
409414/// Attempt a single HTTP delivery of a message.
410415async fn attempt_delivery (
411416 client : & reqwest:: Client ,
412- config : & IdcRuntimeConfig ,
417+ config : & IdcActorConfig ,
413418 msg : & PendingMessage ,
414419) -> DeliveryOutcome {
415420 let target_db_hex = hex:: encode ( msg. target_db_identity . to_byte_array ( ) ) ;
@@ -453,11 +458,11 @@ async fn attempt_delivery(
453458fn delete_message ( db : & RelationalDB , msg_id : u64 ) {
454459 let mut tx = db. begin_mut_tx ( IsolationLevel :: Serializable , Workload :: Internal ) ;
455460 if let Err ( e) = tx. delete_outbound_msg ( msg_id) {
456- log:: error!( "idc_runtime : failed to delete msg_id={msg_id}: {e}" ) ;
461+ log:: error!( "idc_actor : failed to delete msg_id={msg_id}: {e}" ) ;
457462 let _ = db. rollback_mut_tx ( tx) ;
458463 return ;
459464 }
460465 if let Err ( e) = db. commit_tx ( tx) {
461- log:: error!( "idc_runtime : failed to commit delete for msg_id={msg_id}: {e}" ) ;
466+ log:: error!( "idc_actor : failed to commit delete for msg_id={msg_id}: {e}" ) ;
462467 }
463468}
0 commit comments