/// <summary> /// Create engine /// </summary> public DataFlowProcessingEngine(IMessageTrigger messageTrigger, IMessageEncoder encoder, IMessageSink messageSink, IEngineConfiguration engineConfiguration, ILogger logger, IIdentity identity) { _config = engineConfiguration; _messageTrigger = messageTrigger; _messageSink = messageSink; _messageEncoder = encoder; _logger = logger; _identity = identity; if (_config.BatchSize.HasValue && _config.BatchSize.Value > 1) { _dataSetMessageBufferSize = _config.BatchSize.Value; } if (_config.MaxMessageSize.HasValue && _config.MaxMessageSize.Value > 0) { _maxEncodedMessageSize = _config.MaxMessageSize.Value; } _diagnosticInterval = _config.DiagnosticsInterval.GetValueOrDefault(TimeSpan.Zero); _batchTriggerInterval = _config.BatchTriggerInterval.GetValueOrDefault(TimeSpan.Zero); _diagnosticsOutputTimer = new Timer(DiagnosticsOutputTimer_Elapsed); _batchTriggerIntervalTimer = new Timer(BatchTriggerIntervalTimer_Elapsed); _maxOutgressMessages = _config.MaxOutgressMessages.GetValueOrDefault(4096); // = 1 GB _encodingBlock = new TransformManyBlock <DataSetMessageModel[], NetworkMessageModel>( async input => { try { if (_dataSetMessageBufferSize == 1) { return(await _messageEncoder.EncodeAsync(input, _maxEncodedMessageSize).ConfigureAwait(false)); } else { return(await _messageEncoder.EncodeBatchAsync(input, _maxEncodedMessageSize).ConfigureAwait(false)); } } catch (Exception e) { _logger.Error(e, "Encoding failure"); return(Enumerable.Empty <NetworkMessageModel>()); } }, new ExecutionDataflowBlockOptions()); _batchDataSetMessageBlock = new BatchBlock <DataSetMessageModel>( _dataSetMessageBufferSize, new GroupingDataflowBlockOptions()); _batchNetworkMessageBlock = new BatchBlock <NetworkMessageModel>( _networkMessageBufferSize, new GroupingDataflowBlockOptions()); _sinkBlock = new ActionBlock <NetworkMessageModel[]>( async input => { if (input != null && input.Any()) { _logger.Debug("Sink block in engine {Name} triggered with {count} messages", Name, input.Length); await _messageSink.SendAsync(input).ConfigureAwait(false); } else { _logger.Warning("Sink block in engine {Name} triggered with empty input", Name); } }, new ExecutionDataflowBlockOptions()); _batchDataSetMessageBlock.LinkTo(_encodingBlock); _encodingBlock.LinkTo(_batchNetworkMessageBlock); _batchNetworkMessageBlock.LinkTo(_sinkBlock); _messageTrigger.OnMessage += MessageTriggerMessageReceived; _messageTrigger.OnCounterReset += MessageTriggerCounterResetReceived; if (_diagnosticInterval > TimeSpan.Zero) { _diagnosticsOutputTimer.Change(_diagnosticInterval, _diagnosticInterval); } }