Greengrass V2で発生するMqttException: Time limit between request and response has been exceededへの対応方法

MQTTメッセージを送信している時にネットワークが途切れた際など、Greengrassのログに以下のエラーが発生する場合があります。こちらのエラーを制御する方法が検索しても出てこなかったので、調べた内容を記載します。


```/greengrass/v2/logs/greengrass.log
2023-03-16T09:40:10.941Z [ERROR] (Thread-4) com.aws.greengrass.mqttclient.MqttClient: Failed to publish the message via Spooler and will retry. {}
java.util.concurrent.CompletionException: software.amazon.awssdk.crt.mqtt.MqttException: Time limit between request and response has been exceeded.
        at java.base/java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:331)
        at java.base/java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:346)
        at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:632)
        at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:506)
        at java.base/java.util.concurrent.CompletableFuture.completeExceptionally(CompletableFuture.java:2088)
        at software.amazon.awssdk.crt.AsyncCallback$1.onFailure(AsyncCallback.java:32)
Caused by: software.amazon.awssdk.crt.mqtt.MqttException: Time limit between request and response has been exceeded.
```


# 結論

Greengrass nucleusの `mqtt.operationTimeoutMs` で制御可能です。デフォルトは30秒です。


以下の公式ドキュメントには2023/03/16時点では記載が無いので自己責任で使ってください。
https://docs.aws.amazon.com/greengrass/v2/developerguide/greengrass-nucleus-component.html




# 調査内容


そもそも、このエラーですが、Nucleusの内部で使われているMQTTライブラリで出力されています。

https://github.com/awslabs/aws-c-mqtt/blob/v0.8.7/source/mqtt.c#L123-L125


```aws-c-mqtt/source/mqtt.c
            AWS_DEFINE_ERROR_INFO_MQTT(
                AWS_ERROR_MQTT_TIMEOUT,
                "Time limit between request and response has been exceeded."),
```

同リポジトリに説明もあります。これに合わせて設定すれば制御できそうです。

https://github.com/awslabs/aws-c-mqtt/blob/v0.8.7/include/aws/mqtt/client.h#L214-L222

```aws-c-mqtt/include/aws/mqtt/client.h
 * protocol_operation_timeout_ms
 *                           Timeout when waiting for the response to some operation requires response by protocol.
 *                           Set to zero to disable timeout. Otherwise, the operation will fail with error
 *                           AWS_ERROR_MQTT_TIMEOUT if no response is received within this amount of time after
 *                           the packet is written to the socket. The timer is reset if the connection is interrupted.
 *                           It applied to PUBLISH (QoS>0) and UNSUBSCRIBE now.
 *                           Note: While the MQTT 3 specification states that a broker MUST respond,
 *                           some brokers are known to ignore publish packets in exceptional circumstances
 *                           (e.g. AWS IoT Core will not respond if the publish quota is exceeded).
```

ではGreengrassからどうやって設定するか、公式ドキュメントには無いのでコード見てみたら、該当の設定値と同名の設定がありました。

https://github.com/aws-greengrass/aws-greengrass-nucleus/blob/v2.9.3/src/main/java/com/aws/greengrass/mqttclient/MqttClient.java#L90-L91


```aws-greengrass-nucleus/src/main/java/com/aws/greengrass/mqttclient/MqttClient.java
    static final String MQTT_OPERATION_TIMEOUT_KEY = "operationTimeoutMs";
    static final int DEFAULT_MQTT_OPERATION_TIMEOUT = (int) Duration.ofSeconds(30).toMillis();
```