fix(serve): start scheduler at startup instead of first ACP connection (#10766)

This commit is contained in:
Colin Gauvin
2026-08-02 20:05:34 -06:00
committed by GitHub
parent 750d95e974
commit 5ab0e6df34
2 changed files with 42 additions and 0 deletions
+3
View File
@@ -1480,6 +1480,9 @@ async fn handle_serve_command(args: ServeCommandArgs) -> Result<()> {
})
.collect::<Result<Vec<_>>>()?;
let secret_key = env_secret.unwrap_or_else(generate_serve_secret_key);
if let Err(error) = server.start_scheduler().await {
warn!("Scheduler failed to start; scheduled jobs will not run until a client connects: {error}");
}
let router = create_router(
server,
secret_key,
+39
View File
@@ -32,6 +32,13 @@ impl AcpServer {
}
}
/// Start the scheduler now instead of on first client connect, so a
/// headless `goose serve` runs scheduled jobs; on failure `create_agent`
/// retries. No-op when the scheduler is disabled.
pub async fn start_scheduler(&self) -> Result<()> {
self.scheduler().await.map(|_| ())
}
async fn scheduler(&self) -> Result<Option<Arc<dyn SchedulerTrait>>> {
if !self.config.enable_scheduler {
return Ok(None);
@@ -57,6 +64,10 @@ impl AcpServer {
let config = crate::config::Config::global();
let disable_session_naming = config.get_goose_disable_session_naming().unwrap_or(false);
let scheduler = self.scheduler().await?;
if let Some(scheduler) = &scheduler {
// Listing syncs from storage, registering jobs persisted by other processes.
scheduler.list_scheduled_jobs().await;
}
let provider_factory: AcpProviderFactory =
Arc::new(move |provider_name, extensions, working_dir| {
@@ -123,4 +134,32 @@ mod tests {
assert!(server.scheduler().await.unwrap().is_some());
}
#[tokio::test]
async fn start_scheduler_initializes_before_any_client_connects() {
let root = tempfile::tempdir().unwrap();
let server = server(root.path().to_path_buf(), true);
assert!(!server.scheduler.initialized());
server.start_scheduler().await.unwrap();
assert!(server.scheduler.initialized());
}
#[tokio::test]
async fn start_scheduler_is_idempotent() {
let root = tempfile::tempdir().unwrap();
let server = server(root.path().to_path_buf(), true);
server.start_scheduler().await.unwrap();
server.start_scheduler().await.unwrap();
}
#[tokio::test]
async fn start_scheduler_does_not_construct_one_when_disabled() {
let root = tempfile::tempdir().unwrap();
let server = server(root.path().to_path_buf(), false);
server.start_scheduler().await.unwrap();
assert!(!server.scheduler.initialized());
}
}