6.2 MqttPublisher.PublishAsync

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-07 15:16:40 +02:00
parent a6c750d5c4
commit cc0241ab53
3 changed files with 54 additions and 3 deletions

View File

@@ -1,7 +1,9 @@
using FrameProcessor.Configuration;
using FrameProcessor.Domain;
using Microsoft.Extensions.Options;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Protocol;
namespace FrameProcessor.Mqtt;
@@ -86,6 +88,43 @@ public sealed class MqttPublisher : BackgroundService
}
}
/// <summary>
/// Publish an <c>update</c> notification for the given frame. Returns
/// <see cref="PublishResult.Failure"/> on any error (disconnected, broker reject,
/// transport fault) — per SPEC.md §3.5, publish failure must not fail the upload,
/// so this method never throws on MQTT errors. <see cref="OperationCanceledException"/>
/// still propagates so callers can honor cooperative cancellation.
/// </summary>
public async Task<PublishResult> PublishAsync(MacAddress mac, CancellationToken cancellationToken)
{
var opts = _options.Value;
var topic = $"{opts.BaseTopic}/{mac}";
var message = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload("update")
.WithQualityOfServiceLevel((MqttQualityOfServiceLevel)opts.PublishQos)
.WithRetainFlag(false)
.Build();
try
{
var result = await _client.PublishAsync(message, cancellationToken).ConfigureAwait(false);
if (result.IsSuccess)
{
_logger.LogInformation("MQTT publish to {Topic} succeeded", topic);
return PublishResult.Success;
}
_logger.LogWarning("MQTT publish to {Topic} returned {ReasonCode}", topic, result.ReasonCode);
return PublishResult.Failure;
}
catch (Exception ex) when (!cancellationToken.IsCancellationRequested)
{
_logger.LogWarning(ex, "MQTT publish to {Topic} failed", topic);
return PublishResult.Failure;
}
}
public override async Task StopAsync(CancellationToken cancellationToken)
{
await base.StopAsync(cancellationToken).ConfigureAwait(false);