/// <summary> /// RealTimeTelemetryManager constructor for RealTimeTelemetryManager instance creation /// </summary> /// <param name="nodeId">Node Id </param> /// <param name="jsonRpcUrl">JSON Rpc of Parity </param> /// <param name="webSocketUrl">Web Socket URL of Parity </param> /// <param name="ingressEndPoint">Ingress REal time restful End Point </param> /// <param name="ingressFingerPrint">Ingress Finger Print </param> /// <param name="signer">Payload Signer instance reference </param> /// <param name="ftpMgr">FTPManager instance reference </param> /// <param name="verbose">if detailed logs are required set verbose to true </param> /// <returns>returns instance of RealTimeTelemetryManager</returns> /// <exception cref="System.ArgumentException">Thrown when any of provided argument is null or empty.</exception> public RealTimeTelemetryManager(string nodeId, string jsonRpcUrl, string webSocketUrl, string ingressEndPoint, string ingressFingerPrint, PayloadSigner signer, FtpManager ftpMgr, bool verbose = true) { if (string.IsNullOrWhiteSpace(nodeId)) { throw new ArgumentException("Node ID is empty", nameof(nodeId)); } if (string.IsNullOrWhiteSpace(jsonRpcUrl)) { throw new ArgumentException("RPC URL is empty", nameof(jsonRpcUrl)); } if (string.IsNullOrWhiteSpace(webSocketUrl)) { throw new ArgumentException("Web Socket URL is empty", nameof(webSocketUrl)); } if (string.IsNullOrWhiteSpace(ingressEndPoint)) { throw new ArgumentException("Ingress END Point is empty", nameof(ingressEndPoint)); } if (string.IsNullOrWhiteSpace(ingressFingerPrint)) { throw new ArgumentException("Ingress Finger Point is empty", nameof(ingressFingerPrint)); } _ftpMgr = ftpMgr ?? throw new ArgumentException("FTP Manager is null", nameof(ftpMgr)); _signer = signer ?? throw new ArgumentException("Signer is null", nameof(signer)); _webSocketUri = webSocketUrl; _jsonRpcUrl = jsonRpcUrl; _nodeId = nodeId; _verbose = verbose; _tti = new TalkToIngress(ingressEndPoint, ingressFingerPrint); }
/// <summary> /// Sends data to Ingress restful end point /// </summary> /// <param name="state">Object state</param> private static void FlushToIngress(object state) { // Flush to ingress if more than 10 telemetry recordings -or- last flush older that 1 minute if (_globalQueue.Count <= 10 && DateTime.UtcNow - _lastFlush <= new TimeSpan(0, 1, 0)) { Console.WriteLine($"Not flushing: {_globalQueue.Count} Queued - {(DateTime.UtcNow - _lastFlush).TotalSeconds} seconds since flush"); return; } List <string> telemetryToSend = new List <string>(); while (telemetryToSend.Count < 50 && _globalQueue.TryDequeue(out string lineFromQueue)) { telemetryToSend.Add(lineFromQueue); } Console.WriteLine($"Flushing {telemetryToSend.Count} to ingress. {_globalQueue.Count} still in queue." + (_flushHighspeed ? " [HighSpeed]" : "")); TelemetryPacket pkt = new TelemetryPacket { NodeId = _configuration.NodeId, Payload = telemetryToSend, Signature = _signer.SignPayload(string.Join(string.Empty, telemetryToSend)) }; string jsonPayload = JsonConvert.SerializeObject(pkt); // Send data TalkToIngress tti = new TalkToIngress(_configuration.IngressHost + "/api/ingress/influx", _configuration.IngressFingerprint); bool sendSuccess = tti.SendRequest(jsonPayload).Result; if (!sendSuccess) { if (DateTime.UtcNow - _lastFlush > TimeSpan.FromMinutes(5)) { // unable to send to ingress for 5 minutes - send by second channel Console.WriteLine("ERROR: Unable to send to ingress for more then 5 minutes. Sending queue on second channel."); string fileName = $"{_configuration.NodeId}-{DateTime.UtcNow:yyyy-MM-dd_HH:mm:ss}.json"; try { if (!_ftpMgr.TransferData(jsonPayload, fileName)) { Console.WriteLine("ERROR: Unable to send data on second channel. Data File {0}", fileName); // second channel also not available - requeue Console.WriteLine("Unable to flush to second channel - re queueing"); telemetryToSend.ForEach(_globalQueue.Enqueue); } } catch (Exception ex) { Console.WriteLine("ERROR: Unable to send data on second channel. Error Details {0}", ex); // second channel also not available - requeue Console.WriteLine("Unable to flush to second channel - re queueing"); telemetryToSend.ForEach(_globalQueue.Enqueue); } } else { // 5min second channel delay not reached -> re-queue Console.WriteLine("Unable to flush. Re-queuing..."); telemetryToSend.ForEach(_globalQueue.Enqueue); } } else { if (_globalQueue.Count > 250 && !_flushHighspeed) { // increase processing speed to 2 seconds Console.WriteLine("Increasing push speed due to queue size"); _flushTimer.Change(2000, 2000); _flushHighspeed = true; } else if (_globalQueue.Count < 250 && _flushHighspeed) // queue is small enough to get processed. back to normal speed { Console.WriteLine("Decreasing push speed due to queue size"); _flushTimer.Change(10000, 10000); _flushHighspeed = false; } _lastFlush = DateTime.UtcNow; } }