6分以上を可能に！AWSを駆使してGASの実行時間制限を超えてみた

## はじめに

GAS便利ですよね〜。
個人的に業務用のGoogle Sheetsと組み合わせた、ちょっとした自動化で一番ポテンシャルを発揮と思っています。
さらに、AWSのサービスと組み合わせることでより高度な自動化を実現することも可能です。
しかし、GASの最大実行時間が公式により[6分に制限](https://developers.google.com/apps-script/guides/services/quotas?hl=ja#current_limitations)されているため、多くの方が複雑な処理を実行する際に制約を感じることもあるかもしれません。

そこで、今回はこの課題を解決するため、AWSを利用した実行時間の制約を受けないアーキテクチャの一例をご紹介します！

## 課題

こんな感じの構成を想定しております。

![img0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/fc43881e-7eb5-e1fb-d4b0-80b873f87b1f.png)

- 複雑な処理をAWSに委任
    - GASでAWSのサービスを使用
    - 実行時間制限の回避法
- 結果をGoogle Sheetsに書き込み
    - AWSのサービスから書き込み処理

を順に解決していこうと思いますー！

## 解決編

まずはAWS周りです。
[AWS API を GAS (Google Apps Script) から直接呼び出す](https://akkinoc.dev/posts/2022/05/15/aws-api-from-google-apps-script/) を参考に導入していきましょう！
実際のコードは以下です。

https://github.com/smithy545/aws-apps-scripts

![スクリーンショット 2023-10-14 0.05.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/8fc96ef2-006e-b656-4600-e6e6c9529928.png)

のようにaws.gsとしてaws.jsを保存します。
するとグローバルで`AWS`クラスが使用できるようになり、リクエストを送れます🚀
```js
function myFunction() {
  AWS.init("MY_ACCESS_KEY", "MY_SECRET_KEY");
  var instanceXML = AWS.request('ec2', 'us-east-1', 'DescribeInstances', {"Version":"2015-10-01"});
  ...
}
```

これでGAS → AWSへの繋ぎ込みは完了しました。

さて、次は実行時間の回避方法ですが・・・・、使用するのは

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/a3a33c46-aed9-fd4e-9608-20ca1d97bf23.gif">

そうです、[SQS](https://aws.amazon.com/jp/sqs/)です。

つまり、GASの仕事はSQSへエンキューするだで、AWSのサービスが実行する複雑な処理はAWSクラウドに移譲する構成です。

実行側の待機時間に制限がある場合、使わない手はないです！

構成図を更新すると以下のようになります。

![名称未設定ファイル.drawio (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/d0292d0e-06ef-a918-650f-6f6f9111f8be.png)

GASからSQSを呼び出し、AWSサービスでデキューする構成で課題を解決できそうです。

### 実装

さて、先ほどのコードを用いて、GASは以下のようにしました。


```js
function myFunction(){
    AWS.init("YOUR_ACCESS_KEY", "YOUR_SECRET_KEY");
    const res = AWS.request(
      "sqs", 
      "ap-northeast-1", 
      "SendMessage", 
      {}, 
      "POST",
      {   
        "QueueUrl": "https://sqs.ap-northeast-1.amazonaws.com/xxxx/test-queue",
        "MessageBody": "hello world"
      },
      "",
      "/",
      {'contentType': 'application/x-www-form-urlencoded'}
    )
    console.log(res.getResponseCode())
    console.log(res.getContentText())
}
```

ログも残しているし、大丈夫ですね！

さぁ実行！

![1415914174499279757.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/d761d144-6e63-66ee-7788-fc57f0c29ebf.gif)

・・・

![スクリーンショット 2023-10-14 0.29.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/ba389319-598b-d175-05fd-9eab1fecdcf9.png)

・・・
んん？？

```xml
<?xml version="1.0"?>
<ErrorResponse xmlns="http://queue.amazonaws.com/doc/2009-02-01/">
  <Error>
    <Type>Sender</Type>
    <Code>AccessDenied</Code>
    <Message>Access to the resource https://sqs.ap-northeast-1.amazonaws.com/ is denied.</Message>
    <Detail />
  </Error>
  <RequestId>3a0a6747-9868-54ec-91d1-3ae4fc17f7dc</RequestId>
</ErrorResponse>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/332e8412-d283-61d9-6656-a6d7d41e80af.png)

んんん？？400？何が悪いのでしょうか。

### 問題解決

以下調査したこと
- QueueURLに問題なし
- アクセスキーも問題なし
- CLIでは成功

とりあえずAPIレファレンスを見てみましょう。

https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html#SQS-SendMessage-request-MessageBody

ふむふむ、リクエストボディは問題なさそう・・・、

Sample Requestは…。

```
POST /177715257436/MyQueue/ HTTP/1.1
Host: sqs.us-east-1.amazonaws.com
X-Amz-Date: <Date>
Content-Type: application/x-www-form-urlencoded
Authorization: <AuthParams>
Content-Length: <PayloadSizeBytes>
Connection: Keep-Alive
Action=SendMessage
&MessageBody=This+is+a+test+message
&MessageAttribute.1.Name=my_attribute_name_1
&MessageAttribute.1.Value.StringValue=my_attribute_value_1
&MessageAttribute.1.Value.DataType=String
&MessageAttribute.2.Name=my_attribute_name_2
&MessageAttribute.2.Value.StringValue=my_attribute_value_2
&MessageAttribute.2.Value.DataType=String
```

おや、Content-Typeが`application/x-www-form-urlencoded`になっていますね。
ということは、json形式ではリクエストが送れないのかな？

大元のリポジトリを確認すると、すでに修正のプルリクが送られれいました。

https://github.com/smithy545/aws-apps-scripts/pull/10

ここで修正された`aws.js`を用いると・・・。


![スクリーンショット 2023-10-14 0.41.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/61476a51-45b3-f5a4-b6f6-21448ca5f768.png)

```xml
<?xml version="1.0"?>
<SendMessageResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
  <SendMessageResult>
    <MessageId>e6289c58-98f1-4cb4-b18c-a52adad6b3f3</MessageId>
    <MD5OfMessageBody>5eb63bbbe01eeed093cb22bb8f5acdc3</MD5OfMessageBody>
  </SendMessageResult>
  <ResponseMetadata>
    <RequestId>584b451d-39ed-590a-9d17-18be5ea2f13f</RequestId>
  </ResponseMetadata>
</SendMessageResponse>
```

おおー！成功しました！

あとはこのSQSと使用したいAWSサービスを連携させておしまいです！

Google Sheetsへの書き込みはすでに素晴らしい記事がたくさんあるので、よければそちらを参考にしてください！


## まとめ

この記事では、GASの実行時間制限をクリアするための一つの方法として、AWS SQSを利用したアーキテクチャを提案しました。

現在、さまざまなサービスのソースコードを見る機会がありますが、歴史のあるサービスの多くは、リクエストをapplication/x-www-form-urlencodedで受け付けていることが多いように感じます（あくまで体感ですが）。
SQSは歴史のあるサービスなので、この形式を採用しているのでしょうか？

何はともあれ、お読みいただきありがとうございました！

![giphy.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759541/858c2bef-d05c-ba41-55a8-87cdf4459043.gif)