public async Task OnRequestSuccessAsync(HttpResponse response) { var httpMessage = response.HttpResponseMessage; Uri requestUri = httpMessage.RequestMessage.RequestUri; string[] paths = requestUri.AbsolutePath.Split('/'); string key = GetCacheKey(paths[2], paths[3]); if (httpMessage.Headers.Contains(LimitHeader)) { var ratelimit = new Ratelimit(); if (httpMessage.Headers.TryGetValues(RemainingHeader, out var values)) { ratelimit.Remaining = int.Parse(values.FirstOrDefault()); } if (httpMessage.Headers.TryGetValues(LimitHeader, out var limitValues)) { ratelimit.Limit = int.Parse(limitValues.FirstOrDefault()); } if (httpMessage.Headers.TryGetValues(ResetHeader, out var resetValues)) { ratelimit.Reset = int.Parse(resetValues.FirstOrDefault()); } if (httpMessage.Headers.TryGetValues(GlobalHeader, out var globalValues)) { ratelimit.Global = int.Parse(globalValues.FirstOrDefault()); } await cache.UpsertAsync(key, ratelimit); } }
public void IsRatelimited() { var rateLimit = new Ratelimit { Remaining = 5, Reset = (DateTimeOffset.Now + TimeSpan.FromSeconds(1)).ToUnixTimeSeconds() }; Assert.False(Ratelimit.IsRatelimited(rateLimit)); rateLimit.Remaining = 0; Assert.True(Ratelimit.IsRatelimited(rateLimit)); rateLimit.Global = 0; rateLimit.Remaining = 3; Assert.True(Ratelimit.IsRatelimited(rateLimit)); rateLimit.Global = null; rateLimit.Remaining = 0; rateLimit.Reset = 0; Assert.False(Ratelimit.IsRatelimited(rateLimit)); }
public static void Main(string[] args) { //using (var ws = new WebSocket("wss://stream.binance.com:9443/ws")) //{ // var count = 0; // ws.OnMessage += (sender, e) => // { // Console.WriteLine(e.Data); // count++; // if (count == 2) ws.Close(); // }; // ws.OnOpen += (sender, e) => Console.WriteLine("连接成功!"); // ws.SetProxy("http://127.0.0.1:10809", "", ""); // ws.Connect(); // //ws.Send(@"{ ""method"": ""SUBSCRIBE"", ""params"": [ ""btcusdt@bookTicker""], ""id"": 1 }"); // ws.Send(@"{ ""method"": ""SUBSCRIBE"", ""params"": [ ""!miniTicker@arr""], ""id"": 1 }"); // //ws.Send(@"{ ""method"": ""SUBSCRIBE"", ""params"": [ ""btcusdt@kline_4h""], ""id"": 1 }"); // //ws.Close(); // Console.ReadKey(true); //} var ratelimit = new Ratelimit() { rateLimitType = "REQUEST_WEIGHT", interval = "MINUTE", intervalNum = 1, limit = 1200 }; PreloadResource.ExchangeInfo = new ExchangeInfo(); PreloadResource.ExchangeInfo.rateLimits = new Ratelimit[] { ratelimit }; //while (true) //{ // var random = new Random(); // var r = random.Next(50); // RequestLimitUtil.RequestBlock(r); // Thread.Sleep(1000); //} var tslist = new List <Task>(); for (int i = 0; i < 1000; i++) { var ts = new Task(() => { var random = new Random(); var r = random.Next(50); RequestLimitUtil.RequestBlock(r); }); tslist.Add(ts); ts.Start(); } Console.ReadLine(); }
public async Task <bool> CanStartRequestAsync(RequestMethod method, string requestUri) { string key = GetCacheKey(requestUri.Split('/')[0], requestUri.Split('/')[1]); Ratelimit rateLimit = await cache.GetAsync <Ratelimit>(key); rateLimit.Remaining--; await cache.UpsertAsync(key, rateLimit); return(!rateLimit.IsRatelimited()); }
public void Test() { var ratelimit = new Ratelimit() { rateLimitType = "REQUEST_WEIGHT", interval = "MINUTE", intervalNum = 1, limit = 1200 }; LoadedResource.ExchangeInfo.rateLimits = new Ratelimit[] { ratelimit }; while (true) { var random = new Random(); var r = random.Next(50); RequestLimitUtil.RequestBlock(r); Thread.Sleep(1000); } }
/// <summary> /// Configures the database and sets it up /// </summary> public override void AfterConfigure() { // If we share the database with another queue, share the connection as well lock (_lock) foreach (var m in _modules) { if (m.Value.ConnectionClass == this.ConnectionClass && m.Value.ConnectionString == this.ConnectionString) { m_con = m.Value.m_con; break; } } // Initialize base.AfterConfigure(); // The CLI will help us a little bit if (string.IsNullOrWhiteSpace(this.SelfUrl)) { this.SelfUrl = Environment.GetEnvironmentVariable("CEEN_SELF_HTTPS_URL"); } if (string.IsNullOrWhiteSpace(this.SelfUrl)) { this.SelfUrl = Environment.GetEnvironmentVariable("CEEN_SELF_HTTP_URL"); } if (string.IsNullOrWhiteSpace(this.SelfUrl)) { throw new Exception($"The QueueModule needs to know the server url to call back to, please set the {nameof(SelfUrl)} variable"); } // Remove trailing slashes to make it easier to concatenate strings this.SelfUrl = this.SelfUrl.Trim().TrimEnd('/'); if (string.IsNullOrWhiteSpace(Name)) { throw new Exception("The name of the queue cannot be empty"); } if (string.IsNullOrWhiteSpace(SecureHeaderName)) { throw new Exception("The secure header name cannot be empty"); } if (string.IsNullOrWhiteSpace(Ratelimit)) { throw new Exception("The rate limit value cannot be empty"); } if (string.IsNullOrWhiteSpace(RetryBackoff)) { throw new Exception("The retry backoff value cannot be empty"); } if (MaxRetries <= 0) { throw new Exception("Invalid max retry count"); } // Assign a random value if (string.IsNullOrWhiteSpace(SecureHeaderValue)) { SecureHeaderValue = Guid.NewGuid().ToString(); } var rl = Ratelimit.Split(new char[] { '/' }, 2); if (rl.Length != 2 || rl[0].Length < 1 || rl[1].Length < 1) { throw new Exception("Unable to parse the ratelimit"); } if (rl[1][0] < '0' || rl[1][0] > '9') { rl[1] = '1' + rl[1]; } m_ratelimitcount = int.Parse(rl[0]); m_ratelimitWindow = ParseUtil.ParseDuration(rl[1]); if (m_ratelimitWindow.Ticks <= 0 || m_ratelimitcount <= 0) { throw new Exception("Invalid rate limit"); } var rb = RetryBackoff.Split(new char[] { ';' }, 3); var re = new System.Text.RegularExpressions.Regex(@"(?<mode>[exp|lin|exponential|linear])\w+(?<rate>.+)"); // Only have the exp/lin, compute start and limit if (rb.Length == 1) { var m = re.Match(rb[0]); if (!m.Success) { throw new Exception("Unable to parse the backoff"); } var duration = m.Groups["rate"].Value; var ps = ParseUtil.ParseDuration(duration); rb = new string[] { duration, rb[0], $"{ps.TotalSeconds * MaxRetries}s" }; } else if (rb.Length == 2) { // First is exp/lin, last is limit, compute start var m = re.Match(rb[0]); if (m.Success) { rb = new string[] { m.Groups["rate"].Value, rb[0], rb[1] }; } // Second is exp/lin, first is start, compute last else { m = re.Match(rb[1]); if (!m.Success) { throw new Exception("Unable to parse the backoff"); } var duration = m.Groups["rate"].Value; var ps = ParseUtil.ParseDuration(duration); rb = new string[] { rb[0], rb[1], $"{ps.TotalSeconds * MaxRetries}s" }; } } var mx = re.Match(rb[1]); if (!mx.Success) { throw new Exception("Unable to parse the backoff"); } m_initialbackoff = ParseUtil.ParseDuration(rb[0]); m_maximumbackoff = ParseUtil.ParseDuration(rb[2]); m_additionalbackoff = ParseUtil.ParseDuration(mx.Groups["rate"].Value); m_exponentialBackoff = mx.Groups["mode"].Value.StartsWith("exp", true, System.Globalization.CultureInfo.InvariantCulture); if (m_initialbackoff.Ticks < 0 || m_maximumbackoff.Ticks < 0 || m_additionalbackoff.Ticks < 0) { throw new Exception("Invalid back-off values"); } m_ratelimiter = new RateLimit(m_ratelimitcount, m_ratelimitWindow); lock (_lock) _modules.Add(Name, this); // Activate the runner SignalRunner(); }