AWS IoT device managementのJob機能の動きをデバイス視点で見てみる

# はじめに

公式ページは[こちら](https://docs.aws.amazon.com/iot/latest/developerguide/iot-jobs.html)になります。(2018/1/20時点では英語のマニュアルのみとなっております)
同じく、投稿時点では、javascript IoT Device SDKはjobの処理が入っているようですが、pythonなどはまだSDKに入っていないようですので、本説明にあわせてご自分でシーケンスをコードで表現する必要があるようです。
デバイス側でどういったことを考えてシーケンスを書くかや、request/responseのjsonについての理解が深まるようにまとめようと思います。

# デバイスが意識すべきjob用のtopic
以下、topoic中の{}で区切ったものは変数となるものです。 device名やjobIdなど。

## job情報取得で使えるtopic

### 新規job待受用のsubscribe topic

* $aws/things/{thingName}/jobs/notify
* $aws/things/{thingName}/jobs/notify-next

__新規jobが作成__されると下記２つにpublishされます。つまり新規jobを受け取るために、動作中のデバイスがsubscribeしたままにすべきtopicということになります。2つのtopicの情報の差を含めて見ましょう。

$aws/things/{thingName}/jobs/notify
 => job一覧入ってきます。jobDocumentはありません。

```json
{
  "timestamp": unixtime,
  "jobs": {
    "IN_PROGRESS": [
      {
        "jobId": "作成したjob名",
        "queuedAt": unixtime,
        "lastUpdatedAt": unixtime,
        "startedAt": unixtime,
        "executionNumber": 1,
        "versionNumber": 3
      }
    ],
    "QUEUED": [
      {
        "jobId": "作成したjob名",
        "queuedAt": unixtime,
        "lastUpdatedAt": unixtime,
        "startedAt": unixtime,
        "executionNumber": 1,
        "versionNumber": 1
      }
    ]
  }
}
```

$aws/things/{thingName}/jobs/notify-next
 => 次にやるべきjob情報のみが、通知されます。
jobDocumentにある、test:testは job生成時に指定したS3のjob fileの中身(json)が入っています。

```json
{
  "timestamp": unixtime,
  "execution": {
    "jobId": "job名",
    "status": "QUEUED",
    "queuedAt": unixtime,
    "lastUpdatedAt": unixtime,
    "versionNumber": 1,
    "executionNumber": 1,
    "jobDocument": {
      "test": "test"
    }
  }
}
```


__*注意*__：通知対象のdeviceに"IN_PROGRESS"のstatusがある場合、notify-nextは発行されません。
複数の処理を通知して、デバイス側でupdate処理が重複しないための考慮だと思います。

この場合、デバイスが "testjob-20180120-00" のtaskの終了通知(後述のupdate通知をSUCCEEDEDでpublish)すると、AWS IoTがnotify-nextへ通知します。

### 能動的にjob statusを確認するためのtopic

起動時などにjobを確認する用途 publishすると、acceptedへ返却される

* $aws/things/{thingName}/jobs/get  (publish)
* $aws/things/{thingName}/jobs/get/accepted  (publish前にsubscribeしておく)

上記の通り、シーケンスとしては acdepted topicを先にsubscribeしてから、get topicへpublishすることとなります。acceptedへのsubscribeへの返却は以下のようなjsonとなります。先に説明した__notifyと少しjsonフォーマットが異なります__が、取得できる内容はほぼ同じです。
こちらはデバイスが起動したばかりなどで前回の終了状態が分からない場合や電源off時などにupdateが来ていないかなど、最初にチェックするような用途になるかと思います。

```json
{
  "timestamp": unixtime,
  "inProgressJobs": [],
  "queuedJobs": [
    {
      "jobId": "Job名",
      "queuedAt": unixtime,
      "lastUpdatedAt": unixtime,
      "executionNumber": 1,
      "versionNumber": 1
    }
  ]
}
```

## deviceがAWS IoTにreportするためのtopic

$aws/things/thingName/jobs/jobId/update
requestのjson format

```json
{
  "status": ["IN_PROGRESS", "FAILED", "SUCCEEDED", "REJECTED"],
  "statusDetails": {
    "progress": "0%"
  },
  "expectedVersion":"",
  "clientToken":""
}
```
statusは上記の４つの状態のみを指定可能
statusDetailsのjsonについては自由に記載できます。ここでは例として"progress"としています。
管理者視点で見ると、統計などが見れる機能があるので、デバイス側のupdate処理内で定期的に呼び出して置くと良いかと思います。

# AWS IoTのテスト画面を使っての動作確認

## device想定のsubscribe設定

AWSのマネージメントコンソールから、AWS IoTを選択し左側メニューの "Test" を選択します。
Subscription topicへ"$aws/things/+/jobs/#"を入力し、subscribe to topicを押下して、受信状態のままにしておきます。

意味を説明すると$aws/things/(+ = すべてのthingName)/jobs/(# = ここ以下すべてのレイヤtopic)
を受信することになります。

![スクリーンショット 2018-01-21 21.39.56.png](https://qiita-image-store.s3.amazonaws.com/0/100893/a46ff1dc-47ac-d155-da03-13cf5d0d5403.png)



## test Jobの作成

### 事前作業
#### AWS IoTの作成
今回は、AWS IoTのテスト画面しか使わないので名前だけあれば良いです。(証明書やpolicyなどは使いません)
本投稿では qiita-thing　としています。

#### job通知のjsonドキュメント配置
S3へjsonドキュメントを置きます。このjsonドキュメントがjobのjobDocumentとして通知されます。
ここでは、 {"test":"test"}としておいておきます。

### AWS IoTからjob作成
先程の受信状態のコンソールをそのままにして別タブなどでもう一つ AWS IoT画面を開き、Manage => Jobsを選択します。画面右上にあるCreateを押下して、jobの作成をしてみます。

Select a job で、Create custom jobを選択。次の画面で以下を設定
- Job IDに qiita-test
- device updateに、先程作ったthingを一つ選択、
- job fileに 先程おいたS3のjson fileを選択
- job typeに snapshotを選択
 createを実行。createを実行するとjob通知が自動で発行されます。

### 通知の確認とupdateで通知

AWS IoTのtest画面の方に戻ります。
先程のjob作成でsubscribeにnotifyとnotify-nextの通知がきています。
![スクリーンショット 2018-01-21 22.09.31.png](https://qiita-image-store.s3.amazonaws.com/0/100893/b32a2dfb-22e7-ff1d-1641-4938704fa369.png)

本test画面の Publish の topicを以下とします。
$aws/things/qiita-thing/jobs/qiita-test/update

updateのpayloadに以下を設定

```json
{
  "status": "IN_PROGRESS",
  "statusDetails": {
    "progress": "0%"
  },
  "expectedVersion":"",
  "clientToken":""
}
```

### 状態を確認
Publishのtopicを以下に変更して、publishを実行します。
$aws/things/qiita-thing/jobs/get
mqttのpayloadは設定しなくともよいです。

test画面のsubscribeの画面に以下が表示されました。想定通り、queueからinProgressへ変化しています。

```json
{
  "timestamp": 1516540819,
  "inProgressJobs": [
    {
      "jobId": "qiita-test",
      "queuedAt": 1516540026,
      "lastUpdatedAt": 1516540699,
      "startedAt": 1516540699,
      "executionNumber": 1,
      "versionNumber": 2
    }
  ],
  "queuedJobs": []
}
```

AWS IoTコンソールのjob詳細画面もin progressとなっています。
![スクリーンショット 2018-01-21 22.28.08.png](https://qiita-image-store.s3.amazonaws.com/0/100893/6ff7b7db-2719-5d3c-5b97-368cb9380d78.png)

### 複数jobを通知してみる

notifyとnotify-nextの動きを確認するために、再度jobを作成して送信してみます。
jobIdは qiita-test-2としてみます。それ以外は先程同じにしています。

説明済みですが、notifyのみが通知されました。

```json
{
  "timestamp": 1516541383,
  "jobs": {
    "IN_PROGRESS": [
      {
        "jobId": "qiita-test",
        "queuedAt": 1516540026,
        "lastUpdatedAt": 1516540699,
        "startedAt": 1516540699,
        "executionNumber": 1,
        "versionNumber": 2
      }
    ],
    "QUEUED": [
      {
        "jobId": "qiita-test-2",
        "queuedAt": 1516541383,
        "lastUpdatedAt": 1516541383,
        "executionNumber": 1,
        "versionNumber": 1
      }
    ]
  }
}
```

### 最初のjobを完了させてみる
updateの通知と同様の手順で以下のtopicに payloadを"SUCCEEDED"として送信してみます。

topic : $aws/things/qiita-thing/jobs/qiita-test/update

```json
{
  "status": "SUCCEEDED",
  "statusDetails": {
    "progress": "100%"
  },
  "expectedVersion":"",
  "clientToken":""
}
```

完了通知に合わせて自動でnotifyとnotify-nextが送られてきました。
ということで、notify-nextをsubscribeしておけば良いことがわかります。
![スクリーンショット 2018-01-21 22.37.56.png](https://qiita-image-store.s3.amazonaws.com/0/100893/975c65f7-11f6-48d0-3679-a1fc4f03ac37.png)

# 雑にDeviceの想定するシーケンス図
![スクリーンショット 2018-02-22 22.46.25.png](https://qiita-image-store.s3.amazonaws.com/0/100893/88e17637-60e1-bb04-00b0-45d5ec71cea5.png)


# まとめ
ということで、AWS IoTのdevice managementのjob機能についてdeviceの観点で簡単に整理してみました。実際にはjob documentのデザイン(プログラムDLのS3 urlをセット)やプログラム更新をする部分というところがdevice updateの本質なので、主にシーケンス/request方法についての説明となりますが、AWS IoT側でこのくらい作られていれば、device updateプログラムの開発に集中出来るのではないでしょうか？

# 免責
本投稿は、個人の意見で、所属する企業や団体は関係ありません。
ご自身でもドキュメントの確認や、動きを確認してからの利用をおすすめします。