Пример #1
0
        private async ValueTask HandleEvents(IReadOnlyList <ExBalanceUpdateMessage> messages)
        {
            using var activity = MyTelemetry.StartActivity("Handle ExBalanceUpdateMessage's")
                                 ?.AddTag("count-events", messages.Count);
            try
            {
                var sw = new Stopwatch();
                sw.Start();

                var list           = new List <AvgPriceUpdate>();
                var calculatedList = new List <AvgPriceUpdate>();

                if (!messages.Any())
                {
                    return;
                }

                list.AddRange(GetOperationUpdates(messages));
                if (!list.Any())
                {
                    return;
                }

                await using var ctx = DatabaseContext.Create(_dbContextOptionsBuilder);
                var groups = list.GroupBy(t => new { t.AssetId, t.WalletId });
                foreach (var group in groups)
                {
                    var semaphore = SemaphoreManager.GetOrCreate(group.Key.WalletId, group.Key.AssetId);
                    await semaphore.WaitAsync();

                    try
                    {
                        var groupedList = group.OrderBy(t => t.TimeStamp).ToList();

                        var snapshot = await _snapshotManager.GetSnapshot(group.Key.WalletId, group.Key.AssetId);

                        if (snapshot != null)
                        {
                            groupedList = groupedList.Where(t => t.TimeStamp > snapshot.LastTimestamp).ToList();
                        }

                        if (!groupedList.Any())
                        {
                            continue;
                        }

                        groupedList = AvgPriceCalculator.CalculateAvgPrice(groupedList, snapshot);
                        calculatedList.AddRange(groupedList);

                        var openTimestamp = groupedList.LastOrDefault(t => t.Balance == 0)?.TimeStamp ??
                                            snapshot?.OpenTimestamp ?? default;

                        var lastUpdate  = groupedList.Last();
                        var newSnapshot = new SnapshotEntity
                        {
                            WalletId      = lastUpdate.WalletId,
                            AssetId       = lastUpdate.AssetId,
                            Balance       = lastUpdate.Balance,
                            AvgOpenPrice  = lastUpdate.AvgOpenPrice,
                            OpenTimestamp = openTimestamp,
                            LastTimestamp = lastUpdate.TimeStamp
                        };
                        await _snapshotManager.UpsertSnapshots(new() { newSnapshot });
                    }
                    finally
                    {
                        semaphore.Release();
                    }
                }

                await ctx.UpsertAvgPriceAsync(calculatedList.Where(t => t.EventType != "Refund Blockchain Withdrawal").Select(update => new OperationHistoryEntity(update)));

                await ctx.SaveChangesAsync();

                sw.Stop();

                _logger.LogDebug(
                    "Write {countUpdates} avg price updates in database from {countEvents} ME events. Time: {elapsedText} [{elapsedMilliseconds} ms]",
                    list.Count, messages.Count, sw.Elapsed.ToString(), sw.ElapsedMilliseconds);
            }
            catch (Exception ex)
            {
                ex.FailActivity();
                messages.AddToActivityAsJsonTag("me events");
                throw;
            }
        }
Пример #2
0
        private async ValueTask HandleEvents(IReadOnlyList <ExBalanceUpdateMessage> messages)
        {
            await Task.Delay(5000);

            using var locker = await _locker.GetLocker();

            using var activity = MyTelemetry.StartActivity("Handle ExBalanceUpdateMessage's")
                                 ?.AddTag("count-events", messages.Count);
            try
            {
                var sw = new Stopwatch();
                sw.Start();

                var list = new List <BalanceHistoryEntity>();

                foreach (var balanceUpdateMessage in messages)
                {
                    if (balanceUpdateMessage.Update.Result != ExBalanceUpdate.BalanceUpdateResult.Ok)
                    {
                        continue;
                    }

                    var groupedUpdates =
                        balanceUpdateMessage.Update.Updates.GroupBy(t => new { t.WalletId, t.AssetId });

                    foreach (var update in groupedUpdates)
                    {
                        using var _ = MyTelemetry.StartActivity("Update balance")
                                      ?.AddTag("walletId", update.Key.WalletId)
                                      .AddTag("symbol", update.Key.AssetId);

                        var firstUpdate = update.OrderBy(t => t.Number).First();
                        var lastUpdate  = update.OrderBy(t => t.Number).Last();

                        var newBalance = lastUpdate.NewBalance;
                        var oldBalance = firstUpdate.OldBalance;
                        var newReserve = lastUpdate.ReserveNewBalance;
                        var oldReserve = firstUpdate.ReserveOldBalance;
                        newBalance += newReserve;
                        oldBalance += oldReserve;
                        var amountBalance    = newBalance - oldBalance;
                        var amountReserve    = newReserve - oldReserve;
                        var availableBalance = newBalance - newReserve;

                        var balanceVersion = balanceUpdateMessage.Update.Balances.Single(balance =>
                                                                                         balance.AssetId == update.Key.AssetId && balance.WalletId == update.Key.WalletId).Version;

                        var entity = new BalanceHistoryEntity()
                        {
                            WalletId    = update.Key.WalletId,
                            Symbol      = update.Key.AssetId,
                            EventType   = balanceUpdateMessage.Update.EventType,
                            SequenceId  = balanceVersion,
                            OperationId = balanceUpdateMessage.Update.OperationId,
                            Timestamp   = balanceUpdateMessage.Update.Timestamp,

                            NewBalance = (double)newBalance,
                            OldBalance = (double)oldBalance,
                            NewReserve = (double)newReserve,
                            OldReserve = (double)oldReserve,

                            AmountBalance = (double)amountBalance,
                            AmountReserve = (double)amountReserve,

                            AvailableBalance = (double)availableBalance,

                            IsBalanceChanged = amountBalance != 0
                        };

                        list.Add(entity);
                    }
                }

                await using var ctx = DatabaseContext.Create(_dbContextOptionsBuilder);
                await ctx.UpsetAsync(list).ConfigureAwait(false);
                await PopulateBalances(list, ctx);

                sw.Stop();

                _logger.LogDebug(
                    "Write {countUpdates} balance updates in database from {countEvents} ExBalanceUpdateMessage events. Time: {elapsedText} [{elapsedMilliseconds} ms]",
                    list.Count, messages.Count, sw.Elapsed.ToString(), sw.ElapsedMilliseconds);
            }
            catch (Exception ex)
            {
                ex.FailActivity();
                messages.AddToActivityAsJsonTag("me events");
                throw;
            }
        }