dora_runtime_shared_lib/
lib.rs1use dora_core::{
13 config::NodeId,
14 descriptor::{Descriptor, OperatorDefinition, OperatorSource},
15};
16use dora_node_api::Event;
17use dora_runtime_api::{OperatorRunner, RunnerGuard, RuntimeHandle};
18use eyre::{Context, Result};
19use tokio::sync::oneshot;
20
21mod runner;
22
23pub fn main() -> eyre::Result<()> {
25 dora_runtime_api::main(SharedLibRunner)
26}
27
28pub struct SharedLibRunner;
30
31impl OperatorRunner for SharedLibRunner {
32 fn run_operator(
33 &self,
34 node_id: &NodeId,
35 operator: OperatorDefinition,
36 incoming_events: flume::Receiver<Event>,
37 handle: RuntimeHandle,
38 init_done: oneshot::Sender<Result<()>>,
39 _dataflow_descriptor: &Descriptor,
40 ) -> eyre::Result<RunnerGuard> {
41 match &operator.config.source {
42 OperatorSource::SharedLibrary(source) => runner::run(
47 node_id,
48 &operator.id,
49 source,
50 handle,
51 incoming_events,
52 init_done,
53 )
54 .wrap_err_with(|| {
55 format!(
56 "failed to spawn shared library operator for {}",
57 operator.id
58 )
59 })
60 .map(|library| Some(Box::new(library) as Box<dyn std::any::Any>)),
61 OperatorSource::Python(_) => eyre::bail!(
67 "operator `{}` uses a Python source, but this is the shared-library \
68 runtime; Python operators are spawned by the Python runtime \
69 (`dora-runtime-python`)",
70 operator.id
71 ),
72 OperatorSource::Wasm(_) => eyre::bail!(
73 "operator `{}` uses a WASM source, which is not supported yet",
74 operator.id
75 ),
76 }
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use dora_runtime_api::SharedAllocator;
84
85 fn run_unsupported(yaml: &str) -> (eyre::Report, oneshot::Receiver<Result<()>>) {
88 let operator: OperatorDefinition =
89 serde_yaml::from_str(yaml).expect("operator definition parses");
90 let dataflow: Descriptor =
91 serde_yaml::from_str("nodes:\n - id: a\n").expect("descriptor parses");
92 let (_events_in_tx, incoming_events) = flume::unbounded::<Event>();
93 let (events_tx, _events_rx) = tokio::sync::mpsc::channel(1);
94 let (init_done_tx, init_done_rx) = oneshot::channel();
95
96 let err = SharedLibRunner
97 .run_operator(
98 &NodeId::from("node".to_string()),
99 operator,
100 incoming_events,
101 RuntimeHandle::new(events_tx, SharedAllocator::default()),
102 init_done_tx,
103 &dataflow,
104 )
105 .expect_err("unsupported operator source must return an error");
106 (err, init_done_rx)
107 }
108
109 #[test]
115 fn wasm_source_returns_descriptive_error() {
116 let (err, mut init_done_rx) = run_unsupported("id: op\nwasm: model.wasm\n");
117 assert!(
118 err.to_string().contains("WASM"),
119 "expected a descriptive WASM error, got: {err}"
120 );
121 assert!(
122 init_done_rx.try_recv().is_err(),
123 "init_done must not receive a value for an unsupported source"
124 );
125 }
126
127 #[test]
132 fn python_source_returns_descriptive_error() {
133 let (err, mut init_done_rx) = run_unsupported("id: op\npython: op.py\n");
134 let msg = err.to_string();
135 assert!(
136 msg.contains("Python") && msg.contains("shared-library runtime"),
137 "expected an error naming the wrong runtime, got: {err}"
138 );
139 assert!(
140 init_done_rx.try_recv().is_err(),
141 "init_done must not receive a value for a wrongly routed source"
142 );
143 }
144}