Skip to content
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
de929da
Add scheduler service
sitaowang1998 Jun 29, 2026
182d09d
Update doc
sitaowang1998 Jun 29, 2026
a82298d
Add grpc server
sitaowang1998 Jun 29, 2026
bea09d5
Fix docstring
sitaowang1998 Jun 29, 2026
09c351b
Merge branch 'main' into scheduler-service
sitaowang1998 Jun 29, 2026
3baaf8b
Fix merge
sitaowang1998 Jun 29, 2026
7c82fef
Merge branch 'scheduler-service' into scheduler-grpc-server
sitaowang1998 Jun 29, 2026
c7b2216
Implement scheduler runtime.
LinZhihao-723 Jun 30, 2026
351b00f
Merge branch 'scheduler-runtime' into scheduler-grpc-server
sitaowang1998 Jun 30, 2026
b3d3407
Add scheduler grpc server
sitaowang1998 Jun 30, 2026
c876a54
Fix toml
sitaowang1998 Jun 30, 2026
04e3e1e
Merge branch 'oss-main' into scheduler-runtime
LinZhihao-723 Jun 30, 2026
50a562f
Merge branch 'scheduler-runtime' into scheduler-grpc-server
sitaowang1998 Jun 30, 2026
bbf288d
Fix merge
sitaowang1998 Jul 1, 2026
5edb5b8
Merge branch 'main' into scheduler-grpc-server
sitaowang1998 Jul 1, 2026
41f0a80
Fix grpc status
sitaowang1998 Jul 1, 2026
fa97dd6
Merge branch 'main' into scheduler-grpc-server
sitaowang1998 Jul 2, 2026
4f97796
Fix logging
sitaowang1998 Jul 3, 2026
dbc5732
Merge branch 'main' into scheduler-grpc-server
sitaowang1998 Jul 5, 2026
11d6bcc
Merge branch 'main' into scheduler-grpc-server
sitaowang1998 Jul 5, 2026
3fe90a5
Polish server entry point; Polish config's docstring.
LinZhihao-723 Jul 5, 2026
21911fa
Change connection pool size config field name.
LinZhihao-723 Jul 6, 2026
5574bfe
Done.
LinZhihao-723 Jul 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions components/spider-proto-rust/src/assignment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ impl From<TaskAssignmentRecord> for ProtoTaskAssignmentRecord {
}
}

impl From<ProtoTaskAssignmentRecord> for TaskAssignmentRecord {
fn from(record: ProtoTaskAssignmentRecord) -> Self {
Self {
id: TaskAssignmentId::from(record.id),
from: SchedulerId::from(record.from),
}
}
}

impl TryFrom<NextTaskResponse> for Option<SchedulerResponse> {
type Error = Error;

Expand Down Expand Up @@ -67,6 +76,14 @@ mod tests {
assert_eq!(record.from, 9);
}

#[test]
fn protocol_assignment_record_converts_to_core() {
let record = TaskAssignmentRecord::from(ProtoTaskAssignmentRecord { id: 7, from: 9 });

assert_eq!(record.id, TaskAssignmentId::from(7));
assert_eq!(record.from, SchedulerId::from(9));
}

#[test]
fn next_task_response_converts_assignment() {
let response = NextTaskResponse {
Expand Down
2 changes: 2 additions & 0 deletions components/spider-proto-rust/src/unpack/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
//!
//! * [`common`] — shared helpers for `common.proto` types (e.g. [`common::TaskId`]).
//! * [`storage`] — request unpacking for `storage.proto`.
//! * [`scheduler`] — request unpacking for `scheduler.proto`.

mod common;
mod scheduler;
mod storage;

use tonic::{Code, Status};
Expand Down
59 changes: 59 additions & 0 deletions components/spider-proto-rust/src/unpack/scheduler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//! [`RequestUnpack`] implementations for `scheduler.proto` requests.

use std::time::Duration;

use spider_core::types::{id::ExecutionManagerId, scheduler::TaskAssignmentRecord};

use crate::{
scheduler::{
HeartbeatRequest,
NextTaskRequest,
ShutdownRequest,
TaskAssignmentRecord as ProtoTaskAssignmentRecord,
},
unpack::{RequestUnpack, UnpackError},
};

/// Unpacks [`NextTaskRequest`] into a tuple containing:
///
/// * The execution manager ID.
/// * The previously consumed assignment record, if any.
/// * The maximum duration to wait for an assignment.
impl RequestUnpack for NextTaskRequest {
type Unpacked = (ExecutionManagerId, Option<TaskAssignmentRecord>, Duration);

fn unpack(self) -> Result<Self::Unpacked, UnpackError> {
Ok((
ExecutionManagerId::from(self.execution_manager_id),
self.prev_assignment.map(ProtoTaskAssignmentRecord::into),
Duration::from_millis(self.wait_time_ms),
))
}
}

/// Unpacks [`HeartbeatRequest`] into an [`ExecutionManagerId`].
impl RequestUnpack for HeartbeatRequest {
type Unpacked = ExecutionManagerId;

fn unpack(self) -> Result<Self::Unpacked, UnpackError> {
Ok(ExecutionManagerId::from(self.execution_manager_id))
}
}

/// Unpacks [`ShutdownRequest`] into a tuple containing:
///
/// * The execution manager ID.
/// * The previously consumed assignment records.
impl RequestUnpack for ShutdownRequest {
type Unpacked = (ExecutionManagerId, Vec<TaskAssignmentRecord>);

fn unpack(self) -> Result<Self::Unpacked, UnpackError> {
Ok((
ExecutionManagerId::from(self.execution_manager_id),
self.prev_assignments
.into_iter()
.map(ProtoTaskAssignmentRecord::into)
.collect(),
))
}
}
10 changes: 9 additions & 1 deletion components/spider-scheduler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,23 @@ edition = "2024"
name = "spider_scheduler"
path = "src/lib.rs"

[[bin]]
name = "spider_scheduler_grpc_server"
path = "src/bin/grpc_server.rs"

[dependencies]
async-channel = "2.3.1"
async-trait = "0.1.89"
clap = { version = "4.6.1", features = ["derive"] }
serde = { version = "1.0.228", features = ["derive"] }
spider-core = { path = "../spider-core" }
spider-proto-rust = { path = "../spider-proto-rust" }
spider-utils = { path = "../spider-utils" }
thiserror = "2.0.18"
tokio = { version = "1.52.3", features = ["macros", "rt", "sync", "time"] }
tokio = {
version = "1.52.3",
features = ["macros", "rt-multi-thread", "signal", "sync", "time"]
}
tokio-util = "0.7.18"
tonic = "0.14.6"
tracing = { version = "0.1.41", default-features = false, features = ["std"] }
Expand Down
65 changes: 65 additions & 0 deletions components/spider-scheduler/src/bin/grpc_server.rs

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have implemented the EM binary as an example and asked you to review in #362.
And clearly this PR doesn't follow what I've done there.

Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//! Command-line entrypoint for the scheduler gRPC server.

use std::{error::Error, net::SocketAddr, path::PathBuf};

use clap::Parser;
use spider_proto_rust::scheduler::scheduler_service_server::SchedulerServiceServer;
use spider_scheduler::{
GrpcSchedulerStorageClient,
ServerConfig,
create_runtime,
grpc::GrpcSchedulerService,
};
use spider_utils::{config::YamlConfig, logging::set_up_logging};
use tokio::select;
use tonic::transport::Server;

/// Command-line arguments for the scheduler gRPC server.
#[derive(Debug, Parser)]
#[command(about = "Run the Spider scheduler gRPC server.")]
struct Cli {
/// Path to the YAML server configuration file.
#[arg(short, long, value_name = "PATH")]
config: PathBuf,
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let _log_guard = set_up_logging();
let cli = Cli::parse();
let server_config = ServerConfig::from_yaml_file(&cli.config)?;
let listen_addr = SocketAddr::new(server_config.runtime.host, server_config.runtime.port);

let storage_client = GrpcSchedulerStorageClient::connect(
server_config.storage_endpoint.endpoint()?,
server_config.storage_connection_pool_size,
)
.await?;

let (runtime, service, cancellation_token) =
create_runtime(server_config.runtime, storage_client).await?;
let grpc_service = GrpcSchedulerService::new(service, cancellation_token.clone());
tracing::info!(listen_addr = % listen_addr, "Starting scheduler gRPC server.");

let serve_result = Server::builder()
.add_service(SchedulerServiceServer::new(grpc_service))
.serve_with_shutdown(listen_addr, async move {
select! {
() = cancellation_token.cancelled() => {
tracing::info!("Shutting down scheduler gRPC server.");
}
result = tokio::signal::ctrl_c() => {
if let Err(error) = result {
tracing::error!(error = % error, "Failed to listen for Ctrl-C.");
}
cancellation_token.cancel();
}
}
})
.await;

let stop_result = runtime.stop().await;
serve_result?;
stop_result?;
Ok(())
}
24 changes: 23 additions & 1 deletion components/spider-scheduler/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,36 @@
//! The scheduler core configuration that selects and configures the scheduling algorithm.
//! Scheduler configuration: the top-level server configuration and the scheduler core configuration
//! that selects the scheduling algorithm.

use std::num::NonZeroUsize;

use serde::Deserialize;
use spider_utils::config::EndpointConfig;

use crate::{
core::SchedulerCore,
core_impl::RoundRobinConfig,
dispatch_queue::DispatchQueueSink,
runtime::RuntimeConfig,
storage_client::SchedulerStorageClient,
};

/// Top-level configuration for the scheduler gRPC server.
///
/// Wraps the scheduler [`RuntimeConfig`] (which also supplies the gRPC listen `host`/`port`) and
/// adds the storage endpoint and connection-pool size that [`crate::create_runtime`] deliberately
/// leaves out, since it receives the storage client as a parameter.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is your judgment to keep it, or you just missed it: this part is 100% AI-generated and it should be removed.

#[derive(Clone, Debug, Deserialize)]
pub struct ServerConfig {
/// The storage gRPC endpoint the scheduler registers with and polls for ready tasks.
pub storage_endpoint: EndpointConfig,

/// The number of connections per pool used to reach the storage service.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have an example of how to document this, right?

/// The number of connections each gRPC client pool eagerly establishes.

pub storage_connection_pool_size: NonZeroUsize,

/// The scheduler runtime configuration (also supplies the gRPC listen host/port).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think (also supplies the gRPC listen host/port). is a good docstring?
It's expected that this kind of docstring is reviewed as part of your self-review process.

pub runtime: RuntimeConfig,
}

/// The configuration that selects and configures the scheduler core's scheduling algorithm.
#[derive(Clone, Debug, Deserialize)]
#[serde(rename_all = "snake_case")]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ pub enum ExecutionManagerRegistryError {
EmNotFound(ExecutionManagerId),
}

#[derive(Clone, Deserialize)]
#[derive(Clone, Debug, Deserialize)]
pub struct ExecutionManagerRegistryConfig {
/// The time, in seconds, that an execution manager is considered dead without receiving any
/// heartbeat.
Expand Down
Loading
Loading