Skip to content

feat(observability): API health checks + GraphQL #3514

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 118 commits into from
Closed
Changes from 112 commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
20ac3a2
Update mod.rs
leebenson Aug 18, 2020
c2cbbd0
Merge branch 'master' into leebenson/api
leebenson Aug 19, 2020
97197d6
Merge branch 'master' into leebenson/api
leebenson Aug 19, 2020
6c288cc
config diff
leebenson Aug 19, 2020
897bbe1
docs(http sink): Fix default for rate_limit_num (#3498)
jszwedko Aug 19, 2020
6b4ee1e
chore: remove tower:0.1 (#3481)
fanatid Aug 19, 2020
e2f7e7f
fix(sinks): Wrap StreamSink around TcpSink (#3495)
juchiast Aug 19, 2020
9cf5710
chore(topology): Wait for detached sink to finish (#3450)
ktff Aug 19, 2020
52d0ae6
chore(docker source): Provision a /var/lib/vector in docker releases …
Hoverbear Aug 19, 2020
01d4cb0
enhancement: Add events for starting, stopping, and reloading (#3476)
ktff Aug 19, 2020
d9aa9ff
enhancement: Add Heartbeat (#3502)
ktff Aug 20, 2020
2b64d39
wip
leebenson Aug 20, 2020
76c850f
chore(add_tags transform): Add events to add_tags transform (#3504)
Hoverbear Aug 20, 2020
2f1bb86
chore(deps): bump pin-project from 0.4.22 to 0.4.23 (#3294)
dependabot[bot] Aug 20, 2020
ccbab9b
chore(deps): bump indexmap from 1.3.1 to 1.5.1 (#3380)
dependabot[bot] Aug 20, 2020
b3f512c
graphql init
leebenson Aug 21, 2020
f5ebec8
server.stop()
leebenson Aug 21, 2020
379ee14
api -> lib/api
leebenson Aug 21, 2020
691bbd8
minor cleanup
leebenson Aug 21, 2020
41272c6
minor cleanup
leebenson Aug 21, 2020
32da59d
Merge branch 'master' into leebenson/api
leebenson Aug 21, 2020
dde38ab
Merge branch 'master' into leebenson/api
leebenson Aug 21, 2020
18abf6e
reset warp
leebenson Aug 21, 2020
8ae3fb3
reset warp
leebenson Aug 21, 2020
1ca1a25
feat: Allow configuring flags via env vars (#2149)
MOZGIII Aug 21, 2020
ad19a3a
Merge branch 'master' into leebenson/api
leebenson Aug 22, 2020
496649c
Merge branch 'master' into leebenson/api
leebenson Aug 22, 2020
c1ab928
heartbeat subscription
leebenson Aug 22, 2020
5fe26f6
heartbeat subscription
leebenson Aug 22, 2020
3278d14
async-graphql
leebenson Aug 23, 2020
14330c8
async-graphql
leebenson Aug 23, 2020
7e6ea67
appease clippy
leebenson Aug 23, 2020
c46039e
appease clippy
leebenson Aug 23, 2020
f0f4b11
enhancement(file sink): Add support for gzip compression (#3373)
perfectayush Aug 23, 2020
3148415
docs(file sink): Add `compression` option to the `file` source (#3536)
binarylogic Aug 23, 2020
c0bf90f
chore(internal docs): Added some error checking for Make scripts (#3533)
jamtur01 Aug 24, 2020
445f03b
chore: less work on shutdown test (#3526)
fanatid Aug 24, 2020
0659541
feature="api"
leebenson Aug 24, 2020
ade1c8e
feature="api"
leebenson Aug 24, 2020
acf7458
Merge branch 'master' into leebenson/api
leebenson Aug 24, 2020
8c54dba
Merge branch 'master' into leebenson/api
leebenson Aug 24, 2020
2d87021
Update Cargo.lock
leebenson Aug 24, 2020
9c98df8
Update Cargo.lock
leebenson Aug 24, 2020
a6f7023
Update config
leebenson Aug 24, 2020
d58fb5f
Update config
leebenson Aug 24, 2020
24ae20e
Update Cargo.toml
leebenson Aug 24, 2020
a1ef3ee
Update Cargo.toml
leebenson Aug 24, 2020
ea192f5
clippy
leebenson Aug 24, 2020
d080f93
clippy
leebenson Aug 24, 2020
f4359d3
chore(deps): update bollard from 0.7.1 to 0.8.0 (#3534)
fanatid Aug 24, 2020
274f6ff
chore(deps): bump rusoto from 0.44.0 to 0.45.0 (#3527)
fanatid Aug 24, 2020
6588ed2
fix(statsd sink): Handle Absolute kind for values other than Gauge. (…
StephenWakely Aug 24, 2020
f9a9a3e
docs: Correct in_flight_limit default in docs
binarylogic Aug 24, 2020
21f2a49
docs(external docs): Some grammar and structure edits to .meta conten…
jamtur01 Aug 24, 2020
273cfc8
chore: Add .meta/links.toml
binarylogic Aug 25, 2020
bfe3a2d
chore: Regenerate vector.spec.toml
binarylogic Aug 25, 2020
d67f40d
chore(deps): bump getset from 0.1.0 to 0.1.1 (#3296)
dependabot[bot] Aug 25, 2020
27f52ca
Added support for the ci-condition: skip label (#3539)
jamtur01 Aug 25, 2020
6db6ae5
Update semantic.yml
jamtur01 Aug 25, 2020
5d2c83e
feat(geoip transform): ASN/ISP database support (#3265)
markonen Aug 25, 2020
33860b6
enhancement(file sink): Sync all data before finishing (#3475)
ktff Aug 25, 2020
979c09a
graphql metrics
leebenson Aug 25, 2020
d9dc54e
graphql metrics
leebenson Aug 25, 2020
3069e08
chore: add more tokio::test (#3505)
fanatid Aug 25, 2020
fd60004
enhancement(json_parser transform): Enhance instrumentation (#3521)
bruceg Aug 25, 2020
4661aa5
enhancement(socket source): Add and unify events (#3486)
bruceg Aug 25, 2020
6d44bf2
Merge branch 'master' into leebenson/api
leebenson Aug 25, 2020
fcd52ea
Merge branch 'master' into leebenson/api
leebenson Aug 25, 2020
9a8b3a9
remove context
leebenson Aug 25, 2020
5992a69
remove context
leebenson Aug 25, 2020
494b00f
chore: Add k8s related code parts to CODEOWNERS (#3562)
MOZGIII Aug 25, 2020
cde8e77
chore(file source): Multiline config extract (#3466)
MOZGIII Aug 25, 2020
f19a77a
enhancement(regex_parser transform): Enhance instrumentation (#3523)
bruceg Aug 25, 2020
c16e7cd
fix: Fixed language on code fence in CONTRIBUTING.md (#3560)
jamtur01 Aug 25, 2020
10c9235
metrics interface
leebenson Aug 25, 2020
f7da2b9
metrics interface
leebenson Aug 25, 2020
a120404
chore(add_fields transform): Add events to add_fields transform (#3…
Hoverbear Aug 25, 2020
9ccd579
enhancement(grok_parser transform): Add internal events (#3553)
bruceg Aug 25, 2020
5cc20ea
fix: Remove quiet verbose options as environment variables to stop te…
jamtur01 Aug 25, 2020
fae8d1f
Merge branch 'master' into leebenson/api
leebenson Aug 26, 2020
e007b4a
Merge branch 'master' into leebenson/api
leebenson Aug 26, 2020
11b9805
tidy up
leebenson Aug 26, 2020
2ad63ee
tidy up
leebenson Aug 26, 2020
e4ff93f
Update src/api/server.rs
leebenson Aug 26, 2020
c976bcd
Update src/api/server.rs
leebenson Aug 26, 2020
cf7ed9c
conditional playground
leebenson Aug 26, 2020
0c150f2
conditional playground
leebenson Aug 26, 2020
cbf18f7
Update server.rs
leebenson Aug 26, 2020
207ea58
Update server.rs
leebenson Aug 26, 2020
025fe2f
tidy up schema
leebenson Aug 26, 2020
e8fb167
tidy up schema
leebenson Aug 26, 2020
0db1bbf
fix(performance): Only update auto-concurrency RTT from OK responses …
bruceg Aug 26, 2020
1bcf40c
chore: more async functions in tests (#3578)
fanatid Aug 26, 2020
ceab40f
bump async-graphql; stitch schema
leebenson Aug 27, 2020
b3e5aeb
bump async-graphql; stitch schema
leebenson Aug 27, 2020
77328f8
Merge branch 'master' into leebenson/api
leebenson Aug 27, 2020
794e9a1
Merge branch 'master' into leebenson/api
leebenson Aug 27, 2020
67df981
config test; fix lint
leebenson Aug 27, 2020
39f7f7b
config test; fix lint
leebenson Aug 27, 2020
edf7d81
config test
leebenson Aug 27, 2020
db84b43
config test
leebenson Aug 27, 2020
af88a75
ok /health
leebenson Aug 27, 2020
14f755d
ok /health
leebenson Aug 27, 2020
9caeced
health test redux
leebenson Aug 27, 2020
865a39c
health test redux
leebenson Aug 27, 2020
7a30886
Merge branch 'leebenson/api' of github.com:timberio/vector into leebe…
leebenson Aug 27, 2020
951ec51
Merge branch 'master' into leebenson/api
leebenson Aug 27, 2020
fd738c1
Create Cargo.lock
leebenson Aug 27, 2020
c7889eb
Merge branch 'master' into leebenson/api
leebenson Aug 28, 2020
21be95f
mod tests
leebenson Aug 28, 2020
8633879
clippy
leebenson Aug 28, 2020
cf60baa
fix kafka
leebenson Aug 28, 2020
542b328
rustfmt
leebenson Aug 28, 2020
337d9a5
Check if playground is enabled statically (#3618)
MOZGIII Aug 28, 2020
37ef346
fix 404
leebenson Aug 28, 2020
6c27584
tidy routes
leebenson Aug 28, 2020
c07eda0
tidy not_found
leebenson Aug 28, 2020
4ae9402
fix route comment
leebenson Aug 28, 2020
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
550 changes: 474 additions & 76 deletions Cargo.lock

Large diffs are not rendered by default.

19 changes: 13 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ members = [
"lib/tracing-limit",
"lib/vector-wasm",
"lib/k8s-test-framework",
"lib/prometheus-parser",
"lib/prometheus-parser"
]

[dependencies]
@@ -91,6 +91,10 @@ prost-types = "0.6.1"
goauth = { version = "0.7.1", optional = true }
smpl_jwt = { version = "0.5.0", optional = true }

# API
async-graphql = { version = "1.17.11", optional = true }
async-graphql-warp = { version = "1.17.3", optional = true }

# External libs
derivative = "1.0"
chrono = { version = "0.4.6", features = ["serde"] }
@@ -131,7 +135,7 @@ uuid = { version = "0.7", features = ["serde", "v4"], optional = true }
exitcode = "1.1.2"
snafu = { version = "0.6", features = ["futures-01", "futures"] }
url = "2.1.1"
base64 = { version = "0.10.1", optional = true }
base64 = { version = "0.12.3", optional = true }
bollard = { version = "0.8.0", optional = true }
listenfd = { version = "0.3.3", optional = true }
inventory = "0.1"
@@ -197,13 +201,13 @@ k8s-test-framework = { version = "0.1", path = "lib/k8s-test-framework" }

[features]
# Default features for *-unknown-linux-gnu and *-apple-darwin
default = ["sources", "transforms", "sinks", "vendor-all", "unix", "leveldb-plain", "rdkafka-plain"]
default-musl = ["sources", "transforms", "sinks", "vendor-all", "unix", "leveldb-cmake", "rdkafka-cmake"]
default = ["api", "sources", "transforms", "sinks", "vendor-all", "unix", "leveldb-plain", "rdkafka-plain"]
default-musl = ["api", "sources", "transforms", "sinks", "vendor-all", "unix", "leveldb-cmake", "rdkafka-cmake"]
# Default features for *-unknown-linux-* which make use of `cmake` for dependencies
default-cmake = ["sources", "transforms", "sinks", "vendor-all", "unix", "leveldb-cmake", "rdkafka-cmake"]
default-cmake = ["api", "sources", "transforms", "sinks", "vendor-all", "unix", "leveldb-cmake", "rdkafka-cmake"]
# Default features for *-pc-windows-msvc
# TODO: Enable SASL https://github.com/timberio/vector/pull/3081#issuecomment-659298042
default-msvc = ["sources", "transforms", "sinks", "vendor-openssl", "vendor-libz", "leveldb-cmake", "rdkafka-cmake"]
default-msvc = ["api", "sources", "transforms", "sinks", "vendor-openssl", "vendor-libz", "leveldb-cmake", "rdkafka-cmake"]

# Enables features that work only on systems providing `cfg(unix)`
unix = ["jemallocator"]
@@ -231,6 +235,9 @@ wasm-timings = ["wasm"]
# transforms and sinks should depend on this feature.
kubernetes = ["k8s-openapi", "evmap"]

# Enables the API
api = ["warp", "async-graphql", "async-graphql-warp"]
Copy link
Contributor

Choose a reason for hiding this comment

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

Perhaps we can come up with a more descriptive name for this feature? internal-events-api or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There's probably a better name for this than just 'api', although my starting intention is that this would become the de facto gateway into general UI <-> Vector observability and grow into more than just events.

One current use-case we're planning for, for example, is retrieving/validating Cargo.toml.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

To conclude this point: In the absence of a better name, I'll keep this as api for now. I do think it'll grow to be more than simply metrics, so trying to keep the nomenclature in sync with its function might be a bit tough; this generalisation may be preferred.


# Sources
sources = [
"sources-docker",
13 changes: 13 additions & 0 deletions src/api/handler.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use serde::Serialize;
use warp::reply::json;
use warp::{Rejection, Reply};

#[derive(Serialize)]
struct Health {
ok: bool,
}

// health handler, responds with { ok: true }
pub async fn health() -> Result<impl Reply, Rejection> {
Ok(json(&Health { ok: true }))
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm assuming this will eventually expose the actual health of the Vector instance by querying the health of the different active components?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Probably, yeah. Right now, this just asserts that the GraphQL handler is alive. There's also a /health that returns {"ok": true} + a 200 response.

Copy link
Member

Choose a reason for hiding this comment

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

This could probably be simplified a bit with the serde_json::json macro. Something along the lines of

Ok(json!({"ok": true}))

}
68 changes: 68 additions & 0 deletions src/api/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/// Takes a list of handler expressions and `or`s them together
/// in a balanced tree. That is, instead of `a.or(b).or(c).or(d)`,
/// it produces `(a.or(b)).or(c.or(d))`, thus nesting the types
/// less deeply, which provides improvements in compile time.
///
/// It also applies `::warp::Filter::boxed` to each handler expression
/// when in `debug_assertions` mode, improving compile time further.
//
// The basic list splitting algorithm here is based on this gist:
// https://gist.github.com/durka/9fc479de2555225a787f
// It uses a counter from which two items are removed each time,
// stopping when the counter reaches 0. At each step, one item
// is moved from the left to the right, and thus at the end,
// there will be the same number of items in each list.
//
// The flow is as follows:
// - If there is one handler expression, debug_box it and return.
// - If there is more than one handler expression:
// - First, copy the list into two: the one that will go into the
// right side of the `or`, and one that will serve as a counter.
// Recurse with these separated by semicolons, plus an empty `left`
// list before the first semicolon.
// - Then, as long as there are at least two items in the counter
// list, remove them and move the first item on the right side of
// the first semicolon (`head`) to the left side of the first semicolon.
// - Finally, when there are one or zero items left in the counter,
// move one last item to the left, make the call this macro on both the
// left and right sides, and `or` the two sides together.
//
// For example, balanced_or_tree!(a, b, c, d, e) would take the following steps:
//
// - balanced_or_tree!(a, b, c, d, e)
// - balanced_or_tree!(@internal ; a, b, c, d, e ; a, b, c, d, e) // initialise lists
// - balanced_or_tree!(@internal a ; b, c, d, e ; c, d, e) // move one elem; remove two
// - balanced_or_tree!(@internal a, b ; c, d, e ; e) // now only one elem in counter
// - balanced_or_tree!(a, b, c).or(balanced_or_tree(d, e)) // recurse on each sublist
#[macro_export]
macro_rules! balanced_or_tree {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This macro balances Warp's .or() composition, for faster compilation times. For debug builds, it boxes the response for dynamic dispatch, to improve compilation further.

Copy link
Contributor

Choose a reason for hiding this comment

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

What kind of improvement can we expect from introducing this macro?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is the issue that motivated it. Quote:

I was able to cut debug build times by ~65%, from 6 minutes to 2 minutes, by building a more balanced Or tree of filters

Thought it was worth a crack.

Copy link
Contributor

Choose a reason for hiding this comment

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

Did you test this on vector?

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I would really like to see numbers for our use case before we add such a complex optimization.

// Base case: just a single expression, return it wrapped in `debug_boxed`
($x:expr $(,)?) => { debug_boxed!($x) };
// Multiple expressions: recurse with three lists: left, right and counter.
($($x:expr),+ $(,)?) => {
balanced_or_tree!(@internal ; $($x),+; $($x),+)
// ^ left ^ right ^ counter
};
// Counter 1 or 2; move one more item and recurse on each sublist, and or them together
(@internal $($left:expr),*; $head:expr, $($tail:expr),+; $a:expr $(,$b:expr)?) => {
(balanced_or_tree!($($left,)* $head)).or(balanced_or_tree!($($tail),+))
};
// Counter > 2; move one item from the right to the left and subtract two from the counter
(@internal $($left:expr),*; $head:expr, $($tail:expr),+; $a:expr, $b:expr, $($more:expr),+) => {
balanced_or_tree!(@internal $($left,)* $head; $($tail),+; $($more),+)
};
}

#[cfg(debug_assertions)]
macro_rules! debug_boxed {
($x:expr) => {
::warp::Filter::boxed($x)
};
}

#[cfg(not(debug_assertions))]
macro_rules! debug_boxed {
($x:expr) => {
$x
};
}
7 changes: 7 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[macro_use]
mod macros;
mod handler;
mod schema;
mod server;

pub use server::Server;
40 changes: 40 additions & 0 deletions src/api/schema/health.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use async_graphql::{validators::IntRange, Object, SimpleObject, Subscription};
use chrono::{DateTime, Utc};
use tokio::stream::{Stream, StreamExt};
use tokio::time::Duration;

#[SimpleObject]
pub struct Heartbeat {
utc: DateTime<Utc>,
}

impl Heartbeat {
fn new() -> Self {
Heartbeat { utc: Utc::now() }
}
}

#[derive(Default)]
pub struct HealthQuery;

#[Object]
impl HealthQuery {
/// Returns `true` to denote the GraphQL server is reachable
async fn health(&self) -> bool {
true
}
}

#[derive(Default)]
pub struct HealthSubscription;

#[Subscription]
impl HealthSubscription {
/// Heartbeat, containing the UTC timestamp of the last server-sent payload
async fn heartbeat(
&self,
#[arg(default = 1000, validator(IntRange(min = "100", max = "60_000")))] interval: i32,
) -> impl Stream<Item = Heartbeat> {
tokio::time::interval(Duration::from_millis(interval as u64)).map(|_| Heartbeat::new())
}
}
88 changes: 88 additions & 0 deletions src/api/schema/metrics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
use crate::event::{Event, Metric, MetricValue};
use crate::metrics::{capture_metrics, get_controller};
use async_graphql::{validators::IntRange, Interface, Object, Subscription};
use async_stream::stream;
use chrono::{DateTime, Utc};
use tokio::stream::{Stream, StreamExt};
use tokio::time::Duration;

pub struct EventsProcessed(Metric);

#[Object]
impl EventsProcessed {
/// Metric timestamp
async fn timestamp(&self) -> Option<DateTime<Utc>> {
self.0.timestamp
}

/// Number of events processed
async fn events_processed(&self) -> f64 {
match self.0.value {
MetricValue::Counter { value } => value,
_ => 0.00,
}
}
}

impl Into<EventsProcessed> for Metric {
fn into(self) -> EventsProcessed {
EventsProcessed(self)
}
}

pub struct BytesProcessed(Metric);

#[Object]
impl BytesProcessed {
/// Metric timestamp
async fn timestamp(&self) -> Option<DateTime<Utc>> {
self.0.timestamp
}

/// Number of bytes processed
async fn bytes_processed(&self) -> f64 {
match self.0.value {
MetricValue::Counter { value } => value,
_ => 0.00,
}
}
}

#[Interface(field(name = "timestamp", type = "Option<DateTime<Utc>>"))]
pub enum MetricType {
EventsProcessed(EventsProcessed),
BytesProcessed(BytesProcessed),
}

#[derive(Default)]
pub struct MetricsSubscription;

#[Subscription]
impl MetricsSubscription {
/// Returns all Vector metrics, aggregated at the provided millisecond interval
async fn metrics(
&self,
#[arg(validator(IntRange(min = "100", max = "60_000")))] interval: i32,
) -> impl Stream<Item = MetricType> {
get_metrics(interval).filter_map(|m| match m.name.as_str() {
"events_processed" => Some(MetricType::EventsProcessed(m.into())),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Currently, only events_processed metrics are consumed. This will evolve to accommodate all metrics types, and will likely be consumed via specific queries rather than the generalised get_metrics subscription. I also imagine we'll be able to do additional filtering by params.

Since the design of that is TBD and likely to be covered by RFCs, this is just a meantime demonstration that it works.

_ => None,
})
}
}

/// Returns a stream of `Metric`s, collected at the provided millisecond interval
fn get_metrics(interval: i32) -> impl Stream<Item = Metric> {
let controller = get_controller().unwrap();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rather than treat the API as a sink, I thought it made sense to utilise the 'global' controller directly. This is called per-subscription, at the point of query, and returns a stream that's specific to that one subscription.

I'm using the stream! macro to yield the inner value when the value is of type Event::Metric.

Copy link
Member

Choose a reason for hiding this comment

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

The main reason I'd caution against this is that it ties us pretty directly to the current implementation of metrics and doesn't give us a clear path to exposing non-metric data. The idea of making internal metrics a source is that they become less special (e.g. represented by the same data type as user metrics) and any improvements we make to vector's internal observability tools should help improve our users' ability to handle their own metrics.

Basically, internal metrics as a source was an intentional design decision so let's not sidestep it.

let mut interval = tokio::time::interval(Duration::from_millis(interval as u64));

stream! {
while let _ = interval.tick().await {
Copy link
Member

Choose a reason for hiding this comment

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

This appears to be an infinite loop (Interval::tick cannot fail), so:

Suggested change
while let _ = interval.tick().await {
loop {
interval.tick().await;

for ev in capture_metrics(&controller) {
if let Event::Metric(m) = ev {
yield m
}
}
}
}
}
15 changes: 15 additions & 0 deletions src/api/schema/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
mod health;
mod metrics;

use async_graphql::{EmptyMutation, GQLMergedObject, GQLMergedSubscription, Schema, SchemaBuilder};

#[derive(GQLMergedObject, Default)]
pub struct Query(health::HealthQuery);

#[derive(GQLMergedSubscription, Default)]
pub struct Subscription(health::HealthSubscription, metrics::MetricsSubscription);

/// Build a new GraphQL schema, comprised of Query, Mutation and Subscription types
pub fn build_schema() -> SchemaBuilder<Query, EmptyMutation, Subscription> {
Schema::build(Query::default(), EmptyMutation, Subscription::default())
}
Loading