public Task <bool> PublishManyAsync(IEnumerable <JobExecution> jobExecutions, CancellationToken ctx)
        {
            using var _   = MessagingMetrics.TimeBatchPublishDuration();
            jobExecutions = jobExecutions.ToList();

            try
            {
                if (!TryGetOrCreateModel(out var model) || model is null)
                {
                    return(Task.FromResult(false));
                }
                var batchPublish = model.CreateBasicPublishBatch();

                jobExecutions.GroupBy(j => j.Job.Subject).ToList().ForEach(g =>
                {
                    model.EnsureConfig(_options.JobsExchange, g.Key);
                    foreach (var jobExecution in g.ToList())
                    {
                        batchPublish.Add(_options.JobsExchange, jobExecution.Job.Subject, true, null, new ReadOnlyMemory <byte>(Encoding.UTF8.GetBytes(jobExecution.Job.Payload)));
                    }

                    MessagingMetrics.MessagesPublished(g.Key, g.Count());
                });

                batchPublish.Publish();
                return(Task.FromResult(model.WaitForConfirms()));
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Failed to batch publish {JobIds} to RabbitMQ", jobExecutions.Select(j => j.Job.Id));
                return(Task.FromResult(false));
            }
        }
        public Task <bool> PublishAsync(JobExecution jobExecution, CancellationToken ctx)
        {
            using var _ = MessagingMetrics.TimePublishDuration();

            try
            {
                if (!TryGetOrCreateModel(out var model) || model is null)
                {
                    return(Task.FromResult(false));
                }
                var job = jobExecution.Job;

                model.EnsureConfig(_options.JobsExchange, job.Subject);
                model.BasicPublish(_options.JobsExchange, job.Subject, true, null, Encoding.UTF8.GetBytes(job.Payload));

                MessagingMetrics.MessagesPublished(job.Subject);

                return(Task.FromResult(model.WaitForConfirms()));
            }
            catch (Exception e)
            {
                _logger.LogError(e, "Failed to publish job {JobId} to RabbitMQ", jobExecution.Job.Id);
                return(Task.FromResult(false));
            }
        }
        public Task <bool> PublishAsync(JobExecution jobExecution, CancellationToken ctx)
        {
            using var _ = MessagingMetrics.TimePublishDuration();

            var job     = jobExecution.Job;
            var message = new ServiceBusMessage(job.Payload)
            {
                MessageId    = jobExecution.Id.ToString(),
                PartitionKey = job.Id.ToString(),
                Subject      = job.Subject,
            };

            MessagingMetrics.MessagesPublished(job.Subject);

            return(WithSenderAsync(conn => conn.SendMessageAsync(message, ctx)));
        }
        public async Task <bool> PublishManyAsync(IEnumerable <JobExecution> jobExecutions, CancellationToken ctx)
        {
            jobExecutions = jobExecutions.ToList();
            if (!jobExecutions.Any())
            {
                return(true);
            }

            if (_options.PartitionedQueue)
            {
                return(await PublishPartitioned(jobExecutions, ctx));
            }
            else
            {
                return(await PublishBatched(jobExecutions, ctx));
            }

            async Task <bool> PublishPartitioned(IEnumerable <JobExecution> jobExecutions, CancellationToken ctx)
            {
                var tasks  = jobExecutions.Select(jobExecution => PublishAsync(jobExecution, ctx));
                var result = await Task.WhenAll(tasks);

                // Any tasks failed -> we consider the batch to be failed
                return(result.Contains(false) is false);
            }

            async Task <bool> PublishBatched(IEnumerable <JobExecution> jobExecutions, CancellationToken ctx)
            {
                using var _ = MessagingMetrics.TimeBatchPublishDuration();

                var messages = jobExecutions.Select(jobExecution =>
                                                    new ServiceBusMessage(jobExecution.Job.Payload)
                {
                    MessageId = jobExecution.Id.ToString(),
                    Subject   = jobExecution.Job.Subject,
                });

                jobExecutions
                .GroupBy(jobExecution => jobExecution.Job.Subject)
                .ToList()
                .ForEach(jobGroup =>
                         MessagingMetrics.MessagesPublished(jobGroup.Key, jobGroup.Count()));

                return(await WithSenderAsync(conn => conn.SendMessagesAsync(messages, ctx)));
            }
        }