

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 教程：使用 AWS IoT 设备客户端演示远程操作（作业）
<a name="iot-dc-runjobs"></a>

在这些教程中，您将配置任务并将其部署到 Raspberry Pi，演示如何向物联网设备发送远程操作。

**要开始本教程：**
+ 将本地主机和 Raspberry Pi 配置为在[上一节](iot-dc-testconn.md)使用。
+ 如果您尚未完成上一节中的教程，则可以使用 Raspberry Pi 和 microSD 卡来尝试本教程，该卡上有您在安装 AWS IoT 设备客户端后保存的图像。[（可选）保存 microSD 卡映像](iot-dc-install-download.md#iot-dc-install-dc-save)
+ 如果您之前运行过此演示，[第 2 步：使用 AWS IoT 设备客户端 AWS 账户 在构建演示之后清理你的](iot-dc-cleanup.md#iot-dc-cleanup-cloud)请查看删除您在之前运行中创建的所有 AWS IoT 资源，以避免出现重复的资源错误。

完成本教程需要大约 45 分钟。

**完成本主题后：**
+ 您将演示物联网设备使用不同的方式 AWS IoT Core 来运行由管理的远程操作 AWS IoT 。

**所需的设备：**
+ 您在[上一节](iot-dc-install-dc.md)中测试的本地开发和测试环境
+ 您在[上一节](iot-dc-install-dc.md)中测试的 Raspberry Pi
+ 您在[上一节](iot-dc-install-dc.md)中测试的来自Raspberry Pi 的 microSD 存储卡

**Topics**
+ [准备 Raspberry Pi 运行任务](iot-dc-runjobs-prepare.md)
+ [使用 AWS IoT 设备客户端创建和运行作业 AWS IoT](iot-dc-runjobs-prepare-define.md)

# 准备 Raspberry Pi 运行任务
<a name="iot-dc-runjobs-prepare"></a>

本节中的过程介绍如何使用 AWS IoT 设备客户端让 Raspberry Pi 做好运行作业的准备。

**注意**  
这些过程是特定于设备的。如果要同时对多个设备执行本节中的步骤，每个设备将需要自己的策略和唯一的、特定于设备的证书和设备名称。要为每台设备提供独特的资源，请对每台设备执行一次此过程，同时按照过程中所述更改特定于设备的元素。

**Topics**
+ [提供您的 Raspberry Pi 来演示任务](#iot-dc-runjobs-prepare-provision)
+ [将 AWS IoT 设备客户端配置为运行作业代理](#iot-dc-runjobs-prepare-config)

## 提供您的 Raspberry Pi 来演示任务
<a name="iot-dc-runjobs-prepare-provision"></a>

本节中的过程通过为树莓派创建 AWS IoT 资源和设备证书 AWS IoT 来配置 Raspberry Pi。

**Topics**
+ [创建和下载设备证书文件以演示 AWS IoT 作业](#iot-dc-runjobs-prepare-cert)
+ [创建 AWS IoT 资源来演示 AWS IoT 工作](#iot-dc-runjobs-prepare-iot)

### 创建和下载设备证书文件以演示 AWS IoT 作业
<a name="iot-dc-runjobs-prepare-cert"></a>

此过程为此演示创建设备证书文件。

如果准备了多台设备，必须在每台设备上执行此过程。

**要为 Raspberry Pi 创建和下载设备证书文件，请执行以下操作：**

在连接到 Raspberry Pi 的本地主机上的终端窗口中，输入以下命令。

1. 输入以下命令为您的设备创建设备证书文件。

   ```
   aws iot create-keys-and-certificate \
   --set-as-active \
   --certificate-pem-outfile "~/certs/jobs/device.pem.crt" \
   --public-key-outfile "~/certs/jobs/public.pem.key" \
   --private-key-outfile "~/certs/jobs/private.pem.key"
   ```

   此命令会返回类似以下内容的响应。保存 `certificateArn`值供稍后使用。

   ```
   {
   "certificateArn": "arn:aws:iot:us-west-2:57EXAMPLE833:cert/76e7e4edb3e52f52334be2f387a06145b2aa4c7fcd810f3aea2d92abc227d269",
   "certificateId": "76e7e4edb3e52f5233EXAMPLE7a06145b2aa4c7fcd810f3aea2d92abc227d269",
   "certificatePem": "-----BEGIN CERTIFICATE-----\nMIIDWTCCAkGgAwIBAgI_SHORTENED_FOR_EXAMPLE_Lgn4jfgtS\n-----END CERTIFICATE-----\n",
   "keyPair": {
       "PublicKey": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BA_SHORTENED_FOR_EXAMPLE_ImwIDAQAB\n-----END PUBLIC KEY-----\n",
       "PrivateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQE_SHORTENED_FOR_EXAMPLE_T9RoDiukY\n-----END RSA PRIVATE KEY-----\n"
   }
   }
   ```

1. 输入以下命令设置证书目录及其文件的权限。

   ```
   chmod 700 ~/certs/jobs
   chmod 644 ~/certs/jobs/*
   chmod 600 ~/certs/jobs/private.pem.key
   ```

1. 运行此命令可查看证书目录和文件的权限。

   ```
   ls -l ~/certs/jobs
   ```

   命令的输出应与您在此处看到的内容相同，但文件日期和时间会有所不同。

   ```
   -rw-r--r-- 1 pi pi 1220 Oct 28 13:02 device.pem.crt
   -rw------- 1 pi pi 1675 Oct 28 13:02 private.pem.key
   -rw-r--r-- 1 pi pi  451 Oct 28 13:02 public.pem.key
   ```

将设备证书文件下载到 Raspberry Pi 之后，您准备好继续 [提供您的 Raspberry Pi 来演示任务](#iot-dc-runjobs-prepare-provision)。

### 创建 AWS IoT 资源来演示 AWS IoT 工作
<a name="iot-dc-runjobs-prepare-iot"></a>

为此设备创建 AWS IoT 资源。

如果准备了多台设备，必须在每台设备上执行此过程。



**在 AWS IoT中预调配您的设备：**

在连接到 Raspberry Pi 的本地主机的终端窗口中：

1. 输入以下命令获取您的设备数据端点的地址： AWS 账户。

   ```
   aws iot describe-endpoint --endpoint-type IoT:Data-ATS
   ```

   自上次运行此命令以来，端点值未发生更改。再次在此处运行该命令可以轻松查找数据端点值并将其粘贴到本教程中使用的配置文件中。

   此 **describe-endpoint** 命令会返回类似以下内容的响应：记录 `endpointAddress`值以供将来使用。

   ```
   {
   "endpointAddress": "a3qjEXAMPLEffp-ats.iot.us-west-2.amazonaws.com"
   }
   ```

1. *uniqueThingName*替换为设备的唯一名称。如果要使用多台设备执行本教程，请为每台设备指定自己的名称。例如，**TestDevice01**、**TestDevice02** 等等。

   输入此命令为您的 Raspberry Pi 创建新 AWS IoT 事物资源。

   ```
   aws iot create-thing --thing-name "uniqueThingName"
   ```

   由于 AWS IoT 事物资源是您的设备在云中的*虚拟*表示，因此我们可以创建多个事物资源 AWS IoT 以用于不同的目的。它们都可以由同一物理 IoT 设备使用来表示设备的不同方面。
**注意**  
当您想要保护多台设备的策略时，可以使用 `${iot:Thing.ThingName}` 而不是静态事物名称 `uniqueThingName`。

   这些教程每台设备一次只能使用一件事资源。这样，在这些教程中，它们代表了不同的演示，因此在为演示创建 AWS IoT 资源之后，您可以使用专门为每个演示创建的资源返回并重复演示。

   如果您的 AWS IoT 事物资源已创建，则该命令会返回这样的响应。记录 `thingArn` 值以供稍后创建要在此设备上运行的任务时使用。

   ```
   {
   "thingName": "uniqueThingName",
   "thingArn": "arn:aws:iot:us-west-2:57EXAMPLE833:thing/uniqueThingName",
   "thingId": "8ea78707-32c3-4f8a-9232-14bEXAMPLEfd"
   }
   ```

1. 在终端窗口中：

   1. 打开文本编辑器，例如 `nano`。

   1. 复制此 JSON 文档并将其粘贴到打开的文本编辑器中。  
****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Connect"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:client/uniqueThingName"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Publish"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topic/test/dc/pubtopic",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/events/job/*",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/events/jobExecution/*",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/things/uniqueThingName/jobs/*"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Subscribe"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topicfilter/test/dc/subtopic",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/events/jobExecution/*",
                      "arn:aws:iot:us-west-2:123456789012:topicfilter/$aws/things/uniqueThingName/jobs/*"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:Receive"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topic/test/dc/subtopic",
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/things/uniqueThingName/jobs/*"
                  ]
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "iot:DescribeJobExecution",
                      "iot:GetPendingJobExecutions",
                      "iot:StartNextPendingJobExecution",
                      "iot:UpdateJobExecution"
                  ],
                  "Resource": [
                      "arn:aws:iot:us-west-2:123456789012:topic/$aws/things/uniqueThingName"
                  ]
              }
          ]
      }
      ```

   1. 在编辑器中，在每份政策声明的`Resource`部分中，*us-west-2:57EXAMPLE833*用您的 AWS 区域、冒号字符 (:) 和您的 12 位 AWS 账户 数字替换。

   1. 在编辑器中，在每份策略声明中，*uniqueThingName*用你为该事物资源提供的事物名称替换。

   1. 将文本编辑器中的文件保存为 **\$1/policies/jobs\$1test\$1thing\$1policy.json**。

      如果要为多台设备运行此过程，请将文件保存为每台设备上的此文件名。

1. *uniqueThingName*替换为设备的事物名称，然后运行此命令来创建针对该设备量身定制的 AWS IoT 策略。

   ```
   aws iot create-policy \
   --policy-name "JobTestPolicyForuniqueThingName" \
   --policy-document "file://~/policies/jobs_test_thing_policy.json"
   ```

   如果创建策略，该命令将返回类似此类的响应。  
****  

   ```
   {
       "policyName": "JobTestPolicyForuniqueThingName",
       "policyArn": "arn:aws:iot:us-west-2:57EXAMPLE833:policy/JobTestPolicyForuniqueThingName",
       "policyDocument": "{\n\"Version\": \"2012-10-17\",\n\"Statement\": [\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Connect\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:client/PubSubTestThing\"\n]\n},\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Publish\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/pubtopic\"\n]\n},\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Subscribe\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:topicfilter/test/dc/subtopic\"\n]\n},\n{\n\"Effect\": \"Allow\",\n\"Action\": [\n\"iot:Receive\"\n],\n\"Resource\": [\n\"arn:aws:iot:us-west-2:57EXAMPLE833:topic/test/dc/*\"\n]\n}\n]\n}\n",
       "policyVersionId": "1"
   }
   ```

1. *uniqueThingName*替换为设备的事物`certificateArn`名称以及您在本节前面为该设备保存的`certificateArn`值，然后运行此命令将策略附加到设备证书。

   ```
   aws iot attach-policy \
   --policy-name "JobTestPolicyForuniqueThingName" \
   --target "certificateArn"
   ```

   如果成功，该命令不返回任何内容。

1.  *uniqueThingName*替换为设备的事物名称，`certificateArn`替换为本节前面部分中保存的`certificateArn`值，然后运行此命令将设备证书附加到 AWS IoT 事物资源。

   ```
   aws iot attach-thing-principal \
   --thing-name "uniqueThingName" \
   --principal "certificateArn"
   ```

   如果成功，该命令不返回任何内容。

成功预调配 Raspberry Pi 之后，您可以在测试中为另一个 Raspberry Pi 重复此部分，或者，如果所有设备均已预调配，请继续 [将 AWS IoT 设备客户端配置为运行作业代理](#iot-dc-runjobs-prepare-config)。

## 将 AWS IoT 设备客户端配置为运行作业代理
<a name="iot-dc-runjobs-prepare-config"></a>

此过程为 AWS IoT 设备客户端创建一个配置文件以运行作业代理:.

注意：如果准备多台设备，必须在每台设备上执行此过程。

**要创建用于测试 AWS IoT 设备客户端的配置文件，请执行以下操作：**

1. 在连接到 Raspberry Pi 的本地主机的终端窗口中：

   1. 打开文本编辑器，例如 `nano`。

   1. 复制此 JSON 文档并将其粘贴到打开的文本编辑器中。

      ```
      {
        "endpoint": "a3qEXAMPLEaffp-ats.iot.us-west-2.amazonaws.com",
        "cert": "~/certs/jobs/device.pem.crt",
        "key": "~/certs/jobs/private.pem.key",
        "root-ca": "~/certs/AmazonRootCA1.pem",
        "thing-name": "uniqueThingName",
        "logging": {
          "enable-sdk-logging": true,
          "level": "DEBUG",
          "type": "STDOUT",
          "file": ""
        },
        "jobs": {
          "enabled": true,
          "handler-directory": ""
        },
        "tunneling": {
          "enabled": false
        },
        "device-defender": {
          "enabled": false,
          "interval": 300
        },
        "fleet-provisioning": {
          "enabled": false,
          "template-name": "",
          "template-parameters": "",
          "csr-file": "",
          "device-key": ""
        },
        "samples": {
          "pub-sub": {
            "enabled": false,
            "publish-topic": "",
            "publish-file": "",
            "subscribe-topic": "",
            "subscribe-file": ""
          }
        },
        "config-shadow": {
          "enabled": false
        },
        "sample-shadow": {
          "enabled": false,
          "shadow-name": "",
          "shadow-input-file": "",
          "shadow-output-file": ""
        }
      }
      ```

   1. 将该*endpoint*值替换为您在中找到的设备数据端点值[在中配置您的设备 AWS IoT Core](iot-dc-install-provision.md#iot-dc-install-dc-provision)。 AWS 账户 

   1. *uniqueThingName*替换为您用于此设备的事物名称。

   1. 将文本编辑器中的文件保存为 **\$1/dc-configs/dc-jobs-config.json**。

1. 运行此命令设置新配置文件的文件权限。

   ```
   chmod 644 ~/dc-configs/dc-jobs-config.json
   ```

此测试没有使用 **MQTT 测试客户端**。虽然设备将与交换与作业相关的 MQTT 消息 AWS IoT，但任务进度消息仅与运行任务的设备交换。由于任务进度消息仅与运行任务的设备交换，因此您无法从其他设备（例如 AWS IoT 控制台）订阅它们。

保存配置文件后，您已准备继续 [使用 AWS IoT 设备客户端创建和运行作业 AWS IoT](iot-dc-runjobs-prepare-define.md)。

# 使用 AWS IoT 设备客户端创建和运行作业 AWS IoT
<a name="iot-dc-runjobs-prepare-define"></a>

本节中的过程将创建作业文档和 AWS IoT 作业资源。创建作业资源后， AWS IoT 将作业文档发送到指定的作业目标，作业代理会将作业文档应用到设备或客户端。

**Topics**
+ [创建并存储物联网任务的任务文档](#iot-dc-runjobs-prepare-define-jobdoc)
+ [AWS IoT 为一台 IoT 设备运行作业](#iot-dc-runjobs-prepare-define-job)

## 创建并存储物联网任务的任务文档
<a name="iot-dc-runjobs-prepare-define-jobdoc"></a>

此过程创建一个要包含在作业资源中的简单 AWS IoT 作业文档。这份任务文档显示“Hello world\$1” 在任务目标上。

**要创建和存储任务文档：**

1. 选择要将任务文档保存到的 Amazon S3 存储桶。如果您没有现有 Amazon S3 存储桶可用，需要创建一个。有关如何创建 Amazon S3 存储桶的信息，请参阅 [Amazon S3 入门](https://docs.aws.amazon.com//AmazonS3/latest/userguide/GetStartedWithS3.html)中的主题。

1. 为此任务创建并保存任务文档

   1. 在本地主机上，打开文本编辑器。

   1. 复制此文本并粘贴到编辑器中。

      ```
      {
          "operation": "echo",
          "args": ["Hello world!"]
      }
      ```

   1. 在本地主机上，将编辑器内容保存到名为 **hello-world-job.json**的文件中。

   1. 确认文件已正确保存。一些文本编辑器会自动追加 `.txt` 用户保存文本文件时的文件名。如果您的编辑器附加 `.txt` 在文件名中，在继续之前更正文件名。

1. 将替换为路径**hello-world-job.json**，如果它不在您的当前目录中，则将其*s3\$1bucket\$1name*替换为您所选存储桶的 Amazon S3 存储桶路径，然后运行此命令将您的任务文档放入 Amazon S3 存储桶。*path\$1to\$1file*

   ```
   aws s3api put-object \
   --key hello-world-job.json \
   --body path_to_file/hello-world-job.json --bucket s3_bucket_name
   ```

   用于标识您存储在 Amazon S3 中的任务文档的任务文档 URL 是通过替换以下 URL *AWS\$1region* 中的*s3\$1bucket\$1name*和来确定的。记录生成的 URL 以备日后用作 *job\$1document\$1path*

   ```
   https://s3_bucket_name.s3.AWS_Region.amazonaws.com/hello-world-job.json
   ```
**注意**  
AWS 安全性可防止您在外部打开此 URL AWS 账户，例如使用浏览器。默认情况下， AWS IoT 作业引擎使用此 URL，该引擎有权访问该文件。在生产环境中，您需要确保 AWS IoT 服务有权访问存储在 Amazon S3 中的任务文档。

保存任务文档的 URL 后，继续 [AWS IoT 为一台 IoT 设备运行作业](#iot-dc-runjobs-prepare-define-job)。

## AWS IoT 为一台 IoT 设备运行作业
<a name="iot-dc-runjobs-prepare-define-job"></a>

本节中的步骤在 Raspberry Pi 上启动 AWS IoT 设备客户端，在设备上运行作业代理，等待作业运行。它还会在中创建任务资源 AWS IoT，该资源会将任务发送到您的物联网设备并在您的物联网设备上运行。

**注意**  
此过程仅在一台设备上运行任务。

**要在 Raspberry Pi 上启动任务代理：**

1. 在连接到 Raspberry Pi 的本地主机的终端窗口中，运行此命令启动 AWS IoT 设备客户端。

   ```
   cd ~/aws-iot-device-client/build
   ./aws-iot-device-client --config-file ~/dc-configs/dc-jobs-config.json
   ```

1. 在终端窗口中，确认 AWS IoT 设备客户端和显示这些消息

   ```
   2021-11-15T18:45:56.708Z [INFO]  {Main.cpp}: Jobs is enabled
                         .
                         .
                         .
   2021-11-15T18:45:56.708Z [INFO]  {Main.cpp}: Client base has been notified that Jobs has started
   2021-11-15T18:45:56.708Z [INFO]  {JobsFeature.cpp}: Running Jobs!
   2021-11-15T18:45:56.708Z [DEBUG] {JobsFeature.cpp}: Attempting to subscribe to startNextPendingJobExecution accepted and rejected
   2021-11-15T18:45:56.708Z [DEBUG] {JobsFeature.cpp}: Attempting to subscribe to nextJobChanged events
   2021-11-15T18:45:56.708Z [DEBUG] {JobsFeature.cpp}: Attempting to subscribe to updateJobExecutionStatusAccepted for jobId +
   2021-11-15T18:45:56.738Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToUpdateJobExecutionAccepted with code {0}
   2021-11-15T18:45:56.739Z [DEBUG] {JobsFeature.cpp}: Attempting to subscribe to updateJobExecutionStatusRejected for jobId +
   2021-11-15T18:45:56.753Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToNextJobChanged with code {0}
   2021-11-15T18:45:56.760Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToStartNextJobRejected with code {0}
   2021-11-15T18:45:56.776Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToStartNextJobAccepted with code {0}
   2021-11-15T18:45:56.776Z [DEBUG] {JobsFeature.cpp}: Ack received for SubscribeToUpdateJobExecutionRejected with code {0}
   2021-11-15T18:45:56.777Z [DEBUG] {JobsFeature.cpp}: Publishing startNextPendingJobExecutionRequest
   2021-11-15T18:45:56.785Z [DEBUG] {JobsFeature.cpp}: Ack received for StartNextPendingJobPub with code {0}
   2021-11-15T18:45:56.785Z [INFO]  {JobsFeature.cpp}: No pending jobs are scheduled, waiting for the next incoming job
   ```

1. 在终端窗口中，看到此消息后，继续下一步并创建任务资源。请注意，它可能不是列表中的最后一个条目。

   ```
   2021-11-15T18:45:56.785Z [INFO]  {JobsFeature.cpp}: No pending jobs are scheduled, waiting for the next incoming job
   ```

**创建 AWS IoT 任务资源**

1. 在本地主机上：

   1. *job\$1document\$1url*替换为来自的作业文档 URL [创建并存储物联网任务的任务文档](#iot-dc-runjobs-prepare-define-jobdoc)。

   1. *thing\$1arn*替换为您为设备创建的事物资源的 ARN，然后运行此命令。

      ```
      aws iot create-job \
      --job-id hello-world-job-1 \
      --document-source "job_document_url" \
      --targets "thing_arn" \
      --target-selection SNAPSHOT
      ```

      如果成功，该命令将返回类似此结果。

      ```
      {
        "jobArn": "arn:aws:iot:us-west-2:57EXAMPLE833:job/hello-world-job-1",
        "jobId": "hello-world-job-1"
      }
      ```

1. 在终端窗口中，您应该看到 AWS IoT 设备客户端的输出如下所示。

   ```
   2021-11-15T18:02:26.688Z [INFO]  {JobsFeature.cpp}: No pending jobs are scheduled, waiting for the next incoming job
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Job ids differ
   2021-11-15T18:10:24.890Z [INFO]  {JobsFeature.cpp}: Executing job: hello-world-job-1
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Attempting to update job execution status!
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Not including stdout with the status details
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Not including stderr with the status details
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Assuming executable is in PATH
   2021-11-15T18:10:24.890Z [INFO]  {JobsFeature.cpp}: About to execute: echo Hello world!
   2021-11-15T18:10:24.890Z [DEBUG] {Retry.cpp}: Retryable function starting, it will retry until success
   2021-11-15T18:10:24.890Z [DEBUG] {JobsFeature.cpp}: Created EphermalPromise for ClientToken 3TEWba9Xj6 in the updateJobExecution promises map
   2021-11-15T18:10:24.890Z [DEBUG] {JobEngine.cpp}: Child process now running
   2021-11-15T18:10:24.890Z [DEBUG] {JobEngine.cpp}: Child process about to call execvp
   2021-11-15T18:10:24.890Z [DEBUG] {JobEngine.cpp}: Parent process now running, child PID is 16737
   2021-11-15T18:10:24.891Z [DEBUG] {16737}: Hello world!
   2021-11-15T18:10:24.891Z [DEBUG] {JobEngine.cpp}: JobEngine finished waiting for child process, returning 0
   2021-11-15T18:10:24.891Z [INFO]  {JobsFeature.cpp}: Job exited with status: 0
   2021-11-15T18:10:24.891Z [INFO]  {JobsFeature.cpp}: Job executed successfully!
   2021-11-15T18:10:24.891Z [DEBUG] {JobsFeature.cpp}: Attempting to update job execution status!
   2021-11-15T18:10:24.891Z [DEBUG] {JobsFeature.cpp}: Not including stdout with the status details
   2021-11-15T18:10:24.891Z [DEBUG] {JobsFeature.cpp}: Not including stderr with the status details
   2021-11-15T18:10:24.892Z [DEBUG] {Retry.cpp}: Retryable function starting, it will retry until success
   2021-11-15T18:10:24.892Z [DEBUG] {JobsFeature.cpp}: Created EphermalPromise for ClientToken GmQ0HTzWGg in the updateJobExecution promises map
   2021-11-15T18:10:24.905Z [DEBUG] {JobsFeature.cpp}: Ack received for PublishUpdateJobExecutionStatus with code {0}
   2021-11-15T18:10:24.905Z [DEBUG] {JobsFeature.cpp}: Removing ClientToken 3TEWba9Xj6 from the updateJobExecution promises map
   2021-11-15T18:10:24.905Z [DEBUG] {JobsFeature.cpp}: Success response after UpdateJobExecution for job hello-world-job-1
   2021-11-15T18:10:24.917Z [DEBUG] {JobsFeature.cpp}: Ack received for PublishUpdateJobExecutionStatus with code {0}
   2021-11-15T18:10:24.918Z [DEBUG] {JobsFeature.cpp}: Removing ClientToken GmQ0HTzWGg from the updateJobExecution promises map
   2021-11-15T18:10:24.918Z [DEBUG] {JobsFeature.cpp}: Success response after UpdateJobExecution for job hello-world-job-1
   2021-11-15T18:10:25.861Z [INFO]  {JobsFeature.cpp}: No pending jobs are scheduled, waiting for the next incoming job
   ```

1. 当 AWS IoT 设备客户端运行并等待任务时，您可以通过更改`job-id`值并重新运行步骤 1 中的值来提交另一个作业。**create-job**

运行完任务后，在终端窗口中输入 ^C (Control-C) 以停止 AWS IoT 设备客户端。