14#include "mqss/Messenger.hpp"
15#include "mqss/Protocol.hpp"
16#include "mqss/Transport.hpp"
24#include <spdlog/spdlog.h>
28namespace mqss::qrmci {
47[[nodiscard]] mqss::TransportOptions<mqss::RabbitMqSimple>
54 return "quantum task " + std::to_string(task.task_id());
60inline std::string
messageLabel(
const mqss::QuantumResult &result) {
61 return "quantum result for task " + std::to_string(result.task_id());
68 return "backend status for backend " + backend.name();
75template <
class Message>
111 template <
class Message>
112 [[nodiscard]] std::expected<void, Error>
send(
const Message &message,
113 const std::string &queueName) {
114 auto sendStatus = messenger.send<Message>({queueName}, message);
116 if (!sendStatus.ok()) {
119 ": " + sendStatus.reason()});
141 template <
class Message>
142 [[nodiscard]] std::expected<std::optional<Message>,
Error>
143 receive(
const std::string &queueName, std::chrono::milliseconds timeout,
144 const std::atomic<bool> &terminationFlag) {
145 const bool waitIndefinitely = (timeout ==
WaitForever);
146 const auto pollInterval =
151 while (!terminationFlag.load(std::memory_order_acquire)) {
156 auto received = messenger.receiveExtended<Message>(
157 {queueName}, mqss::ReceiveArgs{
158 .timeout = pollInterval,
159 .ack_mode = mqss::AckMode::Manual,
161 if (received.has_value()) {
162 auto &[message, delivery] = *received;
163 if (
auto ackStatus = delivery.ack(); !ackStatus.ok()) {
164 spdlog::warn(
"Failed to ack {}: {}",
messageLabel(message),
167 return std::optional<Message>(std::move(message));
169 if (received.error().code() != mqss::StatusCode::Timeout) {
170 return std::unexpected(
172 "Receive error: " + received.error().reason()});
174 if (!waitIndefinitely) {
178 return std::optional<Message>{};
196 template <
class Message>
197 [[nodiscard]] std::expected<std::optional<Message>,
Error>
200 static const std::atomic<bool> NeverTerminates{
false};
205 mqss::Messenger<mqss::RabbitMqSimple, mqss::ProtoJson> messenger;
mqss::TransportOptions< mqss::RabbitMqSimple > makeTransportOptions(const RabbitMqConnectionConfig &config)
Translate a RabbitMqConnectionConfig into the transport's own options.
constexpr std::chrono::milliseconds WaitForever
Timeout value meaning "poll until a message arrives or the termination flag is set" rather than...
constexpr std::chrono::milliseconds DefaultReceiveTimeout
How long a single receive attempt waits when the caller does not say, and the interval an indefinite ...
std::string messageLabel(const mqss::QuantumTask &task)
Describe a quantum task for an error or log line.
The runtime configuration model shared by every QRM&CI daemon.
The error type every std::expected in QRM&CI's public interfaces carries.
CommunicationHandler(const RabbitMqConnectionConfig &config)
Construct a CommunicationHandler with the given configuration.
CommunicationHandler(const CommunicationHandler &)=delete
Explicitly non-copyable and non-movable: a moved-from handler would leave its messenger's transport c...
std::expected< std::optional< Message >, Error > receive(const std::string &queueName, std::chrono::milliseconds timeout=DefaultReceiveTimeout)
Retrieve the next message of the given type, with no termination flag to interrupt the wait.
std::expected< std::optional< Message >, Error > receive(const std::string &queueName, std::chrono::milliseconds timeout, const std::atomic< bool > &terminationFlag)
Retrieve the next message of the given type from the specified queue.
std::expected< void, Error > send(const Message &message, const std::string &queueName)
Send a message to the specified queue.
A failure reported by a QRM&CI operation: a kind the caller can act on, plus a human-readable detail ...
@ MessagingFailed
A messaging operation against the broker failed.
RabbitMQ connection settings, shared by every stage's messaging.