Fixed #6: Use 'mandatory' on replies
This commit is contained in:
parent
37d55ac71d
commit
60c7020a2c
@ -80,7 +80,7 @@ namespace Tapeti.Flow.Default
|
|||||||
|
|
||||||
await context.Store();
|
await context.Store();
|
||||||
|
|
||||||
await publisher.Publish(message, properties);
|
await publisher.Publish(message, properties, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -105,9 +105,9 @@ namespace Tapeti.Flow.Default
|
|||||||
|
|
||||||
// TODO disallow if replyto is not specified?
|
// TODO disallow if replyto is not specified?
|
||||||
if (reply.ReplyTo != null)
|
if (reply.ReplyTo != null)
|
||||||
await publisher.PublishDirect(message, reply.ReplyTo, properties);
|
await publisher.PublishDirect(message, reply.ReplyTo, properties, true);
|
||||||
else
|
else
|
||||||
await publisher.Publish(message, properties);
|
await publisher.Publish(message, properties, true);
|
||||||
|
|
||||||
await context.Delete();
|
await context.Delete();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using ISeriLogger = Serilog.ILogger;
|
using ISeriLogger = Serilog.ILogger;
|
||||||
|
|
||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
namespace Tapeti.Serilog
|
namespace Tapeti.Serilog
|
||||||
{
|
{
|
||||||
public class TapetiSeriLogger: ILogger
|
public class TapetiSeriLogger: ILogger
|
||||||
|
@ -7,6 +7,8 @@ namespace Tapeti.Config
|
|||||||
{
|
{
|
||||||
public interface IConfig
|
public interface IConfig
|
||||||
{
|
{
|
||||||
|
bool UsePublisherConfirms { get; }
|
||||||
|
|
||||||
IDependencyResolver DependencyResolver { get; }
|
IDependencyResolver DependencyResolver { get; }
|
||||||
IReadOnlyList<IMessageMiddleware> MessageMiddleware { get; }
|
IReadOnlyList<IMessageMiddleware> MessageMiddleware { get; }
|
||||||
IReadOnlyList<ICleanupMiddleware> CleanupMiddleware { get; }
|
IReadOnlyList<ICleanupMiddleware> CleanupMiddleware { get; }
|
||||||
|
@ -17,19 +17,19 @@ namespace Tapeti.Connection
|
|||||||
|
|
||||||
public Task Publish(object message)
|
public Task Publish(object message)
|
||||||
{
|
{
|
||||||
return workerFactory().Publish(message, null);
|
return workerFactory().Publish(message, null, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Task Publish(object message, IBasicProperties properties)
|
public Task Publish(object message, IBasicProperties properties, bool mandatory)
|
||||||
{
|
{
|
||||||
return workerFactory().Publish(message, properties);
|
return workerFactory().Publish(message, properties, mandatory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Task PublishDirect(object message, string queueName, IBasicProperties properties)
|
public Task PublishDirect(object message, string queueName, IBasicProperties properties, bool mandatory)
|
||||||
{
|
{
|
||||||
return workerFactory().PublishDirect(message, queueName, properties);
|
return workerFactory().PublishDirect(message, queueName, properties, mandatory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using RabbitMQ.Client;
|
using RabbitMQ.Client;
|
||||||
using RabbitMQ.Client.Exceptions;
|
using RabbitMQ.Client.Exceptions;
|
||||||
using RabbitMQ.Client.Framing;
|
using RabbitMQ.Client.Framing;
|
||||||
using Tapeti.Config;
|
using Tapeti.Config;
|
||||||
|
using Tapeti.Exceptions;
|
||||||
using Tapeti.Helpers;
|
using Tapeti.Helpers;
|
||||||
using Tapeti.Tasks;
|
using Tapeti.Tasks;
|
||||||
|
|
||||||
@ -13,6 +15,7 @@ namespace Tapeti.Connection
|
|||||||
public class TapetiWorker
|
public class TapetiWorker
|
||||||
{
|
{
|
||||||
private const int ReconnectDelay = 5000;
|
private const int ReconnectDelay = 5000;
|
||||||
|
private const int MandatoryReturnTimeout = 30000;
|
||||||
private const int PublishMaxConnectAttempts = 3;
|
private const int PublishMaxConnectAttempts = 3;
|
||||||
|
|
||||||
private readonly IConfig config;
|
private readonly IConfig config;
|
||||||
@ -24,8 +27,11 @@ namespace Tapeti.Connection
|
|||||||
private readonly IRoutingKeyStrategy routingKeyStrategy;
|
private readonly IRoutingKeyStrategy routingKeyStrategy;
|
||||||
private readonly IExchangeStrategy exchangeStrategy;
|
private readonly IExchangeStrategy exchangeStrategy;
|
||||||
private readonly Lazy<SingleThreadTaskQueue> taskQueue = new Lazy<SingleThreadTaskQueue>();
|
private readonly Lazy<SingleThreadTaskQueue> taskQueue = new Lazy<SingleThreadTaskQueue>();
|
||||||
|
|
||||||
|
// These fields are for use in the taskQueue only!
|
||||||
private RabbitMQ.Client.IConnection connection;
|
private RabbitMQ.Client.IConnection connection;
|
||||||
private IModel channelInstance;
|
private IModel channelInstance;
|
||||||
|
private TaskCompletionSource<int> publishResultTaskSource;
|
||||||
|
|
||||||
|
|
||||||
public TapetiWorker(IConfig config)
|
public TapetiWorker(IConfig config)
|
||||||
@ -39,15 +45,15 @@ namespace Tapeti.Connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Task Publish(object message, IBasicProperties properties)
|
public Task Publish(object message, IBasicProperties properties, bool mandatory)
|
||||||
{
|
{
|
||||||
return Publish(message, properties, exchangeStrategy.GetExchange(message.GetType()), routingKeyStrategy.GetRoutingKey(message.GetType()));
|
return Publish(message, properties, exchangeStrategy.GetExchange(message.GetType()), routingKeyStrategy.GetRoutingKey(message.GetType()), mandatory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Task PublishDirect(object message, string queueName, IBasicProperties properties)
|
public Task PublishDirect(object message, string queueName, IBasicProperties properties, bool mandatory)
|
||||||
{
|
{
|
||||||
return Publish(message, properties, "", queueName);
|
return Publish(message, properties, "", queueName, mandatory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -147,7 +153,7 @@ namespace Tapeti.Connection
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Task Publish(object message, IBasicProperties properties, string exchange, string routingKey)
|
private Task Publish(object message, IBasicProperties properties, string exchange, string routingKey, bool mandatory)
|
||||||
{
|
{
|
||||||
var context = new PublishContext
|
var context = new PublishContext
|
||||||
{
|
{
|
||||||
@ -172,8 +178,39 @@ namespace Tapeti.Connection
|
|||||||
() => taskQueue.Value.Add(async () =>
|
() => taskQueue.Value.Add(async () =>
|
||||||
{
|
{
|
||||||
var body = messageSerializer.Serialize(context.Message, context.Properties);
|
var body = messageSerializer.Serialize(context.Message, context.Properties);
|
||||||
(await GetChannel(PublishMaxConnectAttempts)).BasicPublish(context.Exchange, context.RoutingKey, false,
|
Task<int> publishResultTask = null;
|
||||||
context.Properties, body);
|
|
||||||
|
if (config.UsePublisherConfirms)
|
||||||
|
{
|
||||||
|
publishResultTaskSource = new TaskCompletionSource<int>();
|
||||||
|
publishResultTask = publishResultTaskSource.Task;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mandatory = false;
|
||||||
|
|
||||||
|
(await GetChannel(PublishMaxConnectAttempts)).BasicPublish(context.Exchange, context.RoutingKey, mandatory, context.Properties, body);
|
||||||
|
|
||||||
|
if (publishResultTask != null)
|
||||||
|
{
|
||||||
|
var timerCancellationSource = new CancellationTokenSource();
|
||||||
|
|
||||||
|
if (await Task.WhenAny(publishResultTask, Task.Delay(MandatoryReturnTimeout, timerCancellationSource.Token)) == publishResultTask)
|
||||||
|
{
|
||||||
|
timerCancellationSource.Cancel();
|
||||||
|
|
||||||
|
var replyCode = publishResultTask.Result;
|
||||||
|
|
||||||
|
// There is no RabbitMQ.Client.Framing.Constants value for this "No route" reply code
|
||||||
|
// at the time of writing...
|
||||||
|
if (replyCode == 312)
|
||||||
|
throw new NoRouteException($"Mandatory message with class {context.Message?.GetType().FullName ?? "null"} does not have a route");
|
||||||
|
|
||||||
|
if (replyCode > 0)
|
||||||
|
throw new NoRouteException($"Mandatory message with class {context.Message?.GetType().FullName ?? "null"} could not be delivery, reply code {replyCode}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
throw new TimeoutException($"Timeout while waiting for basic.return for message with class {context.Message?.GetType().FullName ?? "null"} and Id {context.Properties.MessageId}");
|
||||||
|
}
|
||||||
}).Unwrap());
|
}).Unwrap());
|
||||||
// ReSharper restore ImplicitlyCapturedClosure
|
// ReSharper restore ImplicitlyCapturedClosure
|
||||||
}
|
}
|
||||||
@ -207,13 +244,25 @@ namespace Tapeti.Connection
|
|||||||
|
|
||||||
connection = connectionFactory.CreateConnection();
|
connection = connectionFactory.CreateConnection();
|
||||||
channelInstance = connection.CreateModel();
|
channelInstance = connection.CreateModel();
|
||||||
|
channelInstance.ConfirmSelect();
|
||||||
|
|
||||||
if (ConnectionParams.PrefetchCount > 0)
|
if (ConnectionParams.PrefetchCount > 0)
|
||||||
channelInstance.BasicQos(0, ConnectionParams.PrefetchCount, false);
|
channelInstance.BasicQos(0, ConnectionParams.PrefetchCount, false);
|
||||||
|
|
||||||
((IRecoverable)connection).Recovery += (sender, e) => ConnectionEventListener?.Reconnected();
|
((IRecoverable)connection).Recovery += (sender, e) => ConnectionEventListener?.Reconnected();
|
||||||
|
|
||||||
channelInstance.ModelShutdown += (sender, e) => ConnectionEventListener?.Disconnected();
|
channelInstance.ModelShutdown += (sender, eventArgs) => ConnectionEventListener?.Disconnected();
|
||||||
|
channelInstance.BasicReturn += (sender, eventArgs) =>
|
||||||
|
{
|
||||||
|
publishResultTaskSource?.SetResult(eventArgs.ReplyCode);
|
||||||
|
publishResultTaskSource = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
channelInstance.BasicAcks += (sender, eventArgs) =>
|
||||||
|
{
|
||||||
|
publishResultTaskSource?.SetResult(0);
|
||||||
|
publishResultTaskSource = null;
|
||||||
|
};
|
||||||
|
|
||||||
ConnectionEventListener?.Connected();
|
ConnectionEventListener?.Connected();
|
||||||
logger.ConnectSuccess(ConnectionParams);
|
logger.ConnectSuccess(ConnectionParams);
|
||||||
|
@ -16,7 +16,7 @@ namespace Tapeti.Default
|
|||||||
|
|
||||||
public void ConnectSuccess(TapetiConnectionParams connectionParams)
|
public void ConnectSuccess(TapetiConnectionParams connectionParams)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"[Tapeti] Connected");
|
Console.WriteLine("[Tapeti] Connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void HandlerException(Exception e)
|
public void HandlerException(Exception e)
|
||||||
|
@ -69,9 +69,9 @@ namespace Tapeti.Default
|
|||||||
properties.CorrelationId = messageContext.Properties.CorrelationId;
|
properties.CorrelationId = messageContext.Properties.CorrelationId;
|
||||||
|
|
||||||
if (messageContext.Properties.IsReplyToPresent())
|
if (messageContext.Properties.IsReplyToPresent())
|
||||||
return publisher.PublishDirect(message, messageContext.Properties.ReplyTo, properties);
|
return publisher.PublishDirect(message, messageContext.Properties.ReplyTo, properties, true);
|
||||||
|
|
||||||
return publisher.Publish(message, properties);
|
return publisher.Publish(message, properties, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
9
Tapeti/Exceptions/NoRouteException.cs
Normal file
9
Tapeti/Exceptions/NoRouteException.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Tapeti.Exceptions
|
||||||
|
{
|
||||||
|
public class NoRouteException : Exception
|
||||||
|
{
|
||||||
|
public NoRouteException(string message) : base(message) { }
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,7 @@ namespace Tapeti
|
|||||||
|
|
||||||
public interface IInternalPublisher : IPublisher
|
public interface IInternalPublisher : IPublisher
|
||||||
{
|
{
|
||||||
Task Publish(object message, IBasicProperties properties);
|
Task Publish(object message, IBasicProperties properties, bool mandatory);
|
||||||
Task PublishDirect(object message, string queueName, IBasicProperties properties);
|
Task PublishDirect(object message, string queueName, IBasicProperties properties, bool mandatory);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using Tapeti.Config;
|
|||||||
using Tapeti.Default;
|
using Tapeti.Default;
|
||||||
using Tapeti.Helpers;
|
using Tapeti.Helpers;
|
||||||
|
|
||||||
|
// ReSharper disable UnusedMember.Global
|
||||||
|
|
||||||
namespace Tapeti
|
namespace Tapeti
|
||||||
{
|
{
|
||||||
@ -31,6 +32,8 @@ namespace Tapeti
|
|||||||
|
|
||||||
private readonly IDependencyResolver dependencyResolver;
|
private readonly IDependencyResolver dependencyResolver;
|
||||||
|
|
||||||
|
private bool usePublisherConfirms = true;
|
||||||
|
|
||||||
|
|
||||||
public TapetiConfig(IDependencyResolver dependencyResolver)
|
public TapetiConfig(IDependencyResolver dependencyResolver)
|
||||||
{
|
{
|
||||||
@ -90,7 +93,16 @@ namespace Tapeti
|
|||||||
queues.AddRange(dynamicBindings.Select(bl => new Queue(new QueueInfo { Dynamic = true, Name = GetDynamicQueueName(prefixGroup.Key) }, bl)));
|
queues.AddRange(dynamicBindings.Select(bl => new Queue(new QueueInfo { Dynamic = true, Name = GetDynamicQueueName(prefixGroup.Key) }, bl)));
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = new Config(dependencyResolver, messageMiddleware, cleanupMiddleware, publishMiddleware, queues);
|
var config = new Config(queues)
|
||||||
|
{
|
||||||
|
DependencyResolver = dependencyResolver,
|
||||||
|
MessageMiddleware = messageMiddleware,
|
||||||
|
CleanupMiddleware = cleanupMiddleware,
|
||||||
|
PublishMiddleware = publishMiddleware,
|
||||||
|
|
||||||
|
UsePublisherConfirms = usePublisherConfirms
|
||||||
|
};
|
||||||
|
|
||||||
(dependencyResolver as IDependencyContainer)?.RegisterDefaultSingleton<IConfig>(config);
|
(dependencyResolver as IDependencyContainer)?.RegisterDefaultSingleton<IConfig>(config);
|
||||||
|
|
||||||
return config;
|
return config;
|
||||||
@ -155,10 +167,33 @@ namespace Tapeti
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WARNING: disabling publisher confirms means there is no guarantee that a Publish succeeds,
|
||||||
|
/// and disables Tapeti.Flow from verifying if a request/response can be routed. This may
|
||||||
|
/// result in never-ending flows. Only disable if you can accept those consequences.
|
||||||
|
/// </summary>
|
||||||
|
public TapetiConfig DisablePublisherConfirms()
|
||||||
|
{
|
||||||
|
usePublisherConfirms = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// WARNING: disabling publisher confirms means there is no guarantee that a Publish succeeds,
|
||||||
|
/// and disables Tapeti.Flow from verifying if a request/response can be routed. This may
|
||||||
|
/// result in never-ending flows. Only disable if you accept those consequences.
|
||||||
|
/// </summary>
|
||||||
|
public TapetiConfig SetPublisherConfirms(bool enabled)
|
||||||
|
{
|
||||||
|
usePublisherConfirms = enabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void RegisterDefaults()
|
public void RegisterDefaults()
|
||||||
{
|
{
|
||||||
var container = dependencyResolver as IDependencyContainer;
|
if (!(dependencyResolver is IDependencyContainer container))
|
||||||
if (container == null)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ConsoleHelper.IsAvailable())
|
if (ConsoleHelper.IsAvailable())
|
||||||
@ -399,21 +434,19 @@ namespace Tapeti
|
|||||||
|
|
||||||
protected class Config : IConfig
|
protected class Config : IConfig
|
||||||
{
|
{
|
||||||
public IDependencyResolver DependencyResolver { get; }
|
public bool UsePublisherConfirms { get; set; }
|
||||||
public IReadOnlyList<IMessageMiddleware> MessageMiddleware { get; }
|
|
||||||
public IReadOnlyList<ICleanupMiddleware> CleanupMiddleware { get; }
|
public IDependencyResolver DependencyResolver { get; set; }
|
||||||
public IReadOnlyList<IPublishMiddleware> PublishMiddleware { get; }
|
public IReadOnlyList<IMessageMiddleware> MessageMiddleware { get; set; }
|
||||||
|
public IReadOnlyList<ICleanupMiddleware> CleanupMiddleware { get; set; }
|
||||||
|
public IReadOnlyList<IPublishMiddleware> PublishMiddleware { get; set; }
|
||||||
public IEnumerable<IQueue> Queues { get; }
|
public IEnumerable<IQueue> Queues { get; }
|
||||||
|
|
||||||
private readonly Dictionary<MethodInfo, IBinding> bindingMethodLookup;
|
private readonly Dictionary<MethodInfo, IBinding> bindingMethodLookup;
|
||||||
|
|
||||||
|
|
||||||
public Config(IDependencyResolver dependencyResolver, IReadOnlyList<IMessageMiddleware> messageMiddleware, IReadOnlyList<ICleanupMiddleware> cleanupMiddleware, IReadOnlyList<IPublishMiddleware> publishMiddleware, IEnumerable<IQueue> queues)
|
public Config(IEnumerable<IQueue> queues)
|
||||||
{
|
{
|
||||||
DependencyResolver = dependencyResolver;
|
|
||||||
MessageMiddleware = messageMiddleware;
|
|
||||||
CleanupMiddleware = cleanupMiddleware;
|
|
||||||
PublishMiddleware = publishMiddleware;
|
|
||||||
Queues = queues.ToList();
|
Queues = queues.ToList();
|
||||||
|
|
||||||
bindingMethodLookup = Queues.SelectMany(q => q.Bindings).ToDictionary(b => b.Method, b => b);
|
bindingMethodLookup = Queues.SelectMany(q => q.Bindings).ToDictionary(b => b.Method, b => b);
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Tapeti;
|
|
||||||
|
|
||||||
namespace Test
|
|
||||||
{
|
|
||||||
public class MyLogger : ILogger
|
|
||||||
{
|
|
||||||
public void Connect(TapetiConnectionParams connectionParams)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ConnectFailed(TapetiConnectionParams connectionParams, Exception exception)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ConnectSuccess(TapetiConnectionParams connectionParams)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public void HandlerException(Exception e)
|
|
||||||
{
|
|
||||||
Console.WriteLine("Mylogger: " + e.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
103
Test/Program.cs
103
Test/Program.cs
@ -5,7 +5,6 @@ using Tapeti.DataAnnotations;
|
|||||||
using Tapeti.Flow;
|
using Tapeti.Flow;
|
||||||
using Tapeti.SimpleInjector;
|
using Tapeti.SimpleInjector;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using Tapeti.Flow.SQL;
|
|
||||||
|
|
||||||
namespace Test
|
namespace Test
|
||||||
{
|
{
|
||||||
@ -14,58 +13,60 @@ namespace Test
|
|||||||
private static void Main()
|
private static void Main()
|
||||||
{
|
{
|
||||||
// TODO logging
|
// TODO logging
|
||||||
|
try
|
||||||
var container = new Container();
|
|
||||||
container.Register<MarcoEmitter>();
|
|
||||||
container.Register<Visualizer>();
|
|
||||||
container.Register<ILogger, Tapeti.Default.ConsoleLogger>();
|
|
||||||
|
|
||||||
var config = new TapetiConfig(new SimpleInjectorDependencyResolver(container))
|
|
||||||
//.WithFlowSqlRepository("Server=localhost;Database=TapetiTest;Integrated Security=true")
|
|
||||||
.WithFlow()
|
|
||||||
.WithDataAnnotations()
|
|
||||||
.RegisterAllControllers()
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
using (var connection = new TapetiConnection(config)
|
|
||||||
{
|
{
|
||||||
Params = new TapetiAppSettingsConnectionParams()
|
var container = new Container();
|
||||||
})
|
container.Register<MarcoEmitter>();
|
||||||
|
container.Register<Visualizer>();
|
||||||
|
container.Register<ILogger, Tapeti.Default.ConsoleLogger>();
|
||||||
|
|
||||||
|
var config = new TapetiConfig(new SimpleInjectorDependencyResolver(container))
|
||||||
|
//.WithFlowSqlRepository("Server=localhost;Database=TapetiTest;Integrated Security=true")
|
||||||
|
.WithFlow()
|
||||||
|
.WithDataAnnotations()
|
||||||
|
.RegisterAllControllers()
|
||||||
|
//.DisablePublisherConfirms() -> you probably never want to do this if you're using Flow or want requeues when a publish fails
|
||||||
|
.Build();
|
||||||
|
|
||||||
|
using (var connection = new TapetiConnection(config)
|
||||||
|
{
|
||||||
|
Params = new TapetiAppSettingsConnectionParams()
|
||||||
|
})
|
||||||
|
{
|
||||||
|
var flowStore = container.GetInstance<IFlowStore>();
|
||||||
|
var flowStore2 = container.GetInstance<IFlowStore>();
|
||||||
|
|
||||||
|
Console.WriteLine("IFlowHandler is singleton = " + (flowStore == flowStore2));
|
||||||
|
|
||||||
|
connection.Connected += (sender, e) => { Console.WriteLine("Event Connected"); };
|
||||||
|
connection.Disconnected += (sender, e) => { Console.WriteLine("Event Disconnected"); };
|
||||||
|
connection.Reconnected += (sender, e) => { Console.WriteLine("Event Reconnected"); };
|
||||||
|
|
||||||
|
Console.WriteLine("Subscribing...");
|
||||||
|
var subscriber = connection.Subscribe(false).Result;
|
||||||
|
|
||||||
|
Console.WriteLine("Consuming...");
|
||||||
|
subscriber.Resume().Wait();
|
||||||
|
|
||||||
|
Console.WriteLine("Done!");
|
||||||
|
|
||||||
|
connection.GetPublisher().Publish(new FlowEndController.PingMessage());
|
||||||
|
|
||||||
|
//container.GetInstance<IFlowStarter>().Start<MarcoController, bool>(c => c.StartFlow, true).Wait();
|
||||||
|
container.GetInstance<IFlowStarter>().Start<MarcoController>(c => c.TestParallelRequest).Wait();
|
||||||
|
|
||||||
|
Thread.Sleep(1000);
|
||||||
|
|
||||||
|
var emitter = container.GetInstance<MarcoEmitter>();
|
||||||
|
emitter.Run().Wait();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
var flowStore = container.GetInstance<IFlowStore>();
|
Console.WriteLine(e.ToString());
|
||||||
var flowStore2 = container.GetInstance<IFlowStore>();
|
Console.ReadKey();
|
||||||
|
|
||||||
Console.WriteLine("IFlowHandler is singleton = " + (flowStore == flowStore2));
|
|
||||||
|
|
||||||
connection.Connected += (sender, e) => {
|
|
||||||
Console.WriteLine("Event Connected");
|
|
||||||
};
|
|
||||||
connection.Disconnected += (sender, e) => {
|
|
||||||
Console.WriteLine("Event Disconnected");
|
|
||||||
};
|
|
||||||
connection.Reconnected += (sender, e) => {
|
|
||||||
Console.WriteLine("Event Reconnected");
|
|
||||||
};
|
|
||||||
|
|
||||||
Console.WriteLine("Subscribing...");
|
|
||||||
var subscriber = connection.Subscribe(false).Result;
|
|
||||||
|
|
||||||
Console.WriteLine("Consuming...");
|
|
||||||
subscriber.Resume().Wait();
|
|
||||||
|
|
||||||
Console.WriteLine("Done!");
|
|
||||||
|
|
||||||
connection.GetPublisher().Publish(new FlowEndController.PingMessage());
|
|
||||||
|
|
||||||
//container.GetInstance<IFlowStarter>().Start<MarcoController, bool>(c => c.StartFlow, true);
|
|
||||||
container.GetInstance<IFlowStarter>().Start<MarcoController>(c => c.TestParallelRequest);
|
|
||||||
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
|
|
||||||
var emitter = container.GetInstance<MarcoEmitter>();
|
|
||||||
emitter.Run().Wait();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user