multi_instance_isolated/
multi_instance_isolated.rs1use std::cell::{Cell, RefCell};
9use std::rc::Rc;
10
11use auralis_signal::Signal;
12use auralis_task::{Executor, ScheduleFlush, TaskScope};
13
14struct SyncScheduler;
16impl ScheduleFlush for SyncScheduler {
17 fn schedule(&self, callback: Box<dyn FnOnce()>) {
18 callback();
19 }
20}
21
22fn handle_request(request_id: u32) -> String {
29 let ex = Executor::new_instance();
30 Executor::install_flush_scheduler(&ex, Rc::new(SyncScheduler));
31
32 let scope = TaskScope::with_executor(&ex);
33 let data = Signal::new(String::new());
34
35 let d = data.clone();
37 scope.spawn(async move {
38 loop {
39 d.changed().await;
40 let val = d.read();
41 if val == "done" {
42 break;
43 }
44 }
45 });
46
47 let cleanup_called = Rc::new(Cell::new(false));
49 let cc = Rc::clone(&cleanup_called);
50 scope.on_cleanup(move || cc.set(true));
51
52 let result = auralis_task::with_executor(&ex, || {
54 data.set(format!("request {request_id}: processing"));
55 data.set(format!("request {request_id}: done"));
56 data.read()
57 });
58
59 drop(scope);
61
62 assert!(cleanup_called.get());
63 result
64}
65
66fn main() {
67 println!("=== 1. Sequential request isolation ===");
69 let r1 = handle_request(1);
70 let r2 = handle_request(2);
71 println!(" {r1}");
72 println!(" {r2}");
73 assert_eq!(r1, "request 1: done");
74 assert_eq!(r2, "request 2: done");
75
76 println!("\n=== 2. Cross-executor signal isolation ===");
78 {
79 let ex_a = Executor::new_instance();
80 Executor::install_flush_scheduler(&ex_a, Rc::new(SyncScheduler));
81 let ex_b = Executor::new_instance();
82 Executor::install_flush_scheduler(&ex_b, Rc::new(SyncScheduler));
83
84 let sig_a1 = Signal::new(0i32);
85 let sig_b1 = Signal::new(0i32);
86
87 let scope_a = TaskScope::with_executor(&ex_a);
89 let a_val = Rc::new(RefCell::new(Vec::new()));
90 let av = Rc::clone(&a_val);
91 {
92 let s = sig_a1.clone();
93 scope_a.spawn(async move {
94 s.set(42);
95 av.borrow_mut().push(s.read());
96 });
97 }
98 drop(scope_a);
99
100 let scope_b = TaskScope::with_executor(&ex_b);
102 let b_val = Rc::new(RefCell::new(Vec::new()));
103 let bv = Rc::clone(&b_val);
104 {
105 let s = sig_b1.clone();
106 scope_b.spawn(async move {
107 s.set(99);
108 bv.borrow_mut().push(s.read());
109 });
110 }
111 drop(scope_b);
112
113 assert_eq!(*a_val.borrow(), vec![42]);
115 assert_eq!(*b_val.borrow(), vec![99]);
116 assert_eq!(sig_a1.read(), 42);
117 assert_eq!(sig_b1.read(), 99);
118 }
119
120 println!("\n=== 3. SSR mental model ===");
122 for i in 0..3 {
123 let ex = Executor::new_instance();
124 Executor::install_flush_scheduler(&ex, Rc::new(SyncScheduler));
125 let counter = Signal::new(0i32);
126
127 let scope = TaskScope::with_executor(&ex);
128 let c = counter.clone();
129 let results = Rc::new(RefCell::new(Vec::new()));
130 let res = Rc::clone(&results);
131
132 scope.spawn(async move {
133 loop {
134 c.changed().await;
135 let v = c.read();
136 res.borrow_mut().push(v);
137 if v >= 3 {
138 break;
139 }
140 }
141 });
142
143 auralis_task::with_executor(&ex, || {
144 counter.set(1);
145 counter.set(2);
146 counter.set(3);
147 });
148
149 drop(scope);
150 assert_eq!(*results.borrow(), vec![1, 2, 3]);
151 println!(" request {i}: signals {:?}", results.borrow());
152 }
153
154 println!("\nAll patterns completed — zero cross-request leakage.");
155}