improves error reporting for discord bot

This commit is contained in:
benbierens 2024-10-18 11:03:05 +02:00
parent e29ffe4f9c
commit 9e842207ab
No known key found for this signature in database
GPG Key ID: 877D2C2E09A22F3A
13 changed files with 101 additions and 33 deletions

View File

@ -4,6 +4,7 @@
{ {
public RewardUsersCommand[] Rewards { get; set; } = Array.Empty<RewardUsersCommand>(); public RewardUsersCommand[] Rewards { get; set; } = Array.Empty<RewardUsersCommand>();
public ChainEventMessage[] EventsOverview { get; set; } = Array.Empty<ChainEventMessage>(); public ChainEventMessage[] EventsOverview { get; set; } = Array.Empty<ChainEventMessage>();
public string[] Errors { get; set; } = Array.Empty<string>();
public bool HasAny() public bool HasAny()
{ {

View File

@ -17,6 +17,8 @@ namespace CodexContractsPlugin.ChainMonitor
void OnSlotFilled(RequestEvent requestEvent, EthAddress host, BigInteger slotIndex); void OnSlotFilled(RequestEvent requestEvent, EthAddress host, BigInteger slotIndex);
void OnSlotFreed(RequestEvent requestEvent, BigInteger slotIndex); void OnSlotFreed(RequestEvent requestEvent, BigInteger slotIndex);
void OnSlotReservationsFull(RequestEvent requestEvent, BigInteger slotIndex); void OnSlotReservationsFull(RequestEvent requestEvent, BigInteger slotIndex);
void OnError(string msg);
} }
public class RequestEvent public class RequestEvent
@ -67,7 +69,11 @@ namespace CodexContractsPlugin.ChainMonitor
private void Apply(ChainEvents events) private void Apply(ChainEvents events)
{ {
if (events.BlockInterval.TimeRange.From < TotalSpan.From) if (events.BlockInterval.TimeRange.From < TotalSpan.From)
throw new Exception("Attempt to update ChainState with set of events from before its current record."); {
var msg = "Attempt to update ChainState with set of events from before its current record.";
handler.OnError(msg);
throw new Exception(msg);
}
log.Log($"ChainState updating: {events.BlockInterval}"); log.Log($"ChainState updating: {events.BlockInterval}");
@ -110,7 +116,7 @@ namespace CodexContractsPlugin.ChainMonitor
private void ApplyEvent(RequestFulfilledEventDTO @event) private void ApplyEvent(RequestFulfilledEventDTO @event)
{ {
var r = FindRequest(@event.RequestId); var r = FindRequest(@event);
if (r == null) return; if (r == null) return;
r.UpdateState(@event.Block.BlockNumber, RequestState.Started); r.UpdateState(@event.Block.BlockNumber, RequestState.Started);
handler.OnRequestFulfilled(new RequestEvent(@event.Block, r)); handler.OnRequestFulfilled(new RequestEvent(@event.Block, r));
@ -118,7 +124,7 @@ namespace CodexContractsPlugin.ChainMonitor
private void ApplyEvent(RequestCancelledEventDTO @event) private void ApplyEvent(RequestCancelledEventDTO @event)
{ {
var r = FindRequest(@event.RequestId); var r = FindRequest(@event);
if (r == null) return; if (r == null) return;
r.UpdateState(@event.Block.BlockNumber, RequestState.Cancelled); r.UpdateState(@event.Block.BlockNumber, RequestState.Cancelled);
handler.OnRequestCancelled(new RequestEvent(@event.Block, r)); handler.OnRequestCancelled(new RequestEvent(@event.Block, r));
@ -126,7 +132,7 @@ namespace CodexContractsPlugin.ChainMonitor
private void ApplyEvent(RequestFailedEventDTO @event) private void ApplyEvent(RequestFailedEventDTO @event)
{ {
var r = FindRequest(@event.RequestId); var r = FindRequest(@event);
if (r == null) return; if (r == null) return;
r.UpdateState(@event.Block.BlockNumber, RequestState.Failed); r.UpdateState(@event.Block.BlockNumber, RequestState.Failed);
handler.OnRequestFailed(new RequestEvent(@event.Block, r)); handler.OnRequestFailed(new RequestEvent(@event.Block, r));
@ -134,7 +140,7 @@ namespace CodexContractsPlugin.ChainMonitor
private void ApplyEvent(SlotFilledEventDTO @event) private void ApplyEvent(SlotFilledEventDTO @event)
{ {
var r = FindRequest(@event.RequestId); var r = FindRequest(@event);
if (r == null) return; if (r == null) return;
r.Hosts.Add(@event.Host, (int)@event.SlotIndex); r.Hosts.Add(@event.Host, (int)@event.SlotIndex);
r.Log($"[{@event.Block.BlockNumber}] SlotFilled (host:'{@event.Host}', slotIndex:{@event.SlotIndex})"); r.Log($"[{@event.Block.BlockNumber}] SlotFilled (host:'{@event.Host}', slotIndex:{@event.SlotIndex})");
@ -143,7 +149,7 @@ namespace CodexContractsPlugin.ChainMonitor
private void ApplyEvent(SlotFreedEventDTO @event) private void ApplyEvent(SlotFreedEventDTO @event)
{ {
var r = FindRequest(@event.RequestId); var r = FindRequest(@event);
if (r == null) return; if (r == null) return;
r.Hosts.RemoveHost((int)@event.SlotIndex); r.Hosts.RemoveHost((int)@event.SlotIndex);
r.Log($"[{@event.Block.BlockNumber}] SlotFreed (slotIndex:{@event.SlotIndex})"); r.Log($"[{@event.Block.BlockNumber}] SlotFreed (slotIndex:{@event.SlotIndex})");
@ -152,7 +158,7 @@ namespace CodexContractsPlugin.ChainMonitor
private void ApplyEvent(SlotReservationsFullEventDTO @event) private void ApplyEvent(SlotReservationsFullEventDTO @event)
{ {
var r = FindRequest(@event.RequestId); var r = FindRequest(@event);
if (r == null) return; if (r == null) return;
r.Log($"[{@event.Block.BlockNumber}] SlotReservationsFull (slotIndex:{@event.SlotIndex})"); r.Log($"[{@event.Block.BlockNumber}] SlotReservationsFull (slotIndex:{@event.SlotIndex})");
handler.OnSlotReservationsFull(new RequestEvent(@event.Block, r), @event.SlotIndex); handler.OnSlotReservationsFull(new RequestEvent(@event.Block, r), @event.SlotIndex);
@ -171,10 +177,23 @@ namespace CodexContractsPlugin.ChainMonitor
} }
} }
private ChainStateRequest? FindRequest(byte[] requestId) private ChainStateRequest? FindRequest(IHasRequestId request)
{ {
var r = requests.SingleOrDefault(r => Equal(r.Request.RequestId, requestId)); var r = requests.SingleOrDefault(r => Equal(r.Request.RequestId, request.RequestId));
if (r == null) log.Log("Unable to find request by ID!"); if (r == null)
{
var blockNumber = "unknown";
if (request is IHasBlock blk)
{
blockNumber = blk.Block.BlockNumber.ToString();
}
var msg = $"Received event of type '{request.GetType()}' in block '{blockNumber}' for request by Id: '{request.RequestId}'. " +
$"Failed to find request. Request creation event not seen! (Tracker start time: {TotalSpan.From})";
log.Error(msg);
handler.OnError(msg);
}
return r; return r;
} }

View File

@ -1,10 +1,5 @@
using GethPlugin; using GethPlugin;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics; using System.Numerics;
using System.Text;
using System.Threading.Tasks;
namespace CodexContractsPlugin.ChainMonitor namespace CodexContractsPlugin.ChainMonitor
{ {
@ -56,5 +51,10 @@ namespace CodexContractsPlugin.ChainMonitor
{ {
foreach (var handler in Handlers) handler.OnSlotReservationsFull(requestEvent, slotIndex); foreach (var handler in Handlers) handler.OnSlotReservationsFull(requestEvent, slotIndex);
} }
public void OnError(string msg)
{
foreach (var handler in Handlers) handler.OnError(msg);
}
} }
} }

View File

@ -36,5 +36,9 @@ namespace CodexContractsPlugin.ChainMonitor
public void OnSlotReservationsFull(RequestEvent requestEvent, BigInteger slotIndex) public void OnSlotReservationsFull(RequestEvent requestEvent, BigInteger slotIndex)
{ {
} }
public void OnError(string msg)
{
}
} }
} }

View File

@ -10,7 +10,12 @@ namespace CodexContractsPlugin.Marketplace
BlockTimeEntry Block { get; set; } BlockTimeEntry Block { get; set; }
} }
public partial class Request : RequestBase, IHasBlock public interface IHasRequestId
{
byte[] RequestId { get; set; }
}
public partial class Request : RequestBase, IHasBlock, IHasRequestId
{ {
[JsonIgnore] [JsonIgnore]
public BlockTimeEntry Block { get; set; } public BlockTimeEntry Block { get; set; }
@ -28,38 +33,38 @@ namespace CodexContractsPlugin.Marketplace
} }
} }
public partial class RequestFulfilledEventDTO : IHasBlock public partial class RequestFulfilledEventDTO : IHasBlock, IHasRequestId
{ {
[JsonIgnore] [JsonIgnore]
public BlockTimeEntry Block { get; set; } public BlockTimeEntry Block { get; set; }
} }
public partial class RequestCancelledEventDTO : IHasBlock public partial class RequestCancelledEventDTO : IHasBlock, IHasRequestId
{ {
[JsonIgnore] [JsonIgnore]
public BlockTimeEntry Block { get; set; } public BlockTimeEntry Block { get; set; }
} }
public partial class RequestFailedEventDTO : IHasBlock public partial class RequestFailedEventDTO : IHasBlock, IHasRequestId
{ {
[JsonIgnore] [JsonIgnore]
public BlockTimeEntry Block { get; set; } public BlockTimeEntry Block { get; set; }
} }
public partial class SlotFilledEventDTO : IHasBlock public partial class SlotFilledEventDTO : IHasBlock, IHasRequestId
{ {
[JsonIgnore] [JsonIgnore]
public BlockTimeEntry Block { get; set; } public BlockTimeEntry Block { get; set; }
public EthAddress Host { get; set; } public EthAddress Host { get; set; }
} }
public partial class SlotFreedEventDTO : IHasBlock public partial class SlotFreedEventDTO : IHasBlock, IHasRequestId
{ {
[JsonIgnore] [JsonIgnore]
public BlockTimeEntry Block { get; set; } public BlockTimeEntry Block { get; set; }
} }
public partial class SlotReservationsFullEventDTO : IHasBlock public partial class SlotReservationsFullEventDTO : IHasBlock, IHasRequestId
{ {
[JsonIgnore] [JsonIgnore]
public BlockTimeEntry Block { get; set; } public BlockTimeEntry Block { get; set; }

View File

@ -17,8 +17,10 @@ namespace BiblioTech.Rewards
this.eventsChannel = eventsChannel; this.eventsChannel = eventsChannel;
} }
public async Task ProcessChainEvents(ChainEventMessage[] eventsOverview) public async Task ProcessChainEvents(ChainEventMessage[] eventsOverview, string[] errors)
{ {
await SendErrorsToAdminChannel(errors);
if (eventsChannel == null || eventsOverview == null || !eventsOverview.Any()) return; if (eventsChannel == null || eventsOverview == null || !eventsOverview.Any()) return;
try try
{ {
@ -34,6 +36,22 @@ namespace BiblioTech.Rewards
} }
} }
private async Task SendErrorsToAdminChannel(string[] errors)
{
try
{
foreach (var error in errors)
{
await Program.AdminChecker.SendInAdminChannel(error);
}
}
catch (Exception exc)
{
log.Error("Failed to send error messages to admin channel. " + exc);
Environment.Exit(1);
}
}
private async Task SendChainEventsInOrder(ChainEventMessage[] eventsOverview, SocketTextChannel eventsChannel, UserData[] users) private async Task SendChainEventsInOrder(ChainEventMessage[] eventsOverview, SocketTextChannel eventsChannel, UserData[] users)
{ {
eventsOverview = eventsOverview.OrderBy(e => e.BlockNumber).ToArray(); eventsOverview = eventsOverview.OrderBy(e => e.BlockNumber).ToArray();

View File

@ -31,7 +31,7 @@ namespace BiblioTech.Rewards
await ProcessRewards(rewards); await ProcessRewards(rewards);
} }
await eventsSender.ProcessChainEvents(rewards.EventsOverview); await eventsSender.ProcessChainEvents(rewards.EventsOverview, rewards.Errors);
} }
private async Task ProcessRewards(GiveRewardsCommand rewards) private async Task ProcessRewards(GiveRewardsCommand rewards)

View File

@ -1,6 +1,5 @@
using CodexContractsPlugin; using CodexContractsPlugin;
using CodexContractsPlugin.ChainMonitor; using CodexContractsPlugin.ChainMonitor;
using Nethereum.Model;
using TestNetRewarder; using TestNetRewarder;
using Utils; using Utils;
@ -40,7 +39,7 @@ namespace MarketInsights
private MarketTimeSegment BuildContribution(TimeRange timeRange) private MarketTimeSegment BuildContribution(TimeRange timeRange)
{ {
var builder = new ContributionBuilder(timeRange); var builder = new ContributionBuilder(appState.Log, timeRange);
mux.Handlers.Add(builder); mux.Handlers.Add(builder);
chainState.Update(timeRange.To); chainState.Update(timeRange.To);
mux.Handlers.Remove(builder); mux.Handlers.Remove(builder);

View File

@ -1,5 +1,6 @@
using CodexContractsPlugin.ChainMonitor; using CodexContractsPlugin.ChainMonitor;
using GethPlugin; using GethPlugin;
using Logging;
using System.Numerics; using System.Numerics;
using Utils; using Utils;
@ -8,14 +9,16 @@ namespace MarketInsights
public class ContributionBuilder : IChainStateChangeHandler public class ContributionBuilder : IChainStateChangeHandler
{ {
private readonly MarketTimeSegment segment = new MarketTimeSegment(); private readonly MarketTimeSegment segment = new MarketTimeSegment();
private readonly ILog log;
public ContributionBuilder(TimeRange timeRange) public ContributionBuilder(ILog log, TimeRange timeRange)
{ {
segment = new MarketTimeSegment segment = new MarketTimeSegment
{ {
FromUtc = timeRange.From, FromUtc = timeRange.From,
ToUtc = timeRange.To ToUtc = timeRange.To
}; };
this.log = log;
} }
public void OnNewRequest(RequestEvent requestEvent) public void OnNewRequest(RequestEvent requestEvent)
@ -55,6 +58,11 @@ namespace MarketInsights
{ {
} }
public void OnError(string msg)
{
log.Error(msg);
}
public MarketTimeSegment GetSegment() public MarketTimeSegment GetSegment()
{ {
return segment; return segment;

View File

@ -12,6 +12,7 @@ namespace TestNetRewarder
{ {
private static readonly string nl = Environment.NewLine; private static readonly string nl = Environment.NewLine;
private readonly List<ChainEventMessage> events = new List<ChainEventMessage>(); private readonly List<ChainEventMessage> events = new List<ChainEventMessage>();
private readonly List<string> errors = new List<string>();
private readonly EmojiMaps emojiMaps = new EmojiMaps(); private readonly EmojiMaps emojiMaps = new EmojiMaps();
public ChainEventMessage[] GetEvents() public ChainEventMessage[] GetEvents()
@ -21,9 +22,11 @@ namespace TestNetRewarder
return result; return result;
} }
public void AddError(string error) public string[] GetErrors()
{ {
AddBlock(1, "📢 **Error**", error); var result = errors.ToArray();
errors.Clear();
return result;
} }
public void OnNewRequest(RequestEvent requestEvent) public void OnNewRequest(RequestEvent requestEvent)
@ -83,6 +86,11 @@ namespace TestNetRewarder
$"Slot Index: {slotIndex}" $"Slot Index: {slotIndex}"
); );
} }
public void OnError(string msg)
{
errors.Add(msg);
}
private void AddRequestBlock(RequestEvent requestEvent, string eventName, params string[] content) private void AddRequestBlock(RequestEvent requestEvent, string eventName, params string[] content)
{ {

View File

@ -48,7 +48,7 @@ namespace TestNetRewarder
{ {
var msg = "Exception processing time segment: " + ex; var msg = "Exception processing time segment: " + ex;
log.Error(msg); log.Error(msg);
eventsFormatter.AddError(msg); eventsFormatter.OnError(msg);
throw; throw;
} }
} }
@ -58,8 +58,9 @@ namespace TestNetRewarder
var numberOfChainEvents = chainState.Update(timeRange.To); var numberOfChainEvents = chainState.Update(timeRange.To);
var events = eventsFormatter.GetEvents(); var events = eventsFormatter.GetEvents();
var errors = eventsFormatter.GetErrors();
var request = builder.Build(events); var request = builder.Build(events, errors);
if (request.HasAny()) if (request.HasAny())
{ {
await client.SendRewards(request); await client.SendRewards(request);

View File

@ -19,7 +19,7 @@ namespace TestNetRewarder
} }
} }
public GiveRewardsCommand Build(ChainEventMessage[] lines) public GiveRewardsCommand Build(ChainEventMessage[] lines, string[] errors)
{ {
var result = new GiveRewardsCommand var result = new GiveRewardsCommand
{ {
@ -28,7 +28,8 @@ namespace TestNetRewarder
RewardId = p.Key, RewardId = p.Key,
UserAddresses = p.Value.Select(v => v.Address).ToArray() UserAddresses = p.Value.Select(v => v.Address).ToArray()
}).ToArray(), }).ToArray(),
EventsOverview = lines EventsOverview = lines,
Errors = errors
}; };
rewards.Clear(); rewards.Clear();

View File

@ -76,6 +76,10 @@ namespace TestNetRewarder
{ {
} }
public void OnError(string msg)
{
}
private void GiveReward(RewardConfig reward, EthAddress receiver) private void GiveReward(RewardConfig reward, EthAddress receiver)
{ {
giver.Give(reward, receiver); giver.Give(reward, receiver);