public QueuedWorkflowMessageProcessingWorker(IQueueClient queueClient, object listenerObject, MethodInfo listenerMethod, QueuedTransition queuedTransition, QueuedTransition nextQueuedTransition, bool createZombieQueues) { Contract.Requires(queueClient.IsNotNull(), "No queueClient specified: Either specify a non-null value for the 'queueClient' constructor argument."); Contract.Requires(listenerObject.IsNotNull(), "No listenerObject specified: Either specify a non-null value for the 'listenerObject' constructor argument."); Contract.Requires(listenerMethod.IsNotNull(), "No listenerMethod specified: Either specify a non-null value for the 'listenerMethod' constructor argument."); this._queueClient = queueClient; this._listenerObject = listenerObject; this._listenerMethod = listenerMethod; Type inType = this._listenerMethod.GetUniqueAndExpectedInputParameterType(); Type outType = this._listenerMethod.GetReturnValueType(); if (outType == typeof(void) || outType == typeof(Task)) { this._canUseRequestAsResponse = true; } else { this._canUseRequestAsResponse = outType.IsAssignableFrom(inType); } //Receive Route é usada para garantir a criação da rota no RabbitMQ this.ReceiveRoute = new AmqpBasedRoute() { ExchangeName = queuedTransition.ExchangeName, //Criando ExchangeName Default QueueName = queuedTransition.LogicalQueueName + ".Process", //Queue de recebimento (Fila Principal) RoutingKey = queuedTransition.BuildRoutingKey() //Binding Entre a ExchangeName e a Fila }; this.ReceiveRoute.EnsureAll(this._queueClient); if (createZombieQueues) { //Filas Zombie não precisam ser armazenadas em variáveis, só precisam ser configuradas //corretamente no RabbitMQ AmqpBasedRoute zombieConfiguration = new AmqpBasedRoute() { ExchangeName = this.ReceiveRoute.ExchangeName, QueueName = queuedTransition.LogicalQueueName + ".Zombie", RoutingKey = this.ReceiveRoute.RoutingKey }; zombieConfiguration.EnsureAll(this._queueClient); } //Caso não seja um passo final, é necessário armazenar e tratar as respostas para o próximo step if (nextQueuedTransition != null) { this._successResponseRoute = new AmqpBasedRoute() { QueueName = nextQueuedTransition.LogicalQueueName + ".Process", ExchangeName = nextQueuedTransition.ExchangeName, RoutingKey = nextQueuedTransition.BuildRoutingKey(), }; this._successResponseRoute.EnsureAll(this._queueClient); } this._errorFlowStrategy = queuedTransition.ErrorFlowStrategy; //Nesse passo as estratégias são usadas para configurar o comportamento adequado para falhas if (this._errorFlowStrategy == ExceptionStrategy.SendToErrorQueue) { //Se ao encontrar um erro, é necessário enviar para a fila de erro, todo o pipe de erro é criado //isso conta com a criação da fila, e dos bindings no RabbitMQ this._failureResponseRoute = new AmqpBasedRoute() { QueueName = queuedTransition.LogicalQueueName + ".Failure", ExchangeName = this.ReceiveRoute.ExchangeName, RoutingKey = queuedTransition.BuildFailureRoutingKey() }; this._failureResponseRoute.EnsureAll(this._queueClient); } else if (this._errorFlowStrategy == ExceptionStrategy.Requeue) { //Nesse caso, ao gerar um erro na fila a mensagem volta para a fila, portanto //a rota usada é escolhida como a mesma rota de recebimento, forçando um requeue this._failureResponseRoute = this.ReceiveRoute; } else if (this._errorFlowStrategy == ExceptionStrategy.SendToNextStepQueue) { //Nesse caso temos a possibilidade de continuar o fluxo, mesmo que uma //exceção seja lançada. if (this._successResponseRoute == null) { throw new InvalidOperationException("The ErrorFlowStrategy property cannot be setted with SendToNextStepQueue value when current step is a final step."); } this._failureResponseRoute = this._successResponseRoute; } }