NServiceBus能否以不同的速率将事件处理到不同的队列?

NServiceBus能否以不同的速率将事件处理到不同的队列?,nservicebus,Nservicebus,我有两个订户参加同一个活动。一个订阅服务器写入数据库,另一个在内存中缓存数据。前者比后者需要更长的时间,这没关系,因为缓存比写入数据库更需要时间。有时候DB编写器落后了,它的队列开始增长,这没关系(只要它最终赶上)。但是,缓存订阅服务器落后是不可接受的。当DB编写器跟不上时,它可以超越DB编写器。我希望尽快处理这两个队列,而不让一个队列的处理影响另一个队列的处理 但是,我看到的是,当DB编写器队列增长时,缓存订户的队列也会增长。这两个队列具有相同数量的挂起项目。他们似乎步调一致 分析表明,DB写

我有两个订户参加同一个活动。一个订阅服务器写入数据库,另一个在内存中缓存数据。前者比后者需要更长的时间,这没关系,因为缓存比写入数据库更需要时间。有时候DB编写器落后了,它的队列开始增长,这没关系(只要它最终赶上)。但是,缓存订阅服务器落后是不可接受的。当DB编写器跟不上时,它可以超越DB编写器。我希望尽快处理这两个队列,而不让一个队列的处理影响另一个队列的处理

但是,我看到的是,当DB编写器队列增长时,缓存订户的队列也会增长。这两个队列具有相同数量的挂起项目。他们似乎步调一致

分析表明,DB写入所需的时间大约是内存缓存的500倍(这并不奇怪)。因此,缓存订阅服务器可以很容易地跟上,但它似乎被DB writer订阅服务器阻止了

我会为前面的代码道歉。如果没有端点包装器代码,则更容易理解

此方法将端点创建为事件发布者。(我的包装器代码为不同的目的提供了不同的端点类型。我发现缺少NSB端点抽象):

以下是要点:

public sealed class EventPublisherEndpoint : Endpoint, IEventPublisherEndpoint
{
    private EventPublisherEndpoint(IEndpointInstance nsbEndpoint, string name) : base(nsbEndpoint, name) { }

    /// <summary>
    /// Create and start endpoint.
    /// </summary>
    public static async Task<IEventPublisherEndpoint> Start(string endpointName)
    {
        var ep = await ConfigureEndpoint(new EndpointConfig(), endpointName);
        return new EventPublisherEndpoint(ep, endpointName);
    }

    public async Task Publish(object message)
    {
        await NsbEndpoint.Publish(message);
    }
}
public sealed class EventSubscriberEndpoint<T> : Endpoint, IEventSubscriberEndpoint where T : IEvent
{
    private EventSubscriberEndpoint(IEndpointInstance nsbEndpoint, string name) : base(nsbEndpoint, name) {}

    public async Task Unsubscribe()
    {
        await NsbEndpoint.Unsubscribe(typeof(T), new UnsubscribeOptions());
    }

    /// <summary>
    /// Create and start endpoint.
    /// </summary>
    public static async Task<IEventSubscriberEndpoint> Start(
        string endpointName,
        string publisherEndpointName,
        Type[] excludeSubscriberTypes = null)
    {
        return await Start(endpointName, publisherEndpointName, typeof(T), excludeSubscriberTypes);
    }

    /// <summary>
    /// Non-generic version of Start.
    /// </summary>
    private static async Task<IEventSubscriberEndpoint> Start(
        string endpointName,
        string publisherEndpointName,
        Type messageType,
        Type[] excludeSubscriberTypes = null)
    {
        return await Start(new EndpointConfig(), endpointName, publisherEndpointName, messageType, excludeSubscriberTypes);
    }

    private static async Task<IEventSubscriberEndpoint> Start(
        IEndpointConfig config,
        string endpointName,
        string publisherEndpointName,
        Type messageType,
        Type[] excludeSubscriberTypes = null)
    {
        if (publisherEndpointName == null)
            throw new ArgumentNullException(nameof(publisherEndpointName));
        if (messageType == null)
            throw new ArgumentNullException(nameof(messageType));

        var ep = await ConfigureEndpoint(config,
            endpointName,
            endpointConfiguration =>
            {
                if (excludeSubscriberTypes != null)
                    endpointConfiguration.AssemblyScanner().ExcludeTypes(excludeSubscriberTypes);
            }, transport =>
            {
                transport.Routing().RegisterPublisher(messageType, GetFullName(publisherEndpointName));
            });
        return new EventSubscriberEndpoint<T>(ep, endpointName);
    }
}
以下是事件类:

public sealed class Datagram : DeviceOutput, IEvent
{
    public Datagram(long deviceID, DatagramType payloadType, string payload) : base(deviceID)
    {
        Payload = payload;
        PayloadType = payloadType;
    }

    public string Payload { get; set; }

    public DatagramType PayloadType { get; set; }

    public override string ToString()
    {
        return base.ToString() + Environment.NewLine + $"PayloadType:{PayloadType} Payload:{Payload.Truncate()}";
    }
}
以下是订阅服务器端点配置之一:

    public async Task Start()
    {
        if (_endpoint == null)
        {
            _endpoint = await EventSubscriberEndpoint<Datagram>.Start(
                endpointName: "datagram-store-subscriber",
                publisherEndpointName: DatagramPublisher.EndpointName);
        }
    }
    public async Task Start()
    {
        if (_endpoint == null)
        {
            _endpoint = await EventSubscriberEndpoint<Datagram>.Start(
                endpointName: "datagram-live-subscriber",
                publisherEndpointName: DatagramPublisher.EndpointName);
        }
    }
以下是另一个订阅服务器端点配置:

    public async Task Start()
    {
        if (_endpoint == null)
        {
            _endpoint = await EventSubscriberEndpoint<Datagram>.Start(
                endpointName: "datagram-store-subscriber",
                publisherEndpointName: DatagramPublisher.EndpointName);
        }
    }
    public async Task Start()
    {
        if (_endpoint == null)
        {
            _endpoint = await EventSubscriberEndpoint<Datagram>.Start(
                endpointName: "datagram-live-subscriber",
                publisherEndpointName: DatagramPublisher.EndpointName);
        }
    }
以下是EventSubscriberEndpoint:

public sealed class EventPublisherEndpoint : Endpoint, IEventPublisherEndpoint
{
    private EventPublisherEndpoint(IEndpointInstance nsbEndpoint, string name) : base(nsbEndpoint, name) { }

    /// <summary>
    /// Create and start endpoint.
    /// </summary>
    public static async Task<IEventPublisherEndpoint> Start(string endpointName)
    {
        var ep = await ConfigureEndpoint(new EndpointConfig(), endpointName);
        return new EventPublisherEndpoint(ep, endpointName);
    }

    public async Task Publish(object message)
    {
        await NsbEndpoint.Publish(message);
    }
}
public sealed class EventSubscriberEndpoint<T> : Endpoint, IEventSubscriberEndpoint where T : IEvent
{
    private EventSubscriberEndpoint(IEndpointInstance nsbEndpoint, string name) : base(nsbEndpoint, name) {}

    public async Task Unsubscribe()
    {
        await NsbEndpoint.Unsubscribe(typeof(T), new UnsubscribeOptions());
    }

    /// <summary>
    /// Create and start endpoint.
    /// </summary>
    public static async Task<IEventSubscriberEndpoint> Start(
        string endpointName,
        string publisherEndpointName,
        Type[] excludeSubscriberTypes = null)
    {
        return await Start(endpointName, publisherEndpointName, typeof(T), excludeSubscriberTypes);
    }

    /// <summary>
    /// Non-generic version of Start.
    /// </summary>
    private static async Task<IEventSubscriberEndpoint> Start(
        string endpointName,
        string publisherEndpointName,
        Type messageType,
        Type[] excludeSubscriberTypes = null)
    {
        return await Start(new EndpointConfig(), endpointName, publisherEndpointName, messageType, excludeSubscriberTypes);
    }

    private static async Task<IEventSubscriberEndpoint> Start(
        IEndpointConfig config,
        string endpointName,
        string publisherEndpointName,
        Type messageType,
        Type[] excludeSubscriberTypes = null)
    {
        if (publisherEndpointName == null)
            throw new ArgumentNullException(nameof(publisherEndpointName));
        if (messageType == null)
            throw new ArgumentNullException(nameof(messageType));

        var ep = await ConfigureEndpoint(config,
            endpointName,
            endpointConfiguration =>
            {
                if (excludeSubscriberTypes != null)
                    endpointConfiguration.AssemblyScanner().ExcludeTypes(excludeSubscriberTypes);
            }, transport =>
            {
                transport.Routing().RegisterPublisher(messageType, GetFullName(publisherEndpointName));
            });
        return new EventSubscriberEndpoint<T>(ep, endpointName);
    }
}
公共密封类EventSubscriberEndpoint:Endpoint,IEventSubscriberEndpoint其中T:IEvent
{
private EventSubscriberEndpoint(IEndpointInstance nsbEndpoint,字符串名称):基(nsbEndpoint,名称){}
公共异步任务取消订阅()
{
等待NsbEndpoint.Unsubscribe(typeof(T),new Unsubscribe options());
}
/// 
///创建和启动端点。
/// 
公共静态异步任务启动(
字符串端点名称,
字符串名称,
类型[]excludeSubscriberTypes=null)
{
返回等待开始(endpointName、publisherEndpointName、typeof(T)、excludeSubscriberTypes);
}
/// 
///启动的非通用版本。
/// 
专用静态异步任务启动(
字符串端点名称,
字符串名称,
类型messageType,
类型[]excludeSubscriberTypes=null)
{
返回等待启动(new EndpointConfig()、endpointName、publisherEndpointName、messageType、excludeSubscriberTypes);
}
专用静态异步任务启动(
IEndpointConfig配置,
字符串端点名称,
字符串名称,
类型messageType,
类型[]excludeSubscriberTypes=null)
{
if(publisherEndpointName==null)
抛出新ArgumentNullException(nameof(publisherEndpointName));
if(messageType==null)
抛出新ArgumentNullException(nameof(messageType));
var ep=等待配置端点(配置,
端点名称,
endpointConfiguration=>
{
if(excludeSubscriberTypes!=null)
endpointConfiguration.AssemblyScanner().ExcludeTypes(excludeSubscriberTypes);
},运输=>
{
transport.Routing().RegisterPublisher(messageType,GetFullName(publisherEndpointName));
});
返回新的EventSubscriberEndpoint(ep,endpointName);
}
}
是否有允许队列相互独立处理的特殊配置


NServiceBus 6.2.1

这里的主要问题是如何发布事件(如果是实际事件?)以及如何处理这些事件。你能把代码也发到发布者/订阅者的位子上吗?从理论上讲,同一事件的两个处理程序之间没有耦合,如果你真的要引发一个事件,那么它们应该分别处理消息的副本,但我认为你想要的不是这样?因为有一个固有的顺序(先写数据库,然后缓存),所以最好在数据库更新后发出一个命令来同步缓存?为您添加了很多代码。。。msg作为事件发布。我不知道“如何处理事件”是什么意思,因为我只知道一种方法:定义处理程序方法。。。当DB写入备份时,我希望live处理程序保持最新状态。不希望处理程序同步。。。顺便说一句,我通过将处理程序放在单独的进程中解决了我的问题。幸运的是,该系统已经有了一个适合这一目的的流程。尽管如此,我认为NSB应该提供一种在同一进程中以不同速率处理事件的方法。我是否正确理解有两种类型的消息进入同一队列?很长一段时间以来,NSB端点都绑定到AppDomain,因此即使可以在一个进程中运行多个端点,这样做也不是很简单。如果希望并行运行事件订阅处理程序,则将它们放在两个进程中的操作是正确的。这显示了如何在一个项目/流程/应用域中承载多个端点:Nope。在队列中输入一个类型。一个端点用于发布,两个端点用于处理事件
public sealed class EventSubscriberEndpoint<T> : Endpoint, IEventSubscriberEndpoint where T : IEvent
{
    private EventSubscriberEndpoint(IEndpointInstance nsbEndpoint, string name) : base(nsbEndpoint, name) {}

    public async Task Unsubscribe()
    {
        await NsbEndpoint.Unsubscribe(typeof(T), new UnsubscribeOptions());
    }

    /// <summary>
    /// Create and start endpoint.
    /// </summary>
    public static async Task<IEventSubscriberEndpoint> Start(
        string endpointName,
        string publisherEndpointName,
        Type[] excludeSubscriberTypes = null)
    {
        return await Start(endpointName, publisherEndpointName, typeof(T), excludeSubscriberTypes);
    }

    /// <summary>
    /// Non-generic version of Start.
    /// </summary>
    private static async Task<IEventSubscriberEndpoint> Start(
        string endpointName,
        string publisherEndpointName,
        Type messageType,
        Type[] excludeSubscriberTypes = null)
    {
        return await Start(new EndpointConfig(), endpointName, publisherEndpointName, messageType, excludeSubscriberTypes);
    }

    private static async Task<IEventSubscriberEndpoint> Start(
        IEndpointConfig config,
        string endpointName,
        string publisherEndpointName,
        Type messageType,
        Type[] excludeSubscriberTypes = null)
    {
        if (publisherEndpointName == null)
            throw new ArgumentNullException(nameof(publisherEndpointName));
        if (messageType == null)
            throw new ArgumentNullException(nameof(messageType));

        var ep = await ConfigureEndpoint(config,
            endpointName,
            endpointConfiguration =>
            {
                if (excludeSubscriberTypes != null)
                    endpointConfiguration.AssemblyScanner().ExcludeTypes(excludeSubscriberTypes);
            }, transport =>
            {
                transport.Routing().RegisterPublisher(messageType, GetFullName(publisherEndpointName));
            });
        return new EventSubscriberEndpoint<T>(ep, endpointName);
    }
}