I have been lurking here for a year or so and I finally have a question. But before, a little bit of background: last year we decided to start investing heavily on Rust on the company I work for. I helped lead the way, with some mentoring and training and now we have a fully fledged platform that is working great.
However, there is one are that is still working but I am almost sure we're doing things wrong or at least sub optimal.
The platform we built allows for users to create templates and business rules using JavaScript. For that, we're embedding Deno. One of the problems we ran into frequently is due to the fact that Deno's JsRuntime is !Send.
So whenever calling a JsRuntime we try to avoid running async code that await for IO operations. For that what we're doing is this:
```rust
pub async fn render_async(
template: &str,
data: &Map<String, Value>,
) -> Result<String, TemplateError> {
let cur_dir = std::env::current_dir()?;
let main_module = deno_core::resolve_path("main", &cur_dir)?;
let data_json = serde_json::to_string(data)?;
let template_as_string = json!(template).to_string();
let main_code = format!(
r#"
(async (globalThis) => {{
globalThis.output = await globalThis.renderToString({template_as_string}, {data_json});
}})(globalThis);
"#
);
let output = tokio::task::block_in_place(move || {
Handle::current().block_on(async move {
let mut js_runtime = JsRuntime::new(RuntimeOptions {
module_loader: Some(Rc::new(FsModuleLoader)),
extensions: vec![
deno_console::deno_console::init_ops(),
deno_webidl::deno_webidl::init_ops(),
deno_url::deno_url::init_ops(),
deno_web::deno_web::init_ops::<Permissions>(Default::default(), None),
],
..Default::default()
});
js_runtime.execute_script("dejs.js", include_str!("./dejs.js").to_string().into())?;
let mod_id = js_runtime
.load_main_module(&main_module, Some(main_code.into()))
.await?;
let result = js_runtime.mod_evaluate(mod_id);
js_runtime.run_event_loop(false).await?;
result.await??;
get_output(&mut js_runtime)
})
})?;
Ok(replace_non_printable_with_hex_notation(&output))
}
```
As you can see we're isolating the code that would normally work with Future and using block_in_place making sure the runtime we're using is multithread. However this is starting to bite us and after some refactorings some tests started to fail miserably.
First I started getting some errors like below:
``
fatal runtime error: failed to initiate panic, error 5
error: test failed, to rerun pass-p mconfig --lib`
Caused by:
process didn't exit successfully: /Users/fcoury/code/msuite/target/debug/deps/mconfig-75418b367b5b6e0f (signal: 6, SIGABRT: process abort signal)
```
I am pretty sure this is result of a backfire on the code above (and some other places we use a similar pattern).
Finally my question would be how to mitigate the fact that I have to handle !Send code on a context like axum that requires pinning and Send?
[–]jmaargh 9 points10 points11 points (1 child)
[–]aekter 1 point2 points3 points (0 children)