1

SubscribeToKlineUpdatesAsync is a web socket stream event handler receiving data on each second from Binance. I have a long-running operation for 10 seconds inside it. It's separated into a task, because I don't want it to block any incoming price data.

The problem is that it spawns thousand of tasks at a time and I want it to spawn only one task at a time per a symbol. The symbol is identified by data.Symbol. Below the code, you'll find the logs. The second log is what I want it to be like.

I would like to use something like TPL Dataflow or Rx.NET. I just don't know how to do it. I'm aware of the lock way, BlockingCollection and SemaphoreSlim.

There is a log below of what's current and what I want to accomplish.

Code

using System;
using System.Threading;
using System.Threading.Tasks;
using Binance.Net;
using Binance.Net.Enums;
using Binance.Net.Interfaces;
using Binance.Net.Objects.Spot;
using CryptoExchange.Net.Authentication;
using CryptoExchange.Net.Logging;

namespace SubscribeToCandlesEventFixTest
{
    public class BinanceSocketHandler
    {
        private readonly IBinanceClient _client;
        private readonly IBinanceSocketClient _socketClient;

        public BinanceSocketHandler()
        {
            _client = new BinanceClient(new BinanceClientOptions
            {
                ApiCredentials = new ApiCredentials("not required", "not required"),
                AutoTimestamp = true,
                AutoTimestampRecalculationInterval = TimeSpan.FromMinutes(30),
#if DEBUG
                LogVerbosity = LogVerbosity.Debug
#endif
            });

            _socketClient = new BinanceSocketClient(new BinanceSocketClientOptions
            {
                ApiCredentials = new ApiCredentials("not required", "not required"),
                AutoReconnect = true,
                ReconnectInterval = TimeSpan.FromSeconds(15),
#if DEBUG
                LogVerbosity = LogVerbosity.Debug
#endif
            });
        }
        
        public Task StartAsync(CancellationToken cancellationToken)
        {
            var symbols = new[] { "TRXUSDT", "BTCUSDT" };
            var interval = KlineInterval.OneMinute;

            return _socketClient.Spot.SubscribeToKlineUpdatesAsync(symbols, interval,
                data =>
                {
                    if (data.Data.Final)
                    {
                        Console.WriteLine($"[{DateTime.UtcNow}] [{data.Symbol}] New final candle | Timestamp: {data.Data.OpenTime} | Price: {data.Data.Close}");
                    }
                    else
                    {
                        Console.WriteLine($"[{DateTime.UtcNow}] [{data.Symbol}] Candle update | Timestamp: {data.Data.OpenTime} | Price: {data.Data.Close}");

                        Task.Run(async () =>
                        {
                            Console.WriteLine("Operation taking 10 seconds to execute...");

                            await Task.Delay(10000, cancellationToken).ConfigureAwait(false);
                        }, cancellationToken);
                    }
                });
        }
    }

    class Program
    {
        static async Task Main(string[] args)
        {
            var test = new BinanceSocketHandler();
            await test.StartAsync(new CancellationToken()).ConfigureAwait(false);

            Console.ReadLine();
        }
    }
}

Log

It spawns thousand of tasks. I want only one task per a symbol.

[3/7/2021 12:24:53 AM] [TRXUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 0.05049000
Operation taking 10 seconds to execute...
[3/7/2021 12:24:53 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 49240.17000000
Operation taking 10 seconds to execute...
[3/7/2021 12:24:55 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 49245.66000000
Operation taking 10 seconds to execute...
[3/7/2021 12:24:57 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 49251.02000000
Operation taking 10 seconds to execute...
[3/7/2021 12:24:59 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 49254.44000000
Operation taking 10 seconds to execute...
[3/7/2021 12:25:00 AM] [TRXUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 0.05049000
Operation taking 10 seconds to execute...
[3/7/2021 12:25:01 AM] [BTCUSDT] New final candle | Timestamp: 3/7/2021 12:24:00 AM | Price: 49257.99000000
[3/7/2021 12:25:01 AM] [TRXUSDT] New final candle | Timestamp: 3/7/2021 12:24:00 AM | Price: 0.05049000
[3/7/2021 12:25:03 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 49264.26000000
Operation taking 10 seconds to execute...
[3/7/2021 12:25:04 AM] [TRXUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 0.05049000
Operation taking 10 seconds to execute...
[3/7/2021 12:25:05 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 49266.60000000
Operation taking 10 seconds to execute...
[3/7/2021 12:25:07 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 49251.02000000
Operation taking 10 seconds to execute...
[3/7/2021 12:25:07 AM] [TRXUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 0.05050000
Operation taking 10 seconds to execute...

Example log of what I want

[3/7/2021 12:24:53 AM] [TRXUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 0.05049000
Operation taking 10 seconds to execute...
[3/7/2021 12:24:53 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 49240.17000000
Operation taking 10 seconds to execute...
[3/7/2021 12:24:55 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 49245.66000000
[3/7/2021 12:24:57 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 49251.02000000
[3/7/2021 12:24:59 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 49254.44000000
[3/7/2021 12:25:00 AM] [TRXUSDT] Candle update | Timestamp: 3/7/2021 12:24:00 AM | Price: 0.05049000
[3/7/2021 12:25:01 AM] [BTCUSDT] New final candle | Timestamp: 3/7/2021 12:24:00 AM | Price: 49257.99000000
[3/7/2021 12:25:01 AM] [TRXUSDT] New final candle | Timestamp: 3/7/2021 12:24:00 AM | Price: 0.05049000
[3/7/2021 12:25:03 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 49264.26000000
Operation taking 10 seconds to execute...
[3/7/2021 12:25:04 AM] [TRXUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 0.05049000
Operation taking 10 seconds to execute...
[3/7/2021 12:25:05 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 49266.60000000
[3/7/2021 12:25:07 AM] [BTCUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 49251.02000000
[3/7/2021 12:25:07 AM] [TRXUSDT] Candle update | Timestamp: 3/7/2021 12:25:00 AM | Price: 0.05050000
nop
  • 4,711
  • 6
  • 32
  • 93
  • You don't have a [mcve] here. It's hard to say how to help without seeing how you get all the tasks being spawned. – Enigmativity Mar 08 '21 at 06:57
  • @Enigmativity, hey mate, it's the whole code. Only Binance.Net package is required. `Task.Run(...)` is the questioned task. That's the whole thing – nop Mar 08 '21 at 07:04
  • 1
    So it is! I'm away at the moment so I haven't got time to look at it. I just wanted others to be in a position to help. It looks like they are. :-) – Enigmativity Mar 08 '21 at 07:27

0 Answers0