Skip to content

Commit

Permalink
Improve error handling from FFI errors (#180)
Browse files Browse the repository at this point in the history
* Update to use improved error handling on FFI calls

* Update CHANGELOG.md
  • Loading branch information
Søren Schwartz authored Feb 5, 2024
1 parent 4bd9ae1 commit 3eadf9e
Show file tree
Hide file tree
Showing 10 changed files with 43 additions and 108 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Application.Aggregates.Contract.Entities;
using Application.Api.GraphQL.EfCore;
using Application.Configurations;
using Application.Observability;
using Application.Resilience;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using Application.Aggregates.Contract.Entities;
using Application.Api.GraphQL.EfCore;
using Application.Configurations;
using Application.Observability;
using Application.Resilience;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Threading.Tasks;
using System.Transactions;
using Application.Api.GraphQL.EfCore;
using Microsoft.EntityFrameworkCore;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
using Application.Aggregates.Contract;
using Application.Aggregates.Contract.Entities;
using Application.Api.GraphQL.Bakers;
using Application.Exceptions;
using Concordium.Sdk.Exceptions;
using Concordium.Sdk.Interop;
using Concordium.Sdk.Types;
using HotChocolate.Types;
using Serilog.Context;
Expand Down Expand Up @@ -212,30 +213,20 @@ string instigator
var deserializeEvent = new ContractEvent(Convert.FromHexString(eventAsHex)).GetDeserializeEvent(versionedModuleSchema, new ContractIdentifier(contractName));
events[i] = deserializeEvent.ToString();
}
catch (Exception e)
catch (SchemaJsonException e)
{
var error = InteropErrorExtensions.From(e.Message);
if (error == InteropError.Undefined)
Observability.ApplicationMetrics.IncInteropErrors($"{instigator}.{nameof(GetParsedEvents)}", e.SchemaJsonResult);
switch (e.SchemaJsonResult)
{
throw;
}
Observability.ApplicationMetrics.IncInteropErrors($"{instigator}.{nameof(GetParsedEvents)}", error);
switch (error)
{
case InteropError.EventNotSupported:
case SchemaJsonResult.VersionedSchemaErrorEventNotSupported:
logger.Debug(e, "Event's from {ContractName} on {Module} not supported", contractName, moduleReferenceEvent.ModuleReference);
break;
case InteropError.NoEventInContract:
case SchemaJsonResult.VersionedSchemaErrorNoEventInContract:
logger.Debug(e, "Event's from {ContractName} not in schema on {Module}", contractName, moduleReferenceEvent.ModuleReference);
break;
case InteropError.Deserialization:
case SchemaJsonResult.JsonError:
logger.Debug(e, "Error when parsing {Event} from {ContractName} on {Module}", eventsAsHex[i], contractName, moduleReferenceEvent.ModuleReference);
break;
case InteropError.EmptyMessage:
case InteropError.NoReceiveInContract:
case InteropError.NoParamsInReceive:
case InteropError.NoContractInModule:
case InteropError.Undefined:
default:
logger.Error(e, "Error when parsing events from {ContractName} on {Module}", contractName, moduleReferenceEvent.ModuleReference);
break;
Expand Down
2 changes: 1 addition & 1 deletion backend/Application/Application.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ConcordiumNetSdk" Version="4.2.1" />
<PackageReference Include="ConcordiumNetSdk" Version="4.3.1" />
<PackageReference Include="Dapper" Version="2.0.123" />
<PackageReference Include="dbup-postgresql" Version="4.5.0" />
<PackageReference Include="HotChocolate.AspNetCore" Version="13.5.1" />
Expand Down
62 changes: 0 additions & 62 deletions backend/Application/Exceptions/InteropError.cs

This file was deleted.

14 changes: 14 additions & 0 deletions backend/Application/Exceptions/SchemaJsonResultExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
using System.Collections.Concurrent;
using Concordium.Sdk.Interop;

namespace Application.Exceptions;

internal static class SchemaJsonResultExtensions
{
private static readonly ConcurrentDictionary<SchemaJsonResult, string> Cache = new();

internal static string ToStringCached(this SchemaJsonResult value)
{
return Cache.GetOrAdd(value, value.ToString());
}
}
18 changes: 10 additions & 8 deletions backend/Application/Observability/ApplicationMetrics.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Text;
using Application.Aggregates.Contract.Types;
using Application.Exceptions;
using Concordium.Sdk.Interop;
using HotChocolate.Execution;
using Microsoft.Extensions.ObjectPool;
using Prometheus;
Expand All @@ -18,15 +19,15 @@ internal static class ApplicationMetrics
LabelNames = new[] { "process", "source", "exception" }
}
);

private static readonly Gauge ProcessReadHeight = Metrics.CreateGauge(
"import_process_read_height",
"Max height read by an import process",
new GaugeConfiguration
{
LabelNames = new []{"process", "data_source"}
LabelNames = new[] { "process", "data_source" }
});

private static readonly Histogram GraphQlRequestDuration = Metrics.CreateHistogram(
"graphql_request_duration_seconds",
"Duration of GraphQl in seconds",
Expand Down Expand Up @@ -71,15 +72,15 @@ internal static void IncAccountCreated(int accountsCreated)
TotalAccountCreated
.Inc(accountsCreated);
}

internal static void SetReadHeight(double value, string processIdentifier, ImportSource source)
{
ProcessReadHeight
.WithLabels(processIdentifier, source.ToStringCached())
.Set(value);
}

internal static void IncInteropErrors(string instigator, InteropError error)
internal static void IncInteropErrors(string instigator, SchemaJsonResult error)
{
InteropErrors
.WithLabels(instigator, error.ToStringCached())
Expand All @@ -92,7 +93,7 @@ internal static void IncRetryPolicyExceptions(string process, Exception exceptio
.WithLabels(process, PrettyPrintException(exception))
.Inc();
}

internal class DurationMetric : IDisposable
{
private Exception? _exception;
Expand All @@ -117,7 +118,7 @@ public void Dispose()
AddProcessDuration(_time.Elapsed, _process, _source, _exception);
}
}

internal class GraphQlDurationMetric : IDisposable
{
/// <summary>
Expand All @@ -143,7 +144,7 @@ internal void SetException(Exception ex)
{
_exception = PrettyPrintException(ex);
}

public void Dispose()
{
_activity.Stop();
Expand Down Expand Up @@ -223,6 +224,7 @@ private static string PrettyPrintException(Exception ex)
{
name = name[..indexOfGenericCount];
}

var typeArguments = string.Join(",", type.GenericTypeArguments.Select(t => t.Name));

return $"{name}<{typeArguments}>";
Expand Down
26 changes: 9 additions & 17 deletions backend/Application/Types/ReceiveName.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Application.Aggregates.Contract.Exceptions;
using Application.Exceptions;
using Concordium.Sdk.Exceptions;
using Concordium.Sdk.Interop;
using Concordium.Sdk.Types;

namespace Application.Types;
Expand Down Expand Up @@ -35,32 +36,23 @@ string instigator

return message.ToString();
}
catch (Exception e)
catch (SchemaJsonException e)
{
var error = InteropErrorExtensions.From(e.Message);
if (error == InteropError.Undefined)
Observability.ApplicationMetrics.IncInteropErrors($"{instigator}.{nameof(DeserializeMessage)}", e.SchemaJsonResult);
switch (e.SchemaJsonResult)
{
throw;
}
Observability.ApplicationMetrics.IncInteropErrors($"{instigator}.{nameof(DeserializeMessage)}", error);
switch (error)
{
case InteropError.Deserialization:
case SchemaJsonResult.JsonError:
logger.Debug(e, "Error when parsing {Message} from {ContractName} on {Module} at {Entrypoint}", messageAsHex, contractName, moduleReference, entrypoint);
break;
case InteropError.NoReceiveInContract:
case SchemaJsonResult.VersionedSchemaErrorNoReceiveInContract:
logger.Debug(e, "{Entrypoint} not found in schema. Issue when parsing {Message} from {ContractName} on {Module}", entrypoint, messageAsHex, contractName, moduleReference);
break;
case InteropError.NoParamsInReceive:
case SchemaJsonResult.VersionedSchemaErrorNoParamsInReceive:
logger.Debug(e, "{Entrypoint} does not contain parameter in schema. Issue when parsing {Message} from {ContractName} on {Module}", entrypoint, messageAsHex, contractName, moduleReference);
break;
case InteropError.NoContractInModule:
case SchemaJsonResult.VersionedSchemaErrorNoContractInModule:
logger.Debug(e, "{ContractName} not in {Module}. Issue when parsing {Message} on {Entrypoint}", contractName, moduleReference, messageAsHex, entrypoint);
break;
case InteropError.Undefined:
case InteropError.EmptyMessage:
case InteropError.EventNotSupported:
case InteropError.NoEventInContract:
default:
logger.Error(e, "Error when parsing {Message} from {ContractName} on {Module} at {Entrypoint}", messageAsHex, contractName, moduleReference, entrypoint);
break;
Expand Down
1 change: 1 addition & 0 deletions backend/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
## Unreleased changes
- Updated
- Handle FFI errors through the use of error codes rather than string comparison.
- Token view on account details page now sort tokens by contract- index, subindex and token id.

## 1.8.8
Expand Down

0 comments on commit 3eadf9e

Please sign in to comment.