fix(service): Switch from flume to postage to fix out-of-order communication
This commit is contained in:
parent
490c6a6e8b
commit
8b4fbf441f
12 changed files with 156 additions and 208 deletions
14
service/src/plugins/external/load.rs
vendored
14
service/src/plugins/external/load.rs
vendored
|
|
@ -1,7 +1,9 @@
|
|||
use crate::PluginConfig;
|
||||
|
||||
use flume::Sender;
|
||||
use futures_lite::{future::zip, Stream, StreamExt};
|
||||
use postage::mpsc::Sender;
|
||||
use postage::prelude::Stream as PostageStream;
|
||||
use postage::prelude::*;
|
||||
use regex::Regex;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
|
|
@ -9,8 +11,8 @@ use std::path::{Path, PathBuf};
|
|||
///
|
||||
/// Searches plugin paths from highest to least priority. User plugins will override
|
||||
/// distribution plugins. Plugins are loaded in the order they are found.
|
||||
pub async fn from_paths(tx: Sender<(PathBuf, PluginConfig, Option<Regex>)>) {
|
||||
let (tasks_tx, tasks_rx) = flume::unbounded();
|
||||
pub async fn from_paths(mut tx: Sender<(PathBuf, PluginConfig, Option<Regex>)>) {
|
||||
let (mut tasks_tx, mut tasks_rx) = postage::mpsc::channel(8);
|
||||
|
||||
// Spawns a background task to run in parallel for each plugin found
|
||||
let task_spawner = async move {
|
||||
|
|
@ -20,7 +22,7 @@ pub async fn from_paths(tx: Sender<(PathBuf, PluginConfig, Option<Regex>)>) {
|
|||
|
||||
while let Some((source, config)) = loadable_plugins.next().await {
|
||||
let future = smol::unblock(move || crate::plugins::config::load(&source, &config));
|
||||
if tasks_tx.send_async(smol::spawn(future)).await.is_err() {
|
||||
if tasks_tx.send(smol::spawn(future)).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -29,9 +31,9 @@ pub async fn from_paths(tx: Sender<(PathBuf, PluginConfig, Option<Regex>)>) {
|
|||
|
||||
// This future ensures that plugins are returned in the order they were spawned.
|
||||
let task_listener = async move {
|
||||
while let Ok(task) = tasks_rx.recv_async().await {
|
||||
while let Some(task) = tasks_rx.recv().await {
|
||||
if let Some(plugin) = task.await {
|
||||
if tx.send_async(plugin).await.is_err() {
|
||||
if tx.send(plugin).await.is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
18
service/src/plugins/external/mod.rs
vendored
18
service/src/plugins/external/mod.rs
vendored
|
|
@ -11,8 +11,9 @@ use std::{
|
|||
|
||||
use crate::{Event, Plugin, PluginResponse, Request};
|
||||
use async_oneshot::oneshot;
|
||||
use flume::Sender;
|
||||
use futures_lite::{AsyncWriteExt, FutureExt, StreamExt};
|
||||
use postage::mpsc::Sender;
|
||||
use postage::prelude::*;
|
||||
use smol::{
|
||||
process::{Child, Command, Stdio},
|
||||
Task,
|
||||
|
|
@ -66,13 +67,13 @@ impl ExternalPlugin {
|
|||
let detached = self.detached.clone();
|
||||
let searching = self.searching.clone();
|
||||
let (trip_tx, trip_rx) = oneshot::<()>();
|
||||
let tx = self.tx.clone();
|
||||
let mut tx = self.tx.clone();
|
||||
let name = self.name().to_owned();
|
||||
let id = self.id;
|
||||
|
||||
// Spawn a background task to forward JSON responses from the child process.
|
||||
let task = smol::spawn(async move {
|
||||
let tx_ = tx.clone();
|
||||
let mut tx_ = tx.clone();
|
||||
let searching_ = searching.clone();
|
||||
let name_ = name.clone();
|
||||
|
||||
|
|
@ -87,11 +88,10 @@ impl ExternalPlugin {
|
|||
searching_.store(false, Ordering::SeqCst);
|
||||
}
|
||||
|
||||
tracing::debug!("{}: responding with {:?}", name_, response);
|
||||
let _ = tx_.send(Event::Response((id, response)));
|
||||
let _ = tx_.send(Event::Response((id, response))).await;
|
||||
}
|
||||
Err(why) => {
|
||||
event!(Level::ERROR, "{}: serde error: {:?}", name_, why);
|
||||
tracing::error!("{}: serde error: {:?}", name_, why);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +107,9 @@ impl ExternalPlugin {
|
|||
|
||||
// Ensure that a task that was searching sends a finished signal if it dies.
|
||||
if searching.swap(false, Ordering::SeqCst) {
|
||||
let _ = tx.send(Event::Response((id, PluginResponse::Finished)));
|
||||
let _ = tx
|
||||
.send(Event::Response((id, PluginResponse::Finished)))
|
||||
.await;
|
||||
}
|
||||
|
||||
detached.store(true, Ordering::SeqCst);
|
||||
|
|
@ -194,7 +196,7 @@ impl Plugin for ExternalPlugin {
|
|||
} else {
|
||||
let _ = self
|
||||
.tx
|
||||
.send_async(Event::Response((self.id, PluginResponse::Finished)))
|
||||
.send(Event::Response((self.id, PluginResponse::Finished)))
|
||||
.await;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use crate::*;
|
||||
use flume::Sender;
|
||||
use pop_launcher::*;
|
||||
use postage::mpsc::Sender;
|
||||
use postage::prelude::*;
|
||||
use slab::Slab;
|
||||
use std::borrow::Cow;
|
||||
|
||||
|
|
@ -22,23 +23,21 @@ pub const CONFIG: PluginConfig = PluginConfig {
|
|||
pub struct HelpPlugin {
|
||||
pub id: usize,
|
||||
pub details: Slab<PluginHelp>,
|
||||
pub internal: Sender<Event>,
|
||||
pub tx: Sender<Event>,
|
||||
}
|
||||
|
||||
impl HelpPlugin {
|
||||
pub fn new(id: usize, internal: Sender<Event>, tx: Sender<Event>) -> Self {
|
||||
pub fn new(id: usize, tx: Sender<Event>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
details: Slab::new(),
|
||||
internal,
|
||||
tx,
|
||||
}
|
||||
}
|
||||
|
||||
async fn reload(&mut self) {
|
||||
let (tx, rx) = async_oneshot::oneshot();
|
||||
let _ = self.internal.send_async(Event::Help(tx)).await;
|
||||
let _ = self.tx.send(Event::Help(tx)).await;
|
||||
self.details = rx.await.expect("internal error fetching help info");
|
||||
}
|
||||
}
|
||||
|
|
@ -50,7 +49,7 @@ impl Plugin for HelpPlugin {
|
|||
if let Some(help) = detail.help.as_ref() {
|
||||
let _ = self
|
||||
.tx
|
||||
.send_async(Event::Response((
|
||||
.send(Event::Response((
|
||||
self.id,
|
||||
PluginResponse::Fill(help.clone()),
|
||||
)))
|
||||
|
|
@ -84,16 +83,13 @@ impl Plugin for HelpPlugin {
|
|||
..Default::default()
|
||||
});
|
||||
|
||||
let _ = self
|
||||
.tx
|
||||
.send_async(Event::Response((self.id, response)))
|
||||
.await;
|
||||
let _ = self.tx.send(Event::Response((self.id, response))).await;
|
||||
}
|
||||
}
|
||||
|
||||
let _ = self
|
||||
.tx
|
||||
.send_async(Event::Response((self.id, PluginResponse::Finished)))
|
||||
.send(Event::Response((self.id, PluginResponse::Finished)))
|
||||
.await;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ pub use self::help::HelpPlugin;
|
|||
|
||||
use crate::{PluginHelp, Request};
|
||||
use async_trait::async_trait;
|
||||
use flume::{Receiver, Sender};
|
||||
use postage::mpsc::{Receiver, Sender};
|
||||
use postage::prelude::*;
|
||||
use regex::Regex;
|
||||
|
||||
#[async_trait]
|
||||
|
|
@ -31,8 +32,8 @@ where
|
|||
|
||||
async fn quit(&mut self, id: u32);
|
||||
|
||||
async fn run(&mut self, rx: Receiver<Request>) {
|
||||
while let Ok(request) = rx.recv_async().await {
|
||||
async fn run(&mut self, mut rx: Receiver<Request>) {
|
||||
while let Some(request) = rx.recv().await {
|
||||
tracing::event!(
|
||||
tracing::Level::DEBUG,
|
||||
"{}: received {:?}",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue