diff --git a/.github/workflows/_graph_proxy_container.yaml b/.github/workflows/_graph_proxy_container.yaml index 2b9e0b85e..2f76053ab 100644 --- a/.github/workflows/_graph_proxy_container.yaml +++ b/.github/workflows/_graph_proxy_container.yaml @@ -35,6 +35,7 @@ jobs: images: ${{ env.IMAGE_REPOSITORY }} tags: | type=raw,value=${{ steps.tags.outputs.version }} + type=raw,value=${{ github.ref_name }} type=raw,value=latest - name: Set up Docker Buildx @@ -47,7 +48,8 @@ jobs: context: backend file: backend/Dockerfile.graph-proxy target: deploy - push: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/graph-proxy@') }} + #push: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/graph-proxy@') }} + push: ${{ github.event_name == 'push' && (github.ref_type == 'branch' || startsWith(github.ref, 'refs/tags/graph-proxy@')) }} load: ${{ !(github.event_name == 'push' && startsWith(github.ref, 'refs/tags/graph-proxy@')) }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/backend/graph-proxy/src/graphql/mod.rs b/backend/graph-proxy/src/graphql/mod.rs index 76f97543a..f6ecbe511 100644 --- a/backend/graph-proxy/src/graphql/mod.rs +++ b/backend/graph-proxy/src/graphql/mod.rs @@ -116,7 +116,9 @@ pub async fn graphql_handler( auth_token_header: Option>>, request: GraphQLRequest, ) -> GraphQLResponse { + let start = std::time::Instant::now(); let query = request.into_inner(); + let mut request_type = "unparseable"; if let Ok(query) = parse_query(&query.query) { let operation = query.operations; @@ -130,19 +132,24 @@ pub async fn graphql_handler( .map(|operation| operation.1.node.ty) .collect(), }; + let mut has_mutation = false; for operation in operations { match operation { async_graphql::parser::types::OperationType::Query => state .metrics_state .total_requests .add(1, &[KeyValue::new("request_type", "query")]), - async_graphql::parser::types::OperationType::Mutation => state - .metrics_state - .total_requests - .add(1, &[KeyValue::new("request_type", "mutation")]), + async_graphql::parser::types::OperationType::Mutation => { + has_mutation = true; + state + .metrics_state + .total_requests + .add(1, &[KeyValue::new("request_type", "mutation")]) + } async_graphql::parser::types::OperationType::Subscription => {} }; } + request_type = if has_mutation { "mutation" } else { "query" }; } else { state .metrics_state @@ -151,7 +158,22 @@ pub async fn graphql_handler( }; let auth_token = auth_token_header.map(|header| header.0); - state.schema.execute(query.data(auth_token)).await.into() + // state.schema.execute(query.data(auth_token)).await.into() + let response = state.schema.execute(query.data(auth_token)).await; + let elapsed_ms = start.elapsed().as_secs_f64() * 1000.0; + let status = if response.errors.is_empty() { + "ok" + } else { + "error" + }; + state.metrics_state.request_duration_ms.record( + elapsed_ms, + &[ + KeyValue::new("request_type", request_type), + KeyValue::new("status", status), + ], + ); + response.into() } lazy_static! { diff --git a/backend/graph-proxy/src/graphql/subscription.rs b/backend/graph-proxy/src/graphql/subscription.rs index eeb3fcb31..74a4fad2c 100644 --- a/backend/graph-proxy/src/graphql/subscription.rs +++ b/backend/graph-proxy/src/graphql/subscription.rs @@ -53,6 +53,8 @@ struct WatchEvent { /// Error returned by API error: Option, } + +/// Get authentication token fn get_auth_token(ctx: &Context<'_>) -> anyhow::Result { ctx.data_unchecked::>>() .as_ref() @@ -203,6 +205,7 @@ impl WorkflowsSubscription { } } +/// message for StreamError #[derive(Debug, Deserialize)] struct StreamError { /// The message associated with the error diff --git a/backend/graph-proxy/src/graphql/workflows.rs b/backend/graph-proxy/src/graphql/workflows.rs index 030db2aeb..57e97b1c2 100644 --- a/backend/graph-proxy/src/graphql/workflows.rs +++ b/backend/graph-proxy/src/graphql/workflows.rs @@ -121,6 +121,7 @@ impl Workflow { } } +/// Metadata for a workflow #[derive(Debug)] pub(super) struct Metadata { /// The name given to the workflow, unique within a given visit @@ -379,6 +380,7 @@ impl Artifact<'_> { } } +/// Get filename of the artifact in s3 bucket fn artifact_filename( manifest: &IoArgoprojWorkflowV1alpha1Artifact, ) -> Result<&str, WorkflowParsingError> { @@ -471,6 +473,7 @@ impl Task { } } +/// Fetch missing task information async fn fetch_missing_task_info( mut url: Url, token: Option>, diff --git a/backend/graph-proxy/src/metrics.rs b/backend/graph-proxy/src/metrics.rs index e61ed555f..75ff02de8 100644 --- a/backend/graph-proxy/src/metrics.rs +++ b/backend/graph-proxy/src/metrics.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use opentelemetry::metrics::{Counter, MeterProvider}; +use opentelemetry::metrics::{Counter, Histogram, MeterProvider}; use opentelemetry_sdk::metrics::SdkMeterProvider; /// Thread-safe wrapper for OTEL metrics @@ -11,6 +11,8 @@ pub type MetricsState = Arc; pub struct Metrics { /// Total requests on all routes pub total_requests: Counter, + /// Request duration on every request + pub request_duration_ms: Histogram, } impl Metrics { @@ -23,6 +25,15 @@ impl Metrics { .with_description("The total requests on all routes made since the last restart.") .build(); - Metrics { total_requests } + let request_duration_ms = meter + .f64_histogram("graph_proxy_request_duration_ms") + .with_description("GraphQL request duration") + .with_unit("ms") + .build(); + + Metrics { + total_requests, + request_duration_ms, + } } }