Particular / NServiceBus

Build, version, and monitor better microservices with the most powerful service platform for .NET
https://particular.net/nservicebus/
Other
2.1k stars 647 forks source link

ActiveMQ uses DTCTransactionSessionFactory after it is disposed #1393

Closed SimonCropp closed 11 years ago

SimonCropp commented 11 years ago

So when closing down ActiveMQ we first close down the satellites

https://github.com/NServiceBus/NServiceBus/blob/master/src/NServiceBus.Core/Satellites/SatelliteLauncher.cs#L72

    public void Stop()
    {
        Parallel.ForEach(satellites, (ctx, state, index) =>
            {
                Logger.DebugFormat("Stopping {1}/{2} '{0}' satellite", ctx.Instance.GetType().AssemblyQualifiedName,
                                   index + 1, satellites.Count);

                if (ctx.Transport != null)
                {
                    ctx.Transport.Stop();
                }

Which gives us a stack trace of

NServiceBus.Transports.ActiveMQ.SessionFactories.DTCTransactionSessionFactory.Dispose() Line 77 C#
NServiceBus.Transports.ActiveMQ.ActiveMqMessageDequeueStrategy.Stop() Line 78 + 0x41 bytes  C#
NServiceBus.Unicast.Transport.TransportReceiver.Stop() Line 383 + 0x34 bytes    C#
NServiceBus.Satellites.SatelliteLauncher.Stop Line 72 + 0x38 bytes  C#

Next the UnicastBus will shutdown which will get us into here

https://github.com/NServiceBus/NServiceBus/blob/master/src/ActiveMQ/NServiceBus.ActiveMQ/ActiveMqMessageDequeueStrategy.cs#L72

    public void Stop()
    {
        foreach (INotifyMessageReceived messageReceiver in messageReceivers)
        {
            messageReceiver.Stop();
        }

        foreach (INotifyMessageReceived messageReceiver in messageReceivers)
        {
            messageReceiver.Dispose();
        }

        messageReceivers.Clear();
        sessionFactory.Dispose();
    }

Note that the messageReceivers are being disposed. So if you follow that stack down it give us this

NServiceBus.Transports.ActiveMQ.SessionFactories.DTCTransactionSessionFactory.Release(Apache.NMS.ISession session) Line 36  C#
NServiceBus.Transports.ActiveMQ.Receivers.MessageProcessor.Dispose(bool disposing) Line 78 + 0x3c bytes C#
NServiceBus.Transports.ActiveMQ.Receivers.MessageProcessor.Dispose() Line 65 + 0xc bytes    C#
NServiceBus.Transports.ActiveMQ.Receivers.ActiveMqMessageReceiver.Dispose(bool disposing) Line 65 + 0x2f bytes  C#
NServiceBus.Transports.ActiveMQ.Receivers.ActiveMqMessageReceiver.Dispose() Line 30 + 0x16 bytes    C#
NServiceBus.Transports.ActiveMQ.ActiveMqMessageDequeueStrategy.Stop() Line 74 + 0x29 bytes  C#
NServiceBus.Unicast.Transport.TransportReceiver.Stop() Line 383 + 0x34 bytes    C#
NServiceBus.Unicast.UnicastBus.Shutdown() Line 944 + 0x36 bytes C#
NServiceBus.Unicast.UnicastBus.Dispose(bool disposing) Line 893 + 0xa bytes C#
NServiceBus.Unicast.UnicastBus.Dispose() Line 874 + 0x16 bytes  C#

So note that in MessageProcessor it calls sessionFactory.Release(session); https://github.com/NServiceBus/NServiceBus/blob/master/src/ActiveMQ/NServiceBus.ActiveMQ/Receivers/MessageProcessor.cs#L78

    private void Dispose(bool disposing)
    {
        if (disposed)
        {
            return;
        }

        if (disposing)
        {
            sessionFactory.Release(session);
        }

The problem is that the sessionFactory has already been disposed.

So we essentially have an order/corrupted state issue here

danielmarbach commented 11 years ago

If I remember correctly we raised this issue previously. The shutdown sequence was a bit wrong since the start... But can't find the issue now because only on the mobile

Am 06.08.2013 um 05:24 schrieb Simon Cropp notifications@github.com:

So when closing down ActiveMQ we first close down the satellites

https://github.com/NServiceBus/NServiceBus/blob/master/src/NServiceBus.Core/Satellites/SatelliteLauncher.cs#L72

public void Stop()
{
    Parallel.ForEach(satellites, (ctx, state, index) =>
        {
            Logger.DebugFormat("Stopping {1}/{2} '{0}' satellite", ctx.Instance.GetType().AssemblyQualifiedName,
                               index + 1, satellites.Count);

            if (ctx.Transport != null)
            {
                ctx.Transport.Stop();
            }

Which gives us a stack trace of

NServiceBus.Transports.ActiveMQ.SessionFactories.DTCTransactionSessionFactory.Dispose() Line 77 C# NServiceBus.Transports.ActiveMQ.ActiveMqMessageDequeueStrategy.Stop() Line 78 + 0x41 bytes C# NServiceBus.Unicast.Transport.TransportReceiver.Stop() Line 383 + 0x34 bytes C# NServiceBus.Satellites.SatelliteLauncher.Stop Line 72 + 0x38 bytes C# Next the UnicastBus will shutdown which will get us into here

https://github.com/NServiceBus/NServiceBus/blob/master/src/ActiveMQ/NServiceBus.ActiveMQ/ActiveMqMessageDequeueStrategy.cs#L72

public void Stop()
{
    foreach (INotifyMessageReceived messageReceiver in messageReceivers)
    {
        messageReceiver.Stop();
    }

    foreach (INotifyMessageReceived messageReceiver in messageReceivers)
    {
        messageReceiver.Dispose();
    }

    messageReceivers.Clear();
    sessionFactory.Dispose();
}

Note that the messageReceivers are being disposed. So if you follow that stack down it give us this

NServiceBus.Transports.ActiveMQ.SessionFactories.DTCTransactionSessionFactory.Release(Apache.NMS.ISession session) Line 36 C# NServiceBus.Transports.ActiveMQ.Receivers.MessageProcessor.Dispose(bool disposing) Line 78 + 0x3c bytes C# NServiceBus.Transports.ActiveMQ.Receivers.MessageProcessor.Dispose() Line 65 + 0xc bytes C# NServiceBus.Transports.ActiveMQ.Receivers.ActiveMqMessageReceiver.Dispose(bool disposing) Line 65 + 0x2f bytes C# NServiceBus.Transports.ActiveMQ.Receivers.ActiveMqMessageReceiver.Dispose() Line 30 + 0x16 bytes C# NServiceBus.Transports.ActiveMQ.ActiveMqMessageDequeueStrategy.Stop() Line 74 + 0x29 bytes C# NServiceBus.Unicast.Transport.TransportReceiver.Stop() Line 383 + 0x34 bytes C# NServiceBus.Unicast.UnicastBus.Shutdown() Line 944 + 0x36 bytes C# NServiceBus.Unicast.UnicastBus.Dispose(bool disposing) Line 893 + 0xa bytes C# NServiceBus.Unicast.UnicastBus.Dispose() Line 874 + 0x16 bytes C# So note that in MessageProcessor it calls sessionFactory.Release(session); https://github.com/NServiceBus/NServiceBus/blob/master/src/ActiveMQ/NServiceBus.ActiveMQ/Receivers/MessageProcessor.cs#L78

private void Dispose(bool disposing)
{
    if (disposed)
    {
        return;
    }

    if (disposing)
    {
        sessionFactory.Release(session);
    }

The problem is that the sessionFactory has already been disposed.

So we essentially have an order/corrupted state issue here

— Reply to this email directly or view it on GitHub.

SimonCropp commented 11 years ago

moved to https://github.com/Particular/NServiceBus.ActiveMQ/issues/7

remogloor commented 11 years ago

The reason for this is that there should be one session factory per transport instance (main, satelite transport). Because NServiceBus doesn't use a dedicated IoC container for internal construction this is nearly impossible to build it that way using the IoC Container because the lifetime managment of the various IoC containers it too diffrent.

Either use a dedicated IoC container for internal construction and use the configurable one just for external dependencies or change the ActiveMQ transport construction that it is not built by the IoC container but a hardcoded factory.

SimonCropp commented 11 years ago

@remogloor can you move your comment to the activemq repository

johnsimons commented 11 years ago

Already there