Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
80 changes: 59 additions & 21 deletions crates/service/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright 2023-, Edge & Node, GraphOps, and Semiotic Labs.
// SPDX-License-Identifier: Apache-2.0

use std::convert::Infallible;

use anyhow::Error;
use axum::{
response::{IntoResponse, Response},
Expand All @@ -9,6 +11,8 @@ use axum::{
use indexer_monitor::EscrowAccountsError;
use reqwest::StatusCode;
use serde::Serialize;
use tap_core::receipt::ReceiptError;
use tap_core::Error as TapError;
use thegraph_core::DeploymentId;
use thiserror::Error;

Expand All @@ -25,31 +29,37 @@ pub enum IndexerServiceError {
SerializationError(#[from] serde_json::Error),

#[error("Issues with provided receipt: {0}")]
ReceiptError(#[from] tap_core::Error),

TapCoreError(#[from] tap_core::Error),
#[error("There was an error while accessing escrow account: {0}")]
EscrowAccount(#[from] EscrowAccountsError),
}

impl StatusCodeExt for IndexerServiceError {
fn status_code(&self) -> StatusCode {
use IndexerServiceError as E;
match &self {
E::TapCoreError(ref error) => match error {
TapError::SignatureError(_)
| TapError::ReceiptError(ReceiptError::CheckFailure(_)) => StatusCode::BAD_REQUEST,
_ => StatusCode::INTERNAL_SERVER_ERROR,
},
E::EscrowAccount(_) | E::ReceiptNotFound => StatusCode::PAYMENT_REQUIRED,
E::DeploymentIdNotFound => StatusCode::INTERNAL_SERVER_ERROR,
E::AxumError(_) | E::SerializationError(_) => StatusCode::BAD_GATEWAY,
}
}
}

impl IntoResponse for IndexerServiceError {
fn into_response(self) -> Response {
use IndexerServiceError::*;

#[derive(Serialize)]
struct ErrorResponse {
message: String,
}

let status = match self {
ReceiptError(_) | EscrowAccount(_) => StatusCode::BAD_REQUEST,
ReceiptNotFound => StatusCode::PAYMENT_REQUIRED,
DeploymentIdNotFound => StatusCode::INTERNAL_SERVER_ERROR,
AxumError(_) => StatusCode::INTERNAL_SERVER_ERROR,
SerializationError(_) => StatusCode::BAD_REQUEST,
};
tracing::error!(%self, "An IndexerServiceError occoured.");
(
status,
self.status_code(),
Json(ErrorResponse {
message: self.to_string(),
}),
Expand All @@ -72,22 +82,50 @@ pub enum SubgraphServiceError {
QueryForwardingError(reqwest::Error),
}

impl From<&SubgraphServiceError> for StatusCode {
fn from(err: &SubgraphServiceError) -> Self {
impl StatusCodeExt for SubgraphServiceError {
fn status_code(&self) -> StatusCode {
use SubgraphServiceError::*;
match err {
InvalidStatusQuery(_) => StatusCode::BAD_REQUEST,
UnsupportedStatusQueryFields(_) => StatusCode::BAD_REQUEST,
StatusQueryError(_) => StatusCode::INTERNAL_SERVER_ERROR,
InvalidDeployment(_) => StatusCode::BAD_REQUEST,
QueryForwardingError(_) => StatusCode::INTERNAL_SERVER_ERROR,
match self {
InvalidStatusQuery(_) | UnsupportedStatusQueryFields(_) => StatusCode::BAD_REQUEST,
InvalidDeployment(_) => StatusCode::INTERNAL_SERVER_ERROR,
StatusQueryError(_) => StatusCode::BAD_GATEWAY,
QueryForwardingError(_) => StatusCode::SERVICE_UNAVAILABLE,
}
}
}

// Tell axum how to convert `SubgraphServiceError` into a response.
impl IntoResponse for SubgraphServiceError {
fn into_response(self) -> Response {
(StatusCode::from(&self), self.to_string()).into_response()
(self.status_code(), self.to_string()).into_response()
}
}

pub trait StatusCodeExt {
fn status_code(&self) -> StatusCode;
}

impl<T> StatusCodeExt for Response<T> {
fn status_code(&self) -> StatusCode {
self.status()
}
}

impl<T, E> StatusCodeExt for Result<T, E>
where
T: StatusCodeExt,
E: StatusCodeExt,
{
fn status_code(&self) -> StatusCode {
match self {
Ok(t) => t.status_code(),
Err(e) => e.status_code(),
}
}
}

impl StatusCodeExt for Infallible {
fn status_code(&self) -> StatusCode {
unreachable!()
}
}
12 changes: 1 addition & 11 deletions crates/service/src/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,7 @@ lazy_static! {
pub static ref HANDLER_HISTOGRAM: HistogramVec = register_histogram_vec!(
"indexer_query_handler_seconds",
"Histogram for default indexer query handler",
&["deployment", "allocation", "sender"]
).unwrap();

/// Metric registered in global registry for
/// Failed queries to handler
///
/// Labels: "deployment"
pub static ref HANDLER_FAILURE: CounterVec = register_counter_vec!(
"indexer_query_handler_failed_total",
"Failed queries to handler",
&["deployment"]
&["deployment", "allocation", "sender", "status_code"]
).unwrap();

/// Metric registered in global registry for
Expand Down
19 changes: 13 additions & 6 deletions crates/service/src/middleware/attestation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ use thegraph_core::Attestation;

use indexer_attestation::AttestationSigner;

use crate::error::StatusCodeExt;

#[derive(Clone)]
pub enum AttestationInput {
Attestable { req: String },
Expand Down Expand Up @@ -83,15 +85,20 @@ pub enum AttestationError {
SerializationError(#[from] serde_json::Error),
}

impl IntoResponse for AttestationError {
fn into_response(self) -> Response {
impl StatusCodeExt for AttestationError {
fn status_code(&self) -> StatusCode {
match self {
AttestationError::CouldNotFindSigner
| AttestationError::AxumError(_)
AttestationError::CouldNotFindSigner => StatusCode::INTERNAL_SERVER_ERROR,
AttestationError::AxumError(_)
| AttestationError::FromUtf8Error(_)
| AttestationError::SerializationError(_) => StatusCode::INTERNAL_SERVER_ERROR,
| AttestationError::SerializationError(_) => StatusCode::BAD_GATEWAY,
}
.into_response()
}
}

impl IntoResponse for AttestationError {
fn into_response(self) -> Response {
self.status_code().into_response()
}
}

Expand Down
3 changes: 2 additions & 1 deletion crates/service/src/middleware/labels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,9 @@ pub async fn labels_middleware(mut request: Request, next: Next) -> Response {
let labels: MetricLabels = Arc::new(SenderAllocationDeploymentLabels {
sender,
allocation,
deployment_id,
deployment_id: deployment_id.clone(),
});

request.extensions_mut().insert(labels);

next.run(request).await
Expand Down
Loading
Loading