[AWS] PJ毎のコスト管理まとめ(Cost Explorer/Cost Anomaly Detection/Budgets/タグ付けルール)

単一アカウント内で複数のPJやサービスが運用されているケースのコスト管理についてのメモ
マルチアカウント運用の際にもこれらのサービスの設定が必要になる


PJ開始時にすべきコスト関連の作業

以下は基本的に無料枠で実施できるため、PJ開始時に対処しておく
(SNS通知に微量だが料金がかかる)

1. 運用ルールの定義・周知

  • AWSの利用開始時に、タグ付けルールを定めてメンバに周知する
  • CFnテンプレートにはタグの入力欄を設けておく

2. PJで利用中のリソースに限った総コストの確認/予測

Cost Explorer

  • Cost Explorerのフィルタリング機能を活用する
  • 単一のAWSアカウント内で複数のサービスを運用する場合、タグを付与することで費用を区分できる

3. 異常検出

  • Cost Anomaly Detectionを活用する
  • タグやリソースベースでPJのコストを追跡し、料金の異常発生時に通知させる
    • 例えば、DDoS攻撃による料金の急騰などが挙げられる

4. Budgetsで予算を設定、超過時の通知を設定

AWS Budgets

  • AWS Budgetsを活用して、承認を得た予算に対する状況管理を可能にする

設定手順

運用ルール(タグ付けルール)の定義

単一のAWSアカウント内で複数のサービスを運用する場合、タグを付与することで費用を区分することが可能になる。PJでリソースを作り始める前に、ルールを定めて周知しておく必要がある。

  • タグ付けルール例
    • Project
      • Project毎のコスト管理に活用
    • Owner
      • リソースの作成者を後で判別するために必要。誰がこれ作って放置してるの?を防ぐ
    • Environment
      • 本番、テスト環境などの判別/コスト管理のために活用

CFnテンプレートを利用する場合は、上記のタグを入力値として用意しておくと、つけ忘れを防止できる

コスト配分タグのアクティブ化

Cost Explorer内で、タグによるフィルタリングをするには、リソースに付与したタグを Billing and Cost Management コンソールでアクティブ化する必要がある。会社でOrganizationsを利用している場合、部門のアカウントでは設定権限が無いこともあるので注意。

  • AWS Console/Billing and Cost Management/コスト配分タグ
    • アクティブ化するタグを選択
    • ここでアクティブ化したタグのみ、Cost Explorerでフィルタリングに活用できる
      • リソースにタグを付与しただけでは活用できない

PJのコスト確認/予測方法

  • AWS Management Console/Cost Explorer

    • 過去6か月間のコスト($)がサービス毎に表示される
  • 任意の期間に変更

    • 期間が表示されているタブから選択
  • PJのリソースのフィルタリング

    • 右側のフィルター欄/タグを押下
    • Project名のタグを選択

Cost Explorerタグによるフィルタリング

  • 予測
    • 期間を変更することで、最大12ヵ月先までの予想費用をグラフに表示できる

Cost Anomaly Detectionでコストの異常検出を設定

  • AWS Cost Anomaly Detectionにより、コスト異常検出と原因の分析を自動化できる

    • 無料だが、SNSアラート通知を有効化すると微量の料金がかかる
  • AWSConsole/Cost Explorer/コスト異常検出

    • コストモニターを作成
    • モニタータイプを選択
      • コスト配分タグ
        • PJ毎の総費用を追跡する場合はこちらでPJで運用ルールとして付与したタグを選択する
      • 連結アカウント
        • マルチアカウント形式で運用している場合はこちらにアカウントIDを入力
    • アラートサブスクリプションを設定
      • アラート受信者に、開発チームのteamsのチャンネルやメーリスを登録しておくと管理が楽になる
        1
        コストモニターが異常を検出したときに通知します。アラートの頻度に応じて、E メールまたは Amazon SNS によって指定されたユーザーに通知できます。たとえば、組織の Finance team のサブスクリプションを作成できます。
    • モニターを作成

Budgetsによる予算管理

  • AWS Management Console/Cost Explorer/Budgetsタブ
    • 予算を作成
    • 事前に承認されたPJのコストを上限値として設定する
    • 設定した予算に対する状況は%で確認できる
      • 引き上げが必要になったら、Cost Explorerの予測を元に算出した値で予算管理者から承認を得て、Budgetsの予算を更新する流れになる

参考

関連記事

その他

[CloudFormation] WAFv2(SCOPE: CLOUDFRONT)をIaC化する際に発生するリージョン問題について

AWSでCloudFront Distributionに関連付けるWAFv2リソースをCFnテンプレート化する際の注意点についてのメモ

発生する事象

  • CFnテンプレートの書式が正しくても、CFnを実行するリージョンによって以下のエラーが発生する
    1
    2
    3
    Error reason: The scope is not valid., 
    field: SCOPE_VALUE, parameter:
    CLOUDFRONT (Service: Wafv2, Status Code: 400, Request ID: ...

原因: WAFv2のSCOPE: CLOUDFLONT

  • WAFv2はSCOPEによって、us-east-1にしか生成できないことがある

    • CloudFormation Distributionに関連づけるWAFはコンソールであれば、Globalとするが、実体はus-east-1に生成される
    • CFnでは”SCOPE”というプロパティで、WAFv2がCloudFront向けか、各リージョンに生成するか定義する
      • 以下のように定義した場合、cloudFront Distributionにアタッチ可能なWAFv2リソースとなるが、
        1
        Scope: "CLOUDFRONT"
  • SCOPEについてのルールは公式ドキュメントに以下のように書かれていた

    1
    CLOUDFRONT の場合、米国東部 (バージニア北部) リージョン (us-east-1) で WAFv2 リソースを作成する必要があります。
  • CloudFormtationは選択中のリージョンで実行される

    • SCOPE: CLOUDFRONTのWAFv2リソースがあれば、us-east-1で実行する必要がある
    • 同じテンプレートで定義した他のリソース群も、us-east-1に生成されてしまう
      • 払い出せるリージョンが実質ロックされるので、汎用性が欠けたテンプレートになってしまう…

回避策

以下が考えられる

  • テンプレートの分割
    • WAFv2リソースのみ別にする
      • CloudFront Distributionとの関連付けが面倒ではある
  • us-east-1専用テンプレートとしてルール付けする

同様の問題を経験した人も多いはずなので、そのうちAWS側で解消されるかもしれない

参考

関連記事

[AWS/IaC] Former2によるCloudFormation/Terraformテンプレートの自動出力方法

AWSアカウント内の既存のリソースから、IaCテンプレート(CloudFormation/Terraform)を自動で作成するツールの活用方法と手動で改修すべき範囲についてのメモ

1. Former2の概要

Former2

  • Former2
    • ブラウザで動くWebアプリ
    • サードパーティ製のツール
      1
      Former2では、AWSアカウント内の既存のリソースからInfrastructure-as-Codeの出力を生成することができます。AWS JavaScript SDKを使用して関連するコールを行うことで、Former2はインフラストラクチャをスキャンし、出力を生成するリソースのリストを表示します。
    • CFnテンプレートだけでなく、Terraform等も出力可能
      • CloudFormation
      • Terraform
      • Troposphere
      • CDK (Cfn Primitives) - TypeScript, Python, Java, C#
      • CDK for Terraform - TypeScript
      • Pulumi - TypeScript
      • Diagram - embedded version of draw.io
    • CloudFormerと比較して高機能で2021年現在主流になっている
    • 価格はOSSのため無料
      1
      Former2はローカルでのアクセスや利用は無料ですが、一部のAWSサービスではAPIコールに関連して少額の料金が発生するため、AWSの利用料金に数セント余分に加算される可能性があります。
    • 出力したCFn Templateを汎用的にするには少し手直しが必要であった
      • ex. 固定値のパラメータを入力値を参照するように変更、formerでテンプレートに取り込めない細かいリソースの追記
    • 使用方法は二つ
      • Webアプリとして使用
      • セキュリティの関係でローカルホスティングしたい場合は、自分で動作環境を準備してそこで動かば良い

2. (Former2動作環境の起動)

3. Former2 Setup

3.1. Introduction

Former2 Introduction

  • ブラウザにプラグインを導入

    • Install Former2 Helper for Google Chrome
      Former2 Google Chrome Plugin
  • Continue to Credentialsを押下

3.2. Credentials

Former2 Credential

事前にReadOnlyAccessを付与したIAM UserとAccess Key/Secret Access Keyの用意が必要

  • IAM UserのCredentialを入力

    • Access Key ID
    • Secret Access Key
  • Credentialを正しく認識できたら、以下が表示される

    1
    Logged in as: <IAM User Name>@<AWS Account>
  • 公式説明

    1
    2
    リクエストを認証するには、IAM キーのペアが必要です。リソースを直接インポートすることを計画していない場合は、これらの資格情報で読み取りアクセスのみを提供し、
    ReadOnlyAccessポリシーを割り当てることをお勧めします。インポート機能を使用する予定がある場合は、スタックを作成するために適切な権限を付与する必要があります。
  • Continue to Parametersを押下

3.3. Parameter

Former2 Parameter

  • 独自のCloudFormation Parameterを設定する事ができる
    • 特になければスルー
1
オプションとして、以下にCloudFormationスタックのパラメータを追加することで、独自のCloudFormationスタックパラメータを含めることができます。デフォルト値が設定されている場合、値が一致していれば、出力でこれらのパラメータを参照するために !Ref または !Sub を使用することができます。
  • Continue to Settingsを押下

3.4. Settings

  • CFnテンプレートを出力するだけであればデフォルトでもOK

    • 設定後にGo to Dashboardを押下
  • CloudFormation Spacing

    • 出力のスペース数を変更
  • Logical ID Strategy

    • 論理ID名の付け方を設定
  • Default Output

    • 出力言語の設定
    • デフォルトではCloudFormation
    • ここで、TerraformやCDK, Draw.ioのDiagram等に変更可能
  • Irrelevant Resources

    1
    有効にすると、この設定は無関係とみなされるリソースをスキップします(現在はCloudWatchログストリームのみ)
  • Enable Related Resources

    • 関連リソースを有効化
  • Add All Resources

    1
    以下のボタンを使用して、スキャンしたすべてのリソースを出力に追加します(非推奨)
  • Save / Load Settings

    1
    すべての設定されたパラメータと設定(資格情報を除く)を含むファイルを保存またはロードします。
  • Programming Language

    1
    CDKやPulumiの出力プログラミング言語の好みを変更してください。
  • Default Resources

    1
    この設定を有効にすると、デフォルトのVPCやそのサブネットなどのデフォルトのリソースが含まれます。

以上でセットアップは完了

4. Former2によるテンプレートの出力

テンプレートに含めたいリソースを選択していく

  • Former2のDashboardからサービスを選択

Former2 Dashboard

  • 表示されたオブジェクトから、テンプレート化したいリソースを選択

  • +Add Selected

  • 関連するリソースがタブでまとまっており、直感的に操作できる
    Former2 Select Objects

  • Generate Template

    • オブジェクトの追加完了後に、Generate
    • CFnテンプレートが出力される
    • オブジェクト追加時に確認出来なかった項目も反映されていた
      • ex. tag

generate template

5. Former2で出力されるテンプレートについて

  • Former2では、一部CFnテンプレートに含まれない情報を見受けられた
  • また、各Propertyが固定された状態で出力されてしまうため、汎用的なテンプレートにするには入力値(Properties)の設定が必要になる

例とするPF構成

  • 以下のPF構成をformer2でテンプレート化したケースを考える
    • S3 Bucket
      • アプリをホスティング
    • CloudFront Distribution
      • S3 Bucketをソースとしてアプリを配信
    • AWS WAF
      • CloudFrontにアタッチ
      • アクセスを制限

出力したCFn Temlateに含まれない情報/注意点

  • s3 bucket

    • LifecycleConfiguration
      • Rules
        • Id指定のみで、ルール自体はCFn Templateに取り込めていなかった
        • 別アカウントでテンプレートを実行する場合は同名のルールが無いためエラーになってしまうと思われる
        • ライフサイクル未指定であれば無関係
  • WAFに関する注意点

    • CloudFront用に設定したWAFのリソースはGlobal(CloudFront)として扱われる
    • former2では画面右上のボタンでリージョンを選択するが、Globalが無い
    • 調査したところ、リージョンをUS East(N. Virginia)に設定することで確認可能であった
      • US East(N. Virginia)で生成される仕様になっていため、former2の画面右上のボタンでリージョンを変更するだけで良い

汎用的なテンプレートにするには

  • Parametersで各固定値を自由に設定可能な入力値に変更する

    • CFn Template実行時の入力値としてユーザが設定可能なパラメータを規定できる
      • テンプレートが汎用的に利用可能になり、別Projectやアカウントでも使い回し可能になる
    • 各パラメータには以下を定めることで利便性を高めることができる
      • Description
        • 説明を定義
      • 初期値とバリデーションも定義できる
        • 参考となるような名称を予め定めておくことで、Templateの利便性が高まる
    • 記載例
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      Parameters: # 入力値を定義 
      BucketName:
      # CFn実行時に入力欄に表示されるユーザ向けの説明
      Description: Please write bucket name
      # デフォルト値
      Default: sample-bucket #
      # 入力値のタイプ
      Type: String
      XXXXName:
      ...
  • 各リソースのPropertiesの各項目から入力値(Parameters)を参照する

    • !RefでParametesで定めた入力値を参照できる
    • 入力値の規定/参照例
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      Parameters: # 入力値を定義 
      BucketName:
      # CFn実行時に入力欄に表示されるユーザ向けの説明
      Description: Please write bucket name
      # デフォルト値
      Default: sample-bucket #
      # 入力値のタイプ
      Type: String
      ...
      Resources: # 生成するResourceを定義
      S3Bucket:
      Type: "AWS::S3::Bucket"
      Properties:
      BucketName: !Ref BucketName # 入力値を参照
  • 入力値の参照にはRefを用いる

    • 指定した論理IDのパラメータやリソースを参照する
      1
      !Ref <PropertyName>
      CloudFormationRef
  • Subを使うと変数と文字列を組み合わせられる?

  • !Subを活用すると、入力値と固定値を組み合わせることができる

    • 名称の一貫性や、入力の手間の省力化を見込める
    • 書式
      1
      2
      3
      !Sub "${PJName}-Bucket"
      !Sub "${PJName}-Policy"
      ...

所感

  • Former2で出力したテンプレートの活用方法

    • そのまま固定値で使用しても構わないが、他のPJでも使いまわせる汎用的なテンプレートにするには、paramaterで変数化する必要がある。CFnの記法については最低限知識が必要
  • CFnに精通したメンバがいない場合は、以下の流れでIaC化を図ると良さそう

    1. 0から無理にCFnテンプレを作らず、コンソールやCLIで検証しながらPFを構築
      • 初級者が0からCFnテンプレを書くと細かい内容でハマってしまう(実体験)
    2. ある程度定まってからFormer2で固定値のテンプレートを出力
    3. 固定値を変数化
    4. 以降はCFnテンプレートとGitでPFを管理していく
  • テンプレートの分割について

    • 大規模なPFの場合はテンプレートを分割して、他のテンプレートと入れ子構造にした方が良い
      • Former2でホスティング環境/IAM関連/運用監視関係と分割してテンプレートを出力することで、管理が円滑になる
    • 分割テンプレートを連携させるには、パラメータの受け渡しなどの手間が増えるため、CFnの知識がある程度必要

参考

関連記事

その他

[Angular] build時のError: initial exceeded maximum budget の解消方法

[無料RPA] Windows Power Automate Desktop インストール~Webの自動操作方法

  • MSが提供開始したRPAツールについてのメモ
  • Windows 10ユーザーは無料で使える
  • Webの簡単な操作程度なら10分で誰でも覚えることができる

インストール

  • 以下の”Download free”からインストーラーをダウンロード
    -Power Automate

  • インストーラーを起動
    Windows Power Automate Installer
    F

  • 次へ

  • 使用条件にチェック/インストール
    Windows Power Automate Installer2

  • 以上でインストールは完了
    Windows Power Automate Installer 3

ブラウザ拡張機能の設定

  • メインブラウザがChromeの場合は以下を入れたほうがいい
    image

  • Microsoft Power Automate

    1
    2
    3
    Power Automate を使用すると、コンピューターの手動のプロセスとタスクを自動化できます。

    拡張機能をインストールすると、Web スクリプト、データ抽出、Web テスト、Web フォームへの入力、API 呼び出しなどが自動化されます。また、Power Automate Desktop の Web レコーダーも有効になります。

セッティング

  • Power Automate Desktopを起動
    Power Automate Desktop

  • メールアドレスを入力/Windowsアカウントを選択
    Power Automate Desktop Setting

  • 国を選択/開始する
    Power Automate Desktop Setting 2

  • 以上でセットアップは完了
    Power Automate Desktop Top

使用方法

フローの作成

  • “新しいフロー”を押下
    Power Automate Desktop Making Flow

  • フロー名を入力して作成を押下
    Power Automate Desktop Making Flow 2

  • 後はアクションや変数を設定してワークフローを作り上げていく

Power Automateのアクション

Power Automate Desktop Action

  • ざっと見た限り他のRPAツールで可能な大抵のことができそうでした
    • AWSなどの他社クラウドの操作まで
    • 無料なので、既存のRPAベンダーは厳しそう

使用例1: Webページの自動起動

  • まずはWebページを自動で起動させてみました
  • アクション/Webオートメーション/Webフォーム入力/新しいChromeを起動する
    • 各パラメータを設定後に保存

Power Automate Desktop Chrome

  • 上の実行ボタンを押すことでchromeが自動起動することを確認できる

使用例2: ボタンの自動押下

  • 以下のアクションを追加する
    • アクション/Webオートメーション/Webフォーム入力/Webページのリンクをクリックします

image

  • UI要素の追加を押下
    • 実際の画面から要素を選択できる
    • 今回はGithubを開いてNew Issueボタンを押すように設定した

Power Automate Desktop Sample Flow

所感

  • 使用例のようにボタンを押させていくだけでも、誰でも大抵のWEBアプリの単純操作を自動化できる

    • Webアプリの簡単な動作テストもできそう(エンジニアであればテストコードを書くべきだが)
  • Microsoftにしては直感的に操作可能

    • 使用例程度のフローであれば、特にドキュメントを見ずに5分もかからず作れました
  • ページ上の要素からのデータ取得や、TeamsやExcel等の他のアプリとの連携、条件分岐なども使っていけば、自由度は高そう

    • スクレイピングは自分でプログラムを書くとなると面倒
  • まずは会社の勤退システム(Webアプリ)の自動入力から初めてみようと思います

関連

Angular 11 buid error: Index html generation failed.Inlining of fonts failed. An error has occurred while retrieving https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap over the internet.

  • Angular 11で有効化されたフォント最適化機能について
  • プロキシ環境下で開発をしている場合、ng buildでプロキシエラーが発生してしまう

発生した事象

  • Anular11 へのアップデート後に、ng buildで以下のエラーが発生する
    1
    2
    3
    4
    5
    6
    7
    > ng build --prod
    √ Browser application bundle generation complete.
    √ ES5 bundle generation complete.
    √ Copying assets complete.
    × Index html generation failed.
    Inlining of fonts failed. An error has occurred while retrieving https://fonts.googleapis.com/css?family=Roboto:300,400,500&display=swap over the internet.
    connect ETIMEDOUT

原因

  • Angular 11からインラインフォントへの新機能が追加されている
  • プロキシ環境下で開発を行っている場合は、build時にプロキシを通過できずエラーが発生してしまう
    • 正しくHTTP_PROXY/http_proxyの環境変数を設定していても無視されてしまう

回避策

  • 幾つかGitのissueに同様の事象が挙がっていたが、以下が結論であった

    1
    ビルドサーバーはファイアウォールの外にはアクセスできません。それをオフにするのが唯一の選択肢だと思います。
  • font optimizationをオフにする方法

要約

  • 設定ファイル(angular-pj/angular.json)でbuildの設定を変更することで解決可能

  • デフォルトの設定

    • “optimization”: trueとなっている
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      "projects": {
      "app_name": {
      ...
      "architect": {
      "build": {
      "builder": "@angular-devkit/build-angular:browser",
      "options": {
      ...
      },
      "configurations": {
      "production": {
      "fileReplacements": [
      {
      "replace": "src/environments/environment.ts",
      "with": "src/environments/environment.prod.ts"
      }
      ],
      "optimization": true,
  • angular.jsonの各項目について

    • “architect”
      • コンパイルやテスト実行などの複雑なタスクを実行するためにCLIが使用するツール
      • ターゲットの設定に従って、指定されたタスクを実行するために指定されたビルダーを実行するシェル
    • “build”
    • “configurration”
      • このセクションでは、異なる目的地のための代替構成を定義し、名前を付ける。このセクションには、それぞれの設定のためのセクションがあり、その環境でのデフォルトのオプションを設定する。
    • “optimization”
      • より細かい設定を行うために、ブール値かオブジェクトのいずれかを指定できる。このオプションを使用すると、ビルド出力のさまざまな最適化が可能になる
      • fonts
        1
        2
        フォントの最適化を有効にします。
        注意: これにはインターネットへのアクセスが必要です
      • fonts optimsization options
        • inline
          1
          2
          アプリケーションの HTML インデックス ファイル内の外部の Google フォントとアイコンの CSS 定義をインライン化することで、レンダリング ブロック要求を減らします。
          注意:これにはインターネットへのアクセスが必要です。
  • 以下に変更

    1
    2
    3
    "optimization": { 
    "fonts": true
    }
  • 以上でbuildが問題なく実行できた

    1
    2
    3
    4
    5
    > ng build --prod
    √ Browser application bundle generation complete.
    √ ES5 bundle generation complete.
    √ Copying assets complete.
    √ Index html generation complete.

同様の事象はgitのissueで複数確認できたが、無効化する以外の解決策は見つけられなかった。

参考

関連記事

その他

[Angular] ng build時のエラー --aotについて

  • Angular 9以降でデフォルト化されたAOTについてのメモ
    • 8以前のバージョンからアップデートした際に注意すべきポイント

発生する事象

  • Angularのバージョンアップ後、build実行時にエラーが発生する
    • –aot オプションが必要になる
      1
      ng build --aot

原因/AOT

  • Angular9 以降ではahead-of-time (AOT)コンパイラがデフォルトに採用されている

  • Ahead-of-time (AOT) コンパイラ

    • 引用
      1
      2
      3
      Angular の ahead-of-time (AOT) コンパイラ は、ブラウザがそのコードをダウンロードして実行する前に、
      ビルドフェーズ中にAngular HTML コードと TypeScript コードを効率的な JavaScript コードに変換します。
      ビルドプロセス中にアプリケーションをコンパイルすると、ブラウザでのレンダリングが速くなります。
  • Angularには、アプリケーションをコンパイルする2つの方法がある

    • Just-in-Time (JIT)
      • 実行時にブラウザ内でアプリケーションをコンパイルします。This was the default until Angular 8.
    • Ahead-of-Time (AOT)
      • ビルド時にアプリとライブラリをコンパイルします。This is the default since Angular 9.
  • ng build (build only)またはng serve (build and serve locally)のCLIコマンドを実行すると、
    コンパイルの種類(JITかAOTか)は、angular.jsonで指定したビルド設定のaotプロパティの値に依存する

    • Angular 8以前で開始した場合はデフォルトでtrueではない

これらの要因により今回のエラーが発生したと思われる

aotの有効化

  • 設定を変更することで、buildの度にオプション(–aot)を付与せずともエラーを回避可能になる

  • 以下の設定ファイルでbuildの設定を変更することで解決できる

    • aotをtrueとするだけ
  • angular-pj/angular.json

    1
    2
    3
    4
    5
    6
    7
    8
    9
    "build": {
    "builder": "@angular-devkit/build-angular:browser",
    "options": {
    "outputPath": "dist/reacq-pj",
    "index": "src/index.html",
    "main": "src/main.ts",
    "polyfills": "src/polyfills.ts",
    "tsConfig": "tsconfig.app.json",
    "aot": true, //こちらを変更

参考

関連記事

その他

[Angular] An unhandled exception occurred: Port 4200 is already in use の解決策

ng serve実行時のエラーについてのメモ

Error

  • 以下のエラーが出る
    1
    2
    > ng serve
    An unhandled exception occurred: Port 4200 is already in use. Use '--port' to specify a different port.

解決策

Port 4200のプロセスをkillする

  • ポートが:4200と表示されているプロセスを探す
    1
    2
    3
    > netstat -a -n -o
    プロトコル ローカル アドレス 外部アドレス 状態 PID
    TCP 127.0.0.1:62279 127.0.0.1:4200 ESTABLISHED 18492
  • pidを指定してプロセスをkill
    1
    2
    > taskkill -f /pid 8464
    成功: PID 18492 のプロセスは強制終了されました。
  • 以上でserve 可能になる
    1
    > ng serve

参考

関連記事

その他

[Angular x AWS SDK for JavaScript] SPAからAWSのデータを取得する際の待ち合わせ処理(非同期処理)

  • SPAのプラットフォームにAWSを採用した際によく書くロジックについてのメモ

    • ex. クライアントからs3 bucketのobjectを取得して画面に表示
  • AWS SDKでデータを取得するまではディベロッパーガイドを見れば容易だが、待ち合わせ処理の書き方が少し面倒

前提知識


実装例

AWS SDK for JavaScript

  • 想定する状況

    • Angularのコンポーネント生成時(画面遷移時)に自動でAWS(S3)から情報を取得して画面に表示する
  • AWSからデータを取得して値を取り出すまでを待ち合わせ処理にする例

    1. ComponentからServiceのロジックを呼び出す
    2. Service内でAWSからデータを取得
      • 変数 = new Promise() の形式で、AWSへ問い合わせるロジックを書く
        • resolve(data)で変数に返り値を格納
      • 各関数間の待ち合わせ処理は async/await で実現する
    3. Promise型の返り値をComponentへ返す
    4. Component側で forkJoin().subscribe を使って受け取る
      .then()で受け取ってもOK (Angularでは基本subscribeが推奨されている)

書き方は他にもあるかも

AWS SDKを導入するまで

sampleの構成

  • request.service.ts

    • AWSとの通信用のService
  • sample.component.ts

    • Serviceを呼び出し、返り値を受け取るComponent
  • sample.component.html

    • 取得したデータを表示する

AWSへリクエストするService

以下の様に書かないと、データが帰ってくる前にcomponentにundefinedを返してしまう

  • AWSへのリクエストからの待ち合わせで返り値を取り出す方法

    • Promiseの中でリクエストする
    • GETしたデータをresolve()で返す
    • resolveで返された値をreturn
  • async/await でService内の各関数間の待ち合わせ処理を実現する

  • Service記載例 (request.service.ts)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    import { Injectable } from '@angular/core';

    // aws-sdkを変数AWSとしてimportする必要がある
    import * as AWS from 'aws-sdk'

    @Injectable({
    providedIn: 'root'
    })

    export class requestService {
    constructor() { }

    // 1. Componentから呼び出される関数
    async getAwsData() {
    return await this.requestData();
    }

    // 2. AWSに対してリクエストする関数
    async requestData() {

    // 変数requestに返り値を格納 待ち合わせのためにPromiseを用いる
    const request = new Promise((resolve, reject) => {

    // AWS SDKサービスのオブジェクトを宣言
    let bucket = new AWS.S3(({params: {Bucket: 'myBucket'}});

    // リクエストを実行 基本的に以下の様にdataに返り値が入る
    bucket.listObject(({}, (err, data ) => {
    if (err) {
    let errorMessage = String(err);
    alert(errorMessage);
    }
    else {
    // resolveでPromiseの処理を終了させる
    resolve(data); // データ加工が必要であれば、ここで関数を呼び出す
    }
    });
    });

    // エラーハンドリング
    request.catch((error) => {alert(error); } );
    // リクエスト結果を返す
    return request;
    }

    }
  • s3のデータの扱い方についてはディベロッパーガイドを参照。ここではあくまで共通した待ち合わせ処理の記法のみ


データを受け取るComponent側

  • Component側の受け取り方は2パターンある

    1. .then()
    2. .subscribe()
  • Component側の実装例(sample.component.ts)

    • serviceを呼び、データを受け取る
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//rxjs 待ち合わせ処理に必要
import { forkJoin } from 'rxjs';

let awsData; //データ受取用の変数を宣言

// 起動時に取得 → ngOnInitから呼び出す
ngOnInit() {
getData();
}

getData() {

// Credential認証 Service側でもいいかも
AWS.config.credentials = new AWS.Credentials("<access key>","<secret key>")

// thenで受け取る例
this.requestService.getAwsData().then(response =>{
console.log(response);
this.awsData = response; // 取得データを代入
});

// subscribeで受け取る例 Promise型のため、forkJoinが必要
forkJoin(this.grequestService.getAwsData()).subscribe(result => {
this.awsData = result[0]; // 取得データを代入
});
}
  • sample.compoent.html 取得したデータを画面に表示
    1
    {{getAwsData}}

参考

関連記事

その他

[Angular/TypeScript(JavaScript)] 非同期処理/待ち合わせ処理のまとめ (Observable/subscribe/forkJoin/Promise/async/await/then)

  • Angular等のTypeScriptベースのフレームワークでフロントエンドを開発する際には、待ち合わせ処理が度々問題となる
  • 外部通信が基本的に非同期処理であるため、返り値を加工するにはひと手間加える必要がある

前提知識

同期/非同期/待ち合わせ処理とは?

プログラムを書く前にどれが最適化か?を判断する必要がある(書き方が変わってくる)

  • 非同期処理

    • 実行完了を待たずに次の処理を並列で開始する
    • メリット
      • 処理の高速化を図れる。
      • 一部の処理でエラーが出ても、他の処理は問題無く動く
      • 処理完了までユーザーを待たせない
    • デメリット
      • 返り値を使って次の処理を行いたい時に問題が発生する
        (返り値無しの状態で次の処理を実行してしまう)
  • 同期処理

    • 処理完了まで他の処理をストップする
    • メリット
      • 処理を順に実行できるため、プログラムを書きやすい
    • デメリット
      • 処理完了までユーザーを待たせる事になる
  • 待ち合わせ処理

    • ある条件が満たされるまで処理を待たせる
      • ex. 返り値が戻ってくるまである処理の開始を待たせる
    • 同期処理とイコールではない
    • 複数の処理群としてみると非同期でOKだが、個々の処理は待ち合わせて順番に実行させたいケースがある
      • ユーザーが処理の完了を待つ必要がない → 非同期でOK
      • データ取得後に加工したい → 待ち合わせ処理が必要
  • TypeScript(JavaScript)においては、以下のような処理が非同期で実行されることを考慮する必要がある

    • API通信
    • データベース通信
    • その他の重い処理全般

TypeScript(JS)の待ち合わせ処理問題とは

上述の非同期で動く特性から、初級者は以下の問題でハマることが多い

  • TypeScript(JS)では、プログラムが書かれた順に動くとは限らない

    • 基本的に非同期処理で動く
      • 非同期処理は重い処理の終了を待たずに、次の処理を進められるので、高速化という意味では有効だが、困るシーンもある
  • よくあるケース

    • 外部APIと通信してデータを取得する場合、その戻り値が帰ってくる前に次の処理に進んでしまう。そのため、以降の処理がデータ無しで行われてしまう
    • 正しく外部にリクエストできている筈が、データ=undefinedと出力されてしまう
      • この辺りはChromeの開発モードで出力順を見ると理解し易い
  • 回避策: 待ち受け処理/同期処理を実現する(返り値が来た後に次の処理を実行させるように書き換える)
    • 書き方は色々ある
      1. Observable, subscibeを活用して待ち合わせ処理を実現する
      2. Observable, forkJoin()を活用して待ち合わせ処理を実現する
      3. aync/awaitを利用して同期処理化する
      4. Promise, then()を活用して同期処理化する

Observable型を使って待ち合わせ処理を実現するパターン

  • Angularでは適したケースであれば、基本的にPromiseよりもObservableが推奨されている

  • service側の返り値をobservable型に定義、component側で.subscribe()で受け取り、その中に処理を書き込む

  • ポイント

    • Observableでも待ち合わせ処理は実現できるが、同期処理はできない
    • 同期処理についてはPromiseを使う
    • ストリームを扱える

1. Observable & subscribe()

  • Service側

    • 返り値をObservable型で定義
  • Component側

    • .subscribe()で返り値を受け取る
  • sample.service.ts

    • Observable型で返り値を返す
      1
      2
      3
      4
      5
      6
      getmethod(){
      return observable = new Observable<number>(observer => {
      // 外部APIとの通信処理

      });
      }
  • sample.component.ts

    • 書式:observable.subscribe()
1
2
3
4
5
6

this.sampleService.getMethod().subscribe(value => {

// 返り値を利用する処理をここに書く

});

2. Observable & forkJoin()

  • forkJoin()を活用すると、Observableの全ての処理の完了を待って次の処理を実行できる

    • ユースケース
      • 複数回外部APIにリクエストを実行して、全てのデータが帰ってきてから加工
  • 書式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 複数の外部リクエストを実行してobservable型で受けとる
    // 配列hogehogeの中身を一つずつ引数として渡して実行する例
    const observable = hogehoge.map(hoge => {
    return this.sampleService.getData(hoge).pipe(catchError(e => observableOf({"error": e})))
    });

    // 待ち合わせ処理
    forkJoin(observables).subscribe( response => {
    // 以降に処理を記載
  • 活用例は以下の記事に記載した


Promise型を使って同期処理化するパターン

3. async/awaitを活用する

  • asyncをつけた関数の返り値はPromise型となる

  • asyncをつけた関数はawaitで待てる

  • await

    • Promiseの値が取り出されるまで待つ
  • async

    • awaitキーワードを使っている関数の頭に付ける必要がある
  • import必要?

  • ポイント

    • 同期処理化したい関数の宣言時:頭にasyncを付ける
    • 同期処理化したい関数の実行時:awaitを付ける
    • awaitはasyncを付けた関数内でしか実行できない

Serviceで外部API通信を実行 ⇒ Component側の変数に受け取る例

  • sample.component.ts
    • awaitを付けた関数の処理を待つ
      1
      2
      3
      4
      5
      6
      let result; // 返り値を受け取る変数
      async ngOnInit() {
      // Service経由で外部APIからデータを受け取る
      this.result = await this.sampleService.getMethod()
      console.log(this.getData);
      }
  • sample.service.ts
    • 関数の頭にasyncを付ける
      1
      2
      async getMethod(){
      }

複数の関数を順に実行する例

1
2
3
4
5
6
7
8
9
10
11
12
13
// プログラムの大筋
async function main() {
const x = await getX()
const y = await getY()
console.log(x + y)
}
async function getX() {
return 1
}
async function getY() {
return 2
}
main()

アロー関数の場合はasyncをつける箇所が異なる

  • Angularの場合は基本的にアロー関数が推奨されているのでこの書き方も覚えた方が良い
1
2
3
4
5
6
7
8
// functionによる関数宣言
async function sampleFunc() {
// 処理内容
}
// アロー関数による関数宣言
const sampleFunc = async() => {
// 処理内容
}

4. Promise, .then()を活用する

参考

関連記事

非同期処理参考

@EventEmitter @Input @Output @ViewChild ACM AMP API Gateway AR AR.js AR.js Studio AWS AWS Amplify AWS Budgets AWS Cost Explorer AWS SDK for JavaScript AddThis Adobe XD Alexa Amazon CloudWatch Amazon Honycode Amazon SNS Android Angular Angular Material AngularFire AppSync Augury C CDN CI/CD Cloud Craft Cloud9 CloudFormation CloudFront CloudTrail Cognito Cost Anomaly Detection Cubase ai Cubasis LE DTM Disqus DynamoDB Elgato HD 60S Firebase Firebase Hosting Former2 Github Github Actions Github.com GithubEnterprise GithubPages Google Chrome Google Cloud Shell GraphQL Hexo Hosting IAM Ionic JSON JavaScript LadioCast Logging LowCode MFA MS Authentication MacBook Pro 16 Mind Node NETDUETTO Netflix Party Netlify Network NoCode Observable PO PdM Promise RPA ReactiveForm Recognition Route53 S3 SAM(Serverless Application Model) SAR SSL SYNCROOM Schematics ScrumInc Serverless Service Siri Sitemap Spark AR Steinberg UR44C Teams Touch Cast Studio Treetable TypeScript UI UI Bakery WAF WAFv2 WEB Page Dev WEB会議 WebAR WebSocketAPI Webhook Windows Power Automate Wireshark aot async/await aws config cloud9 display.land draw.io e2e test filter() forkJoin() google search console hexo-generator-amp iOS iPad Pro iPhone icarus map() mat input mat tree mat-checkbox mat-input mat-selection-list mmhmm ngFor plantUML popIn Aladdin2 then() vscode ”global is not defined” らくがきAR アジャイル アジャイル開発 クロスプラットフォーム ショートカット スクラム スクラム開発 テレワーク ファイル操作 ブラウザ型IDE プロダクトオーナー プロダクトマネージャー プロトタイピング リモートセッション 共同開発 双方向データバインディング 待ち合わせ処理 認定スクラムマスター 静的WEB Hosting 静的WEBサイトHosting
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×