Skip to content

Commit 14fe520

Browse files
author
Matthew Hawkins
authored
Hot reload operation files and directories (#69)
1 parent c6c4f89 commit 14fe520

File tree

21 files changed

+723
-565
lines changed

21 files changed

+723
-565
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
1616
## [Unreleased]
1717

1818
### 🚀 Features
19+
- The `--operations` argument now supports hot reloading and directory paths. If a directory is specified, all .graphql files in the directory will be loaded as operations. The running server will update when files are added to or removed from the directory. (#69)
1920
- Add an optional `--sse-address` argument to set the bind address of the MCP server. Defaults to 127.0.0.1. (#63)
2021

2122
### 🐛 Fixes

Cargo.lock

Lines changed: 0 additions & 52 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,18 @@ reqwest = { version = "0.12.15", default-features = false, features = [
2222
serde = { version = "1.0.219", features = ["derive"] }
2323
serde_json = "1.0.140"
2424
thiserror = "2.0.12"
25+
tokio = { version = "1.45.0", features = [
26+
"fs",
27+
"io-std",
28+
"macros",
29+
"net",
30+
"rt",
31+
"rt-multi-thread",
32+
"signal",
33+
"sync",
34+
"time",
35+
] }
36+
tokio-stream = "0.1"
2537
tracing = "0.1.41"
2638
tracing-core = "0.1.33"
2739
tracing-subscriber = { version = "0.3.19", features = ["json"] }

crates/apollo-mcp-registry/Cargo.toml

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,13 @@ futures.workspace = true
1717
graphql_client = "0.14.0"
1818
insta.workspace = true
1919
notify = "8.0.0"
20-
parking_lot = "0.12"
2120
reqwest.workspace = true
2221
secrecy = "0.10.3"
2322
serde.workspace = true
2423
serde_json.workspace = true
2524
thiserror.workspace = true
26-
tokio = { version = "1.0", features = [
27-
"fs",
28-
"sync",
29-
"time",
30-
"rt-multi-thread",
31-
"macros",
32-
] }
33-
tokio-stream = "0.1"
25+
tokio.workspace = true
26+
tokio-stream.workspace = true
3427
tower = "0.5.2"
3528
tracing.workspace = true
3629
url = "2.4"

crates/apollo-mcp-registry/src/files.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,12 @@ const DEFAULT_WATCH_DURATION: Duration = Duration::from_millis(100);
2828
///
2929
/// returns: impl Stream<Item=()>
3030
///
31-
pub(crate) fn watch(path: &Path) -> impl Stream<Item = ()> + use<> {
31+
pub fn watch(path: &Path) -> impl Stream<Item = ()> + use<> {
3232
watch_with_duration(path, DEFAULT_WATCH_DURATION)
3333
}
3434

3535
#[allow(clippy::panic)] // TODO: code copied from router contained existing panics
3636
fn watch_with_duration(path: &Path, duration: Duration) -> impl Stream<Item = ()> + use<> {
37-
// Due to the vagaries of file watching across multiple platforms, instead of watching the
38-
// supplied path (file), we are going to watch the parent (directory) of the path.
3937
let config_file_path = PathBuf::from(path);
4038
let watched_path = config_file_path.clone();
4139

@@ -58,6 +56,8 @@ fn watch_with_duration(path: &Path, duration: Duration) -> impl Stream<Item = ()
5856
event.kind,
5957
EventKind::Modify(ModifyKind::Metadata(MetadataKind::WriteTime))
6058
| EventKind::Modify(ModifyKind::Data(DataChange::Any))
59+
| EventKind::Create(_)
60+
| EventKind::Remove(_)
6161
) && event.paths.contains(&watched_path)
6262
{
6363
loop {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
pub(crate) mod files;
1+
pub mod files;
22
pub(crate) mod logging;
33
pub mod uplink;

crates/apollo-mcp-registry/src/uplink.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ use tokio_stream::wrappers::ReceiverStream;
1010
use tower::BoxError;
1111
use url::Url;
1212

13-
pub mod event;
1413
pub mod persisted_queries;
1514
pub mod schema;
1615

@@ -136,7 +135,7 @@ impl Endpoints {
136135
}
137136

138137
/// Configuration for polling Apollo Uplink.
139-
#[derive(Debug, Default)]
138+
#[derive(Clone, Debug, Default)]
140139
pub struct UplinkConfig {
141140
/// The Apollo key: `<YOUR_GRAPH_API_KEY>`
142141
pub apollo_key: SecretString,

crates/apollo-mcp-registry/src/uplink/persisted_queries.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
use graphql_client::GraphQLQuery;
22

3+
pub mod event;
34
mod manifest;
45
mod manifest_poller;
56

67
pub use manifest::FullPersistedQueryOperationId;
78
pub use manifest::ManifestOperation;
89
pub use manifest::PersistedQueryManifest;
910
pub use manifest::SignedUrlChunk;
10-
pub use manifest_poller::ManifestChanged;
1111
pub use manifest_poller::ManifestSource;
12-
pub use manifest_poller::PersistedQueryManifestPoller;
1312
pub use manifest_poller::PersistedQueryManifestPollerState;
1413

1514
use crate::uplink::UplinkRequest;
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
use std::fmt::Debug;
2+
use std::fmt::Formatter;
3+
4+
/// Persisted Query events
5+
pub enum Event {
6+
/// The persisted query manifest was updated
7+
UpdateManifest(Vec<(String, String)>),
8+
}
9+
10+
impl Debug for Event {
11+
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
12+
match self {
13+
Event::UpdateManifest(_) => {
14+
write!(f, "UpdateManifest(<redacted>)")
15+
}
16+
}
17+
}
18+
}

0 commit comments

Comments
 (0)