akkadotnet / Alpakka

Akka Streams Connectors - Alpakka

Home Page:https://alpakka.getakka.net/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Restarted AMQP Source does not recreates auto-delete queue

vasily-kirichenko opened this issue · comments

let system = ActorSystem.Create("test", ConfigurationFactory.Load())
let mat = ActorMaterializer.Create(system, ActorMaterializerSettings.Create(system).WithSupervisionStrategy(Deciders.ResumingDecider))

let connSettings = 
    AmqpConnectionDetails
        .Create("localhost", 5672)
        .WithAutomaticRecoveryEnabled(true)
        .WithNetworkRecoveryInterval(TimeSpan.FromSeconds 1.0)
        .WithTopologyRecoveryEnabled(true)
        
let taskQueue = "task-queue"
let taskQueueDecl = QueueDeclaration.Create(taskQueue).WithDurable(false).WithAutoDelete(true)

// send 10 tasks
let sink = AmqpSink.CreateSimple(AmqpSinkSettings.Create(connSettings).WithRoutingKey(taskQueue).WithDeclarations(taskQueueDecl))
Source.From([1..10]).Select(fun x -> x |> string |> ByteString.FromString).RunWith(sink, mat).Wait()

let reportQueue = QueueDeclaration.Create("report-queue").WithDurable(false).WithAutoDelete(true)

RestartSource
    .WithBackoff((fun _ ->
        AmqpSource.CommittableSource(NamedQueueSourceSettings.Create(connSettings, taskQueue), bufferSize = 100)),
        TimeSpan.FromSeconds 1.0, TimeSpan.FromSeconds 2.0, 0.2)
    .Throttle(1, TimeSpan.FromMilliseconds 1000.0, 0, ThrottleMode.Shaping)
    .Select(fun x ->
        printfn "[0] %s" (x.Message.Bytes.ToString())
        x)
    .SelectAsync(1, fun cms ->
        async {
            if cms.Message.Bytes.ToString() = "5" then
                do! cms.Nack() |> Async.AwaitTask
            do! cms.Ack() |> Async.AwaitTask // here we fail on "5" message
            return cms.Message.Bytes
        }
        |> Async.StartAsTask)
    .Select(fun x ->
        printfn "[1] %O" x
        x)
    .RunWith(
        RestartSink.WithBackoff((fun _ ->
            AmqpSink.CreateSimple(AmqpSinkSettings.Create(connSettings).WithRoutingKey(reportQueue.Name).WithDeclarations(reportQueue))),
                TimeSpan.FromSeconds 1.0, TimeSpan.FromSeconds 2.0, 0.2), mat)
|> ignore
system.WhenTerminated.Wait()
[0] 1
[1] 1
[0] 2
[1] 2
[0] 3
[1] 3
[0] 4
[1] 4
[0] 5
[1] 5
[ERROR][18-Jan-18 19:45:06][Thread 0011][Akka.Streams.Dsl.RestartWithBackoffSource`2+Logic[Akka.Streams.Amqp.Dsl.CommittableIncomingMessage,Akka.NotUsed]] Restarting graph due to failure
Cause: Akka.Streams.Amqp.ShutdownSignalException: ShutdownSignal has been received, ShutdownInitiator=Peer, Cause=, ClassId=60, MethodId=80, ReplyCode=406, ReplyText=PRECONDITION_FAILED - unknown delivery tag 5
[DEBUG][18-Jan-18 19:45:06][Thread 0011][Akka.Streams.Dsl.RestartWithBackoffSource`2+Logic[Akka.Streams.Amqp.Dsl.CommittableIncomingMessage,Akka.NotUsed]] Last restart attempt was more than 00:00:01 ago, resetting restart count
[DEBUG][18-Jan-18 19:45:06][Thread 0011][Akka.Streams.Dsl.RestartWithBackoffSource`2+Logic[Akka.Streams.Amqp.Dsl.CommittableIncomingMessage,Akka.NotUsed]] Restarting graph in 00:00:01.0657050
[0] 6
[ERROR][18-Jan-18 19:45:08][Thread 0003][[akka://test/user/StreamSupervisor-0/Flow-1-0-unknown-operation#477839087]] Error during PreStart in [AmqpSource]
Cause: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=404, text="NOT_FOUND - no queue 'task-queue' in vhost '/'", classId=60, methodId=20, cause=
   at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout)
   at RabbitMQ.Client.Impl.ModelBase.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at RabbitMQ.Client.Impl.AutorecoveringModel.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at Akka.Streams.Amqp.AmqpSourceStage.AmqpSourceStageLogic.SetupNamedQueue(NamedQueueSourceSettings settings)
   at Akka.Streams.Amqp.AmqpConnectorLogic.PreStart()
   at Akka.Streams.Implementation.Fusing.GraphInterpreter.Init(IMaterializer subMaterializer)
[ERROR][18-Jan-18 19:45:08][Thread 0003][Akka.Streams.Dsl.RestartWithBackoffSource`2+Logic[Akka.Streams.Amqp.Dsl.CommittableIncomingMessage,Akka.NotUsed]] Restarting graph due to failure
Cause: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=404, text="NOT_FOUND - no queue 'task-queue' in vhost '/'", classId=60, methodId=20, cause=
   at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout)
   at RabbitMQ.Client.Impl.ModelBase.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at RabbitMQ.Client.Impl.AutorecoveringModel.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at Akka.Streams.Amqp.AmqpSourceStage.AmqpSourceStageLogic.SetupNamedQueue(NamedQueueSourceSettings settings)
   at Akka.Streams.Amqp.AmqpConnectorLogic.PreStart()
   at Akka.Streams.Implementation.Fusing.GraphInterpreter.Init(IMaterializer subMaterializer)
[DEBUG][18-Jan-18 19:45:08][Thread 0003][Akka.Streams.Dsl.RestartWithBackoffSource`2+Logic[Akka.Streams.Amqp.Dsl.CommittableIncomingMessage,Akka.NotUsed]] Restarting graph in 00:00:02.3403801
[ERROR][18-Jan-18 19:45:10][Thread 0005][[akka://test/user/StreamSupervisor-0/Flow-1-0-unknown-operation#477839087]] Error during PreStart in [AmqpSource]
Cause: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=404, text="NOT_FOUND - no queue 'task-queue' in vhost '/'", classId=60, methodId=20, cause=
   at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout)
   at RabbitMQ.Client.Impl.ModelBase.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at RabbitMQ.Client.Impl.AutorecoveringModel.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at Akka.Streams.Amqp.AmqpSourceStage.AmqpSourceStageLogic.SetupNamedQueue(NamedQueueSourceSettings settings)
   at Akka.Streams.Amqp.AmqpConnectorLogic.PreStart()
   at Akka.Streams.Implementation.Fusing.GraphInterpreter.Init(IMaterializer subMaterializer)
[ERROR][18-Jan-18 19:45:10][Thread 0005][Akka.Streams.Dsl.RestartWithBackoffSource`2+Logic[Akka.Streams.Amqp.Dsl.CommittableIncomingMessage,Akka.NotUsed]] Restarting graph due to failure
Cause: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=404, text="NOT_FOUND - no queue 'task-queue' in vhost '/'", classId=60, methodId=20, cause=
   at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout)
   at RabbitMQ.Client.Impl.ModelBase.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at RabbitMQ.Client.Impl.AutorecoveringModel.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at Akka.Streams.Amqp.AmqpSourceStage.AmqpSourceStageLogic.SetupNamedQueue(NamedQueueSourceSettings settings)
   at Akka.Streams.Amqp.AmqpConnectorLogic.PreStart()
   at Akka.Streams.Implementation.Fusing.GraphInterpreter.Init(IMaterializer subMaterializer)
[DEBUG][18-Jan-18 19:45:10][Thread 0005][Akka.Streams.Dsl.RestartWithBackoffSource`2+Logic[Akka.Streams.Amqp.Dsl.CommittableIncomingMessage,Akka.NotUsed]] Restarting graph in 00:00:02.1493502
[ERROR][18-Jan-18 19:45:12][Thread 0008][[akka://test/user/StreamSupervisor-0/Flow-1-0-unknown-operation#477839087]] Error during PreStart in [AmqpSource]
Cause: RabbitMQ.Client.Exceptions.OperationInterruptedException: The AMQP operation was interrupted: AMQP close-reason, initiated by Peer, code=404, text="NOT_FOUND - no queue 'task-queue' in vhost '/'", classId=60, methodId=20, cause=
   at RabbitMQ.Client.Impl.SimpleBlockingRpcContinuation.GetReply(TimeSpan timeout)
   at RabbitMQ.Client.Impl.ModelBase.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at RabbitMQ.Client.Impl.AutorecoveringModel.BasicConsume(String queue, Boolean autoAck, String consumerTag, Boolean noLocal, Boolean exclusive, IDictionary`2 arguments, IBasicConsumer consumer)
   at Akka.Streams.Amqp.AmqpSourceStage.AmqpSourceStageLogic.SetupNamedQueue(NamedQueueSourceSettings settings)
   at Akka.Streams.Amqp.AmqpConnectorLogic.PreStart()
   at Akka.Streams.Implementation.Fusing.GraphInterpreter.Init(IMaterializer subMaterializer)

It fails with "text="NOT_FOUND - no queue 'task-queue'". I don't understand why.

OK, carefully catching exceptions and nacking task messages works pretty good:

.SelectAsync(1, fun cms ->
    async {
        try
            if cms.Message.Bytes.ToString() = "5" then failwithf "It's 5 and we are failing."
            do! cms.Ack() |> Async.AwaitTask
        with e ->
            do! cms.Nack() |> Async.AwaitTask
        return cms
    }
    |> Async.StartAsTask)

The problem is that auto-delete queues are owned by channels they are declared by, and if a channel dies, the queues disappear too. RestartSource properly re-creates the channel (IModel), but not the queue (should it?). So I consider this by design.