44
55use rpc_core:: { Codec , Transport } ;
66use std:: sync:: Arc ;
7+ use std:: time:: Duration ;
78use tokio:: sync:: Mutex ;
89use wasmtime:: component:: { Component , Linker } ;
910use wasmtime:: { Config , Engine , Store } ;
@@ -71,42 +72,74 @@ where
7172{
7273 engine : Engine ,
7374 linker : Linker < RuntimeState < T , C > > ,
75+ max_timeout : Duration ,
7476}
7577
7678impl < T , C > WasmRuntime < T , C >
7779where
7880 T : Transport + Send + ' static ,
7981 C : Codec + Send + ' static ,
8082{
81- /// Create a new WASM runtime
82- pub fn new ( ) -> Result < Self > {
83+ /// Create a new WASM runtime with a maximum execution timeout
84+ ///
85+ /// # Arguments
86+ /// * `max_timeout` - Maximum CPU time any kernel can use (enforced server-side)
87+ pub fn new ( max_timeout : Duration ) -> Result < Self > {
8388 let mut config = Config :: new ( ) ;
8489 config. wasm_component_model ( true ) ;
8590 config. async_support ( true ) ;
91+ // Enable epoch-based interruption for CPU time limiting
92+ config. epoch_interruption ( true ) ;
8693
8794 let engine = Engine :: new ( & config) ?;
8895 let mut linker = Linker :: new ( & engine) ;
8996
9097 // Add WASI support
9198 wasmtime_wasi:: add_to_linker_async ( & mut linker) ?;
9299
93- Ok ( Self { engine, linker } )
100+ Ok ( Self { engine, linker, max_timeout } )
94101 }
95102
96- /// Execute a WASM component kernel
103+ /// Execute a WASM component kernel with timeout
104+ ///
105+ /// # Arguments
106+ /// * `component_bytes` - The compiled WASM component
107+ /// * `transport` - Transport for RPC calls
108+ /// * `codec` - Codec for serialization
109+ /// * `requested_timeout` - Optional client-requested timeout (capped at max_timeout)
110+ ///
111+ /// # Timeout Behavior
112+ /// The actual timeout used is `min(requested_timeout, max_timeout)`, ensuring the server
113+ /// always enforces its maximum limit regardless of client requests.
97114 pub async fn execute (
98115 & mut self ,
99116 component_bytes : & [ u8 ] ,
100117 transport : T ,
101118 codec : C ,
119+ requested_timeout : Option < Duration > ,
102120 ) -> Result < Vec < u8 > > {
121+ // Client can request shorter timeout, but not longer than server max
122+ let timeout = requested_timeout
123+ . map ( |t| t. min ( self . max_timeout ) )
124+ . unwrap_or ( self . max_timeout ) ;
125+
103126 let component = Component :: from_binary ( & self . engine , component_bytes) ?;
104127
105128 let state = RuntimeState :: new ( transport, codec) ;
106129 let mut store = Store :: new ( & self . engine , state) ;
107130
131+ // Set epoch deadline for timeout
132+ store. set_epoch_deadline ( 1 ) ;
133+
134+ // Spawn background task to increment epoch after timeout
135+ let engine = self . engine . clone ( ) ;
136+ tokio:: spawn ( async move {
137+ tokio:: time:: sleep ( timeout) . await ;
138+ engine. increment_epoch ( ) ;
139+ } ) ;
140+
108141 // Instantiate the component
109- let instance = self . linker . instantiate_async ( & mut store, & component) . await ?;
142+ let _instance = self . linker . instantiate_async ( & mut store, & component) . await ?;
110143
111144 // TODO: Call the kernel's exported function and get result
112145 // For now, return empty result
@@ -119,7 +152,8 @@ where
119152 T : Transport + Send + ' static ,
120153 C : Codec + Send + ' static ,
121154{
155+ /// Create a default runtime with 5 second timeout
122156 fn default ( ) -> Self {
123- Self :: new ( ) . expect ( "Failed to create WASM runtime" )
157+ Self :: new ( Duration :: from_secs ( 5 ) ) . expect ( "Failed to create WASM runtime" )
124158 }
125159}
0 commit comments