public async Task Can_manage_errors_with_custom_retry_policy()
        {
            const int expected = 1000;
            var       actual   = 0;
            var       producer = new BackgroundThreadProducer <BaseEvent> {
                MaxDegreeOfParallelism = 10
            };

            producer.AttachError(x =>
            {
                /* compensating for not using an intermediary like Hub, which handles exceptions */
            });
            producer.AttachUndeliverable(new Action <BaseEvent>(x => Interlocked.Increment(ref actual)));
            producer.Attach(new ThrowingHandler());

            producer.RetryPolicy = new RetryPolicy();
            producer.RetryPolicy.After(1, RetryDecision.Undeliverable);

            for (var i = 0; i < expected; i++)
            {
                await producer.Produce(new BaseEvent { Id = i });
            }
            await producer.Start();

            await producer.Stop();
        }
        public async Task Can_requeue_with_exponential_backoff()
        {
            const int expected = 1;
            const int maxTries = 3;

            var actual = 0;

            var producer = new BackgroundThreadProducer <BaseEvent> {
                MaxDegreeOfParallelism = 10
            };

            producer.AttachError(x =>
            {
                /* compensating for not using an intermediary like Hub, which handles exceptions */
            });
            producer.Attach(new ThrowingHandler());
            producer.AttachUndeliverable(x =>
            {
                _console.WriteLine("abandoned message after " + x.Attempts + " attempts");
                Assert.Equal(maxTries, x.Attempts);
                Interlocked.Increment(ref actual);
            });

            producer.RetryPolicy = new RetryPolicy();
            producer.RetryPolicy.After(maxTries, RetryDecision.Undeliverable);

            for (var i = 0; i < expected; i++)
            {
                await producer.Produce(new BaseEvent { Id = i });
            }
            await producer.Start();

            while (producer.Undeliverable < expected)
            {
                await Task.Delay(10);
            }
            await producer.Stop();

            Assert.Equal(expected, actual);
        }