improve assistant behavior when the service is shutting down
This commit is contained in:
@@ -13,6 +13,7 @@ pub use signal_gateway_assistant::{
|
|||||||
use crate::message_handler::AdminMessageResponse;
|
use crate::message_handler::AdminMessageResponse;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use tokio::sync::{mpsc, oneshot};
|
use tokio::sync::{mpsc, oneshot};
|
||||||
|
use tokio_util::sync::CancellationToken;
|
||||||
use worker::{AssistantWorker, Input};
|
use worker::{AssistantWorker, Input};
|
||||||
|
|
||||||
/// Size of the request queue for the assistant worker.
|
/// Size of the request queue for the assistant worker.
|
||||||
@@ -39,8 +40,9 @@ pub enum AssistantError {
|
|||||||
pub struct AssistantAgent {
|
pub struct AssistantAgent {
|
||||||
input_tx: mpsc::Sender<Input>,
|
input_tx: mpsc::Sender<Input>,
|
||||||
stop_tx: mpsc::Sender<()>,
|
stop_tx: mpsc::Sender<()>,
|
||||||
|
cancellation_token: CancellationToken,
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
worker_handle: tokio::task::JoinHandle<()>,
|
worker_handle: Option<tokio::task::JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssistantAgent {
|
impl AssistantAgent {
|
||||||
@@ -50,18 +52,20 @@ impl AssistantAgent {
|
|||||||
pub fn new(assistant: Box<dyn Assistant>) -> Self {
|
pub fn new(assistant: Box<dyn Assistant>) -> Self {
|
||||||
let (input_tx, input_rx) = mpsc::channel(REQUEST_QUEUE_SIZE);
|
let (input_tx, input_rx) = mpsc::channel(REQUEST_QUEUE_SIZE);
|
||||||
let (stop_tx, stop_rx) = mpsc::channel(REQUEST_QUEUE_SIZE);
|
let (stop_tx, stop_rx) = mpsc::channel(REQUEST_QUEUE_SIZE);
|
||||||
|
let cancellation_token = CancellationToken::new();
|
||||||
|
|
||||||
let worker = AssistantWorker::new(assistant, input_rx, stop_rx);
|
let worker = AssistantWorker::new(assistant, input_rx, stop_rx, cancellation_token.clone());
|
||||||
|
|
||||||
let worker_handle = tokio::spawn(async move {
|
let worker_handle = Some(tokio::spawn(async move {
|
||||||
worker.run().await;
|
worker.run().await;
|
||||||
tracing::info!("Assistant worker task exited");
|
tracing::info!("Assistant worker task exited");
|
||||||
});
|
}));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
input_tx,
|
input_tx,
|
||||||
stop_tx,
|
stop_tx,
|
||||||
worker_handle,
|
worker_handle,
|
||||||
|
cancellation_token,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,8 +115,14 @@ impl AssistantAgent {
|
|||||||
let _ = self.input_tx.try_send(Input::Debug);
|
let _ = self.input_tx.try_send(Input::Debug);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Request the worker to stop processing and cancel pending requests.
|
/// Request the worker to stop what it's doing and cancel pending requests (but not exit).
|
||||||
pub fn request_stop(&self) {
|
pub fn request_stop(&self) {
|
||||||
let _ = self.stop_tx.try_send(());
|
let _ = self.stop_tx.try_send(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for AssistantAgent {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.cancellation_token.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,7 +26,10 @@ pub enum Input {
|
|||||||
pub struct AssistantWorker {
|
pub struct AssistantWorker {
|
||||||
assistant: Box<dyn Assistant>,
|
assistant: Box<dyn Assistant>,
|
||||||
input_rx: mpsc::Receiver<Input>,
|
input_rx: mpsc::Receiver<Input>,
|
||||||
|
/// Used when the user wants to cancel the current requests, but not shutdown the service
|
||||||
stop_rx: mpsc::Receiver<()>,
|
stop_rx: mpsc::Receiver<()>,
|
||||||
|
/// Used when the user wants to shut down the service
|
||||||
|
cancellation_token: CancellationToken,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AssistantWorker {
|
impl AssistantWorker {
|
||||||
@@ -35,11 +38,13 @@ impl AssistantWorker {
|
|||||||
assistant: Box<dyn Assistant>,
|
assistant: Box<dyn Assistant>,
|
||||||
input_rx: mpsc::Receiver<Input>,
|
input_rx: mpsc::Receiver<Input>,
|
||||||
stop_rx: mpsc::Receiver<()>,
|
stop_rx: mpsc::Receiver<()>,
|
||||||
|
cancellation_token: CancellationToken,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
assistant,
|
assistant,
|
||||||
input_rx,
|
input_rx,
|
||||||
stop_rx,
|
stop_rx,
|
||||||
|
cancellation_token,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,22 +56,34 @@ impl AssistantWorker {
|
|||||||
let Some(input) = input else {
|
let Some(input) = input else {
|
||||||
break; // Channel closed
|
break; // Channel closed
|
||||||
};
|
};
|
||||||
self.handle_input(input).await;
|
let was_canceled = self.handle_input(input).await;
|
||||||
|
if was_canceled {
|
||||||
|
// If the overall cancellation token was canceled,
|
||||||
|
// then don't even bother calling handle_stop, just exit
|
||||||
|
if self.cancellation_token.is_cancelled() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.handle_stop().await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ = self.stop_rx.recv() => {
|
_ = self.stop_rx.recv() => {
|
||||||
self.handle_stop().await;
|
self.handle_stop().await;
|
||||||
}
|
}
|
||||||
|
_ = self.cancellation_token.cancelled() => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_input(&mut self, input: Input) {
|
async fn handle_input(&mut self, input: Input) -> bool {
|
||||||
match input {
|
match input {
|
||||||
Input::Prompt(msg, sender) => {
|
Input::Prompt(msg, sender) => {
|
||||||
// Make a cancel token for each new request
|
// Make a child cancel token for each new request
|
||||||
let cancel_token = CancellationToken::new();
|
let cancel_token = self.cancellation_token.child_token();
|
||||||
|
|
||||||
let mut assistant_fut = self.assistant.prompt(msg, cancel_token.clone());
|
let mut assistant_fut = self.assistant.prompt(msg, cancel_token.clone());
|
||||||
|
let mut was_canceled = false;
|
||||||
|
|
||||||
// If the assistant finishes normally, return its result.
|
// If the assistant finishes normally, return its result.
|
||||||
// If we get a stop request, cancel the token, then wait for assistant to finish.
|
// If we get a stop request, cancel the token, then wait for assistant to finish.
|
||||||
@@ -76,6 +93,7 @@ impl AssistantWorker {
|
|||||||
},
|
},
|
||||||
_ = self.stop_rx.recv() => {
|
_ = self.stop_rx.recv() => {
|
||||||
cancel_token.cancel();
|
cancel_token.cancel();
|
||||||
|
was_canceled = true;
|
||||||
assistant_fut.await
|
assistant_fut.await
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -91,15 +109,20 @@ impl AssistantWorker {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let _ = sender.send(response);
|
let _ = sender.send(response);
|
||||||
|
|
||||||
|
was_canceled
|
||||||
}
|
}
|
||||||
Input::Record(msg) => {
|
Input::Record(msg) => {
|
||||||
self.assistant.record_message(msg).await;
|
self.assistant.record_message(msg).await;
|
||||||
|
false
|
||||||
}
|
}
|
||||||
Input::Compact => {
|
Input::Compact => {
|
||||||
self.assistant.compact().await;
|
self.assistant.compact().await;
|
||||||
|
false
|
||||||
}
|
}
|
||||||
Input::Debug => {
|
Input::Debug => {
|
||||||
self.assistant.debug_log();
|
self.assistant.debug_log();
|
||||||
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user