MassTransit和服务结构有状态服务?

MassTransit和服务结构有状态服务?,masstransit,service-fabric-stateful,Masstransit,Service Fabric Stateful,我一直在尝试制作一个网站的演示,该网站使用MassTransit和RabbitMQ将消息作为有状态服务发布到服务结构上运行的服务 一切都很顺利,我的客户会发布一条消息: IBusControl bus = BusConfigurator.ConfigureBus(); Uri sendToUri = new Uri($"{RabbitMqConstants.RabbitMqUri}" + $"{RabbitMqConstants.PeopleServiceQueue}"); ISendEndpo

我一直在尝试制作一个网站的演示,该网站使用MassTransit和RabbitMQ将消息作为有状态服务发布到服务结构上运行的服务

一切都很顺利,我的客户会发布一条消息:

IBusControl bus = BusConfigurator.ConfigureBus();
Uri sendToUri = new Uri($"{RabbitMqConstants.RabbitMqUri}" + $"{RabbitMqConstants.PeopleServiceQueue}");
ISendEndpoint endPoint = await bus.GetSendEndpoint(sendToUri);

await endPoint.Send<ICompanyRequest>(new {CompanyId = id });
然后,在我的消息消费者类中,我可以执行以下操作:

    internal sealed class PersonInformationConsumer : StatefulService, IConsumer<ICompanyRequest>
{
    private static StatefulServiceContext _currentContext;

    #region Constructors

    public PersonInformationConsumer(StatefulServiceContext serviceContext) : base(serviceContext)
    {
        _currentContext = serviceContext;
    }

    public PersonInformationConsumer() : base(_currentContext)
    {
    }
我现在遇到的问题是试图在IReliableDictionary上存储一些内容,这样做会导致“对象引用未设置为对象实例”错误:(…任何想法都将受到欢迎(尽管可能直到新年才阅读!)

公共异步任务使用(consumercontext)
{
ServiceEventSource.Current.ServiceMessage(this.Context,“消息已被使用,请求Id:{0}”,Context.Message.CompanyId);
使用(ITransaction tx=StateManager.CreateTransaction())
{
尝试
{
var myDictionary=await StateManager.GetOrAddAsync(“myDictionary”);

这是导致错误的原因。…帮助!:)

要使MassTransit和有状态服务协同工作,您需要做更多的工作,这里有几个问题需要您自己考虑

只有一个有状态分区内的主机(n个分区内的n个主机)将能够写入/更新有状态服务,所有副本在尝试写回任何状态时都会抛出异常。因此,您需要处理此问题,表面上看,这听起来很容易,直到您考虑到由于重新平衡群集(通用服务结构appli的默认设置),主机可以在群集周围移动这就是关闭副本上的处理,只在主机上运行工作。这都是通过RunAsync方法完成的(尝试一下,在RunAsync方法中使用noddy运行3个有状态服务,然后终止主机)

还有你的数据分区要考虑,由于有分区服务的状态服务规模,你需要创建一种分配数据到你的服务总线上的端点的方法,也许有一个单独的队列只侦听一个给定的分区范围?比如说你有一个<代码>用户创建的消息,你可以把它拆分在<代码> C上。国家

英国
转到分区1,
美国
转到分区2等

如果您只是想让一些基本的东西启动并运行,我会将它限制在一个分区内,然后尝试将您的总线创建放在RunAsync中,并在取消令牌上请求取消后关闭总线

protected override async Task RunAsync(CancellationToken cancellationToken)
{
    var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
    {
        IRabbitMqHost host = cfg.Host(new Uri(RabbitMqConstants.RabbitMqUri), h =>
        {
            h.Username(RabbitMqConstants.UserName);
            h.Password(RabbitMqConstants.Password);
        });

        cfg.ReceiveEndpoint(host, RabbitMqConstants.PeopleServiceQueue, e =>
        {
            // Pass in the stateful service context
            e.Consumer(c => new PersonInformationConsumer(Context));
        });

    });

    busControl.Start();

    while (true)
    {
        if(cancellationToken.CancellationRequested)
        {
            //Service Fabric wants us to stop
            busControl.Stop();

            cancellationToken.ThrowIfCancellationRequested();
        }

        await Task.Delay(TimeSpan.FromSeconds(1));
    }
}

我没有安装service fabric SDK,但是看到在异步方法中访问静态类会让我停顿,当然还有另一种方法可以访问可靠的字典实例。我使用服务侦听器对其进行了一些POC,请查看此示例-
    internal sealed class PersonInformationConsumer : StatefulService, IConsumer<ICompanyRequest>
{
    private static StatefulServiceContext _currentContext;

    #region Constructors

    public PersonInformationConsumer(StatefulServiceContext serviceContext) : base(serviceContext)
    {
        _currentContext = serviceContext;
    }

    public PersonInformationConsumer() : base(_currentContext)
    {
    }
ServiceEventSource.Current.ServiceMessage(this.Context, "Message has been consumed, request Id: {0}", context.Message.CompanyId);
        public async Task Consume(ConsumeContext<ICompanyRequest> context)
    {

        ServiceEventSource.Current.ServiceMessage(this.Context, "Message has been consumed, request Id: {0}", context.Message.CompanyId);

        using (ITransaction tx = StateManager.CreateTransaction())
        {

            try
            {

                var myDictionary = await StateManager.GetOrAddAsync<IReliableDictionary<string, long>>("myDictionary");
protected override async Task RunAsync(CancellationToken cancellationToken)
{
    var busControl = Bus.Factory.CreateUsingRabbitMq(cfg =>
    {
        IRabbitMqHost host = cfg.Host(new Uri(RabbitMqConstants.RabbitMqUri), h =>
        {
            h.Username(RabbitMqConstants.UserName);
            h.Password(RabbitMqConstants.Password);
        });

        cfg.ReceiveEndpoint(host, RabbitMqConstants.PeopleServiceQueue, e =>
        {
            // Pass in the stateful service context
            e.Consumer(c => new PersonInformationConsumer(Context));
        });

    });

    busControl.Start();

    while (true)
    {
        if(cancellationToken.CancellationRequested)
        {
            //Service Fabric wants us to stop
            busControl.Stop();

            cancellationToken.ThrowIfCancellationRequested();
        }

        await Task.Delay(TimeSpan.FromSeconds(1));
    }
}