sitateru tech blog: Lambda

sitateru tech blog

シタテルの技術やエンジニアの取り組みを紹介するテックブログです。

ラベル Lambda の投稿を表示しています。 すべての投稿を表示
ラベル Lambda の投稿を表示しています。 すべての投稿を表示

2019年2月21日木曜日

Alexaスキルを作ろう - 第2回

2月 21, 2019
こんにちは。シタテルでエンジニアをしている熊谷です。

SPECというサービスのバックエンド開発などを行っています。

今回は前回の続きで、Alexaスキルの作成について書いていきます。


今回は、前回作成したスキルから呼び出されるLambdaを作成します。

まずAWSコンソールにログインして、Lambda - 関数の作成に行きます。

そこから「一から作成」、「設計図」などが選べます。

「設計図」でalexaを検索すると、
それぞれのスキルタイプに合わせたsdkが用意されています。
使用したいタイプのsdkがある場合は、それを使用しましょう。

今回はとても単純なスキルを作成したので、「一から作成」を選択します。
いろいろな言語が選べますが、今回はNode.jsで作成しました。

関数を作成すると、シンプルなレスポンスを返す関数が書かれているので、その中身を変更します。

今回作成したスキルは、「言葉を逆さまにする」です。
シンプル...!

コードを記述します。

exports.handler = async (event) => {
  const word = event.request.intent.slots.word.value;
  const response = {
    "version": "1.0",
    "response": {
      "outputSpeech": {
        "type": "PlainText",
        "text": word.split('').reverse().join('')
      },
      "shouldEndSession": false
    },
    "sessionAttributes": {}
  };
  return response;
};

こんな感じになりました。

responseの形式について、詳しくは応答の形式を参考にしてください。
「intent.slots.word」の部分の「word」は前回設定した「スロット名」に対応します。

次にこのLambdaを呼び出すトリガーを設定します。

「トリガーの追加」から、「Alexa Skills Kit」を選択して、スキルID(alexa developer consoleを参照)を設定します。

alexa developer consoleでテストしてみましょう。

前回、スキルの呼び出し名とサンプル発話を設定しました。

テスト画面で、

「<スキルの呼び出し名>を開いて、<サンプル発話>おはよう」と入力すると‥


ちゃんと逆さまにして返してくれましたね!

シンプルなスキルですが動くと面白いと思います。


今回はここまでにします。

次回は実機でのテストとスキルの公開について書ければと思います。

ありがとうございました!

2018年12月25日火曜日

[第一回]SansanとHubSpotの連携

12月 25, 2018

こんにちは、シタテルエンジニアの工です!
今回は、SansanとHubSpotの連携の仕方について書いていきます 🚀

はじめに

シタテルでは、衣服生産をSCS、マーケティング・営業の部分をHubSpotを使って管理しています。

HubSpotを導入する際に、Sansanの情報をHubSpotに同期したいという要望があったので、SansanのAPIとHubSpotのAPIを組み合わせて同期処理を実装しました。

AWSLambdaを使って、定期的に同期処理を実行しています。

HubSpot公式にもSansanとハブスポットの連携の仕方という記事も公開されていますので参考にしてみてください。

Sansanの名刺情報をHubSpotにインポートする

使うもの

余談ですが実装したときAWSLambdaにはRubyの選択肢がなかったのですが、今は使用できるみたいですね。
普段はRubyを使うことが多いので、次にLambdaを使うときはRubyで実装してみたいです。

Sansanの情報を取得

公式ドキュメント Sansan Open API

handler.js

const axios = require('axios')
const moment = require('moment')
axios.defaults.headers.common['X-Sansan-Api-Key'] = process.env.SANSAN_API_KEY
axios.defaults.headers.get['Content-Type'] = 'application/json'

module.exports.importSansanData= async (event, context, callback) => {
  var updatedFrom = moment().subtract(2, 'hours').format("YYYY-MM-DDTHH:mm:ss")+"Z"
  var updatedTo = moment().format("YYYY-MM-DDTHH:mm:ss")+"Z"

  await axios.get(`https://api.sansan.com/v2.0/bizCards?updatedFrom=${updatedFrom}&updatedTo=${updatedTo}&range=all`)
      .then(function (response) {
        importHubspot(response)
        callback(null, response.data)
      })
      .catch(function (error) {
        callback(error)
      });
};

詳しくはこのあたりを参考にしてください。
AWSLambdaとServerlessを使ってみる[第1回]
AWSLambdaとServerlessを使ってみる[第2回]

日時取得のところがとてもブサイクです... 😢
なぜかタイムゾーンZにしないとうまくいかなっかった 🤔
本当は+09:00に設定したい。

var updatedFrom = moment().subtract(2, 'hours').format("YYYY-MM-DDTHH:mm:ss")+"Z"
var updatedTo = moment().format("YYYY-MM-DDTHH:mm:ss")+"Z"

HubSpotにインポート

取得したSansanデータをインポート。
propertyは数が多いのでほとんど割愛して記載します。

公式ドキュメント HubSpot Developers

handler.js

function importHubspot (response) {
  response.data.data.forEach(createContact)
}

function createContact (value, index) {
  var properties = [
      {
        property: 'email',
        value: value.email
      },
      {
        property: 'firstname',
        value: value.firstName
      },
      {
        property: 'lastname',
        value: value.lastName
      }
    ]

  axios.post(`https://api.hubapi.com/contacts/v1/contact?hapikey=${process.env.HUBSPOT_API_KEY}`, {
    properties: properties,
  })
  .then(function (response) {
    console.log(response.data)
  })
  .catch(function (error) {
    console.error(error.response.data)
  });
}

上の例はひとつひとつPOSTしていますが、こちらのAPI使えば1回のPOSTでまとめてCreateできます。
Create or update a group of contacts | Contacts API

CloudWatchでスケジュールを設定

serverless.ymlにスケジュールを設定します。
2時間おきにインポート 🚀

serverless.yml

functions:
  importSansanData:
    handler: handler.importSansanData
    events:
      - schedule: cron(0 */2 * * ? *)

これで2時間おきに、Sansanの名刺情報がHubSpotのコンタクトに同期されます!👏

最後に、deploy 🚀

serverless deploy -v

まとめ

今回はSansanとHubSpotのAPIを使って、Sansanの名刺情報をHubSpotのコンタクトにインポートする方法について書きました。

SCSと外部サービスとの連携は今後もどんどん加速していくと思います!
マーケティング・営業 -> 衣服生産 -> 請求この流れがシステムでシームレスに実現できるように開発中です 💻

2018年11月30日金曜日

AWSLambdaとServerlessを使ってみる[第2回]

11月 30, 2018

こんにちは、シタテルエンジニアの工です!

AWSLambdaとServerless第2回に入っていきます!
前回は、AWSLambdaとserverlessについてさらっと確認して
serverlessでServiceをcreateするところまでをやってきました。
AWSLambdaとServerlessを使ってみる[第1回]|sitateru tech blog

今回は実際にSansan OpenAPIを利用して名刺情報を取得してみます 🚀

SansanAPI


公式ドキュメント Sansan Open API

名刺API 名刺Set取得(期間指定)を使ってみます。
SansanAPIを利用するにはAPI Keyが必要です。
取得方法はこちらを参考にしてください。

作る

前回createしたServiceを利用して作っていきます。
現在この2ファイルが作成されている状態です。

  • serverless.yml
    • 各種設定を書いていきます
  • handler.js
    • 処理を書いていきます

axiosインストール

今回は、httpリクエストにaxiosを使用します。

$ npm install axios

インストールされました

.
├── handler.js
├── node_modules
│  ├── axios
├── package-lock.json
└── serverless.yml

serverless.yml

環境変数の設定

lambdaには環境変数を設定することができます。
SansanAPIKeyを環境変数として設定してみます。
serverless.yml

# you can define service wide environment variables here
  environment:
    SANSAN_API_KEY: xxx

環境変数を利用する場合は、このように取得できます。

process.env.SANSAN_API_KEY

handler.js

それでは処理を書いていきます。
lambdaの非同期処理とcallbackについてはこちらを参考にしてください。

名刺情報はお見せできないので、取得した件数を出力してみます。

'use strict';

const axios = require('axios')
axios.defaults.headers.common['X-Sansan-Api-Key'] = process.env.SANSAN_API_KEY
axios.defaults.headers.get['Content-Type'] = 'application/json'

module.exports.hello = async (event, context, callback) => {
  var updatedFrom = "2018-11-26T01:00:00Z"
  var updatedTo = "2018-11-27T21:00:00Z"

  await axios.get(`https://api.sansan.com/v2.0/bizCards?updatedTo=${updatedTo}&range=all&entryStatus=completed`)
      .then(function (response) {
        callback(null, response.data.data.length)
      })
      .catch(function (error) {
        callback(error)
      });
};

deploy

cliでdeployします。
serverlessを使わない場合、serviceを手動でzipにしてawsにdeployする必要があるのでとても面倒です...

$ serverless deploy -v

deployが完了したら情報が出力されます。

...
Serverless: Stack update finished...
Service Information
service: hello-sansan
stage: dev
region: us-east-1
stack: hello-sansan-dev
api keys:
  None
endpoints:
  None
functions:
  hello: hello-sansan-dev-hello

lambdaの関数のところにも表示されています。

環境変数も設定されています。

実行

こちらもcliで実行します。

$ sls invoke -f hello
16

件数が取得できました。

おわりに

今回はlambdaからSansanOpenAPIを利用して名刺情報をゲットしてみました!
lambdaはサーバーのこと気にせずに処理だけ書けば良く、serverlessはcliでごにょごにょできるし、とても便利です!
sitateruではlambdaを使って、SansanとHubSpotの同期を自動化しています。
どこかのタイミング第3回としてserverless-offlineを使用したlambdaの開発についても書こうと思います。

2018年11月22日木曜日

AWSLambdaとServerlessを使ってみる[第1回]

11月 22, 2018

こんにちは、シタテルエンジニアの工です!
AWS Lambdaを触る機会がありましたので、ServerlessFrameworkと一緒にいじいじしてみました!
シリーズで、
Serverlessをインストール
AWSLambdaでSansanの名刺データを取得してみる
serverless-offlineでAWSLambdaをローカルで実行
なんかを書いていこうと思います!

さらっとAWSLamdaとServerlessFrameworkについて

AWS Lambdaとは


AWS Lambda とは - AWS Lambda

AWS Lambda はサーバーをプロビジョニングしたり管理しなくてもコードを実行できるコンピューティングサービスです。

つまり、流行りのサーバーレスてやつで、サーバーを準備しなくてよいので、ちょっとした処理の実行など大変助かります。
しかも、LambdaはNode.js (JavaScript)、Python、Java (Java 8 互換)、C# (.NET Core)、 Goに対応しています!
様々な言語に対応しているので学習コストもかからないのがいいですね。

シタテルでは、HubSpotとSansanのデータ同期や、SlackCommandでリリースPRを作るなどで使っています。

Serverlessとは


Serverless Framework

The Serverless Framework is an open-source CLI for building and deploying serverless applications.

つまり、サーバーレスアプリケーションの開発を手助けをしてくれるやつです!
AWS Lambda単体で開発してみるとわかるのですが、ローカルでの開発やビルド、デバッグやらが面倒です。
このServerless Frameworkを使えばそのあたりのもやもやを解消してくれます!

作ってみる

Serverless Framework - AWS Lambda Guide - Introduction こちらがAWS用のServerlessFramework公式ドキュメントです。 基本的にこちらの内容に沿って進めていきます、

今回は、Sansanの名刺データを取得してみます。

まずはServerlessFrameworkをインストール

$ npm install -g serverless
$ serverless -v
1.33.2

正しくバージョンが表示されていたら、インストール完了です!

Serviceを作る

Serviceはプロジェクトのようなもの。
今回は、nodejsで作っていきますので、aws-nodejsを指定。
その他の言語を使いたい方はこちらを参考に。

$ serverless create --template aws-nodejs --path hello-sansan

実行すると

Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/Users/mogura/work/sitateru/lambda/hello-sansan"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.33.2
 -------'

Serverless: Successfully generated boilerplate for template: "aws-nodejs"

このような構成で、Serviceができました!

hello-sansan
   ├── handler.js
   └── serverless.yml

次は、実際に処理を書いていきます。
が、長くなりそうなので今回はここまでに。

おわりに

今回は、ServerlessFrameworkでserviceを作るところまでをやってみました。
次回は、実際にAWSLamdaでSansanから名刺データを取得するとことまでをやっていきます! 🚀

2018年11月14日水曜日

リリース作業を少し楽にした開発(Slack+Lambda+Golang)

11月 14, 2018

こんにちは、シタテルの鶴巻です。

devops&インフラ担当です。

シタテルのプロダクトのリリース作業を少し楽にするために、
Slack+Lambda+Golangを用いて開発した話をします。

リリースの流れ

シタテルでは、GitフローやGitHubフローを採用しています。

また、本番環境へのデプロイは、以下の流れで実施しています。

  1. developブランチからreleaseブランチを作成
  2. ステージング環境でreleaseブランチをデプロイ&動作確認
  3. 本番環境にデプロイ

ちなみに、1.でreleaseブランチを作成すると、CircleCIによって2.のステージング環境へのデプロイは自動で行われます。

地味に面倒なリリース作業

ステージング環境へのデプロイは自動化されているとはいえ、小さな手作業が合間に発生し、地味に面倒でした。

具体的には以下のような作業です。

  • developブランチからreleaseブランチの作成
    • ローカルPCでdevelopブランチを最新の状態にpullして、releaseブランチ作成してGitHubにpush
  • releaseブランチのプルリクエスト作成
    • GitHubのUIをポチポチ
  • リリースタグの作成
    • 前回のリリース以降でマージされたプルリクエストを見て、リリース内容を記述

手作業はSlackからコマンドを叩くだけにしました

Slackから以下のコマンドを叩くだけで、地味に面倒くさかった作業を自動で行うようにしました。

/release <repository> <release branch>

実際には、以下の内容を実施するGolangプログラムをLambdaで実行しています。

  • 対象のリポジトリをクローンし、developブランチからreleaseブランチを作成し、GitHubにpush
  • releaseブランチのプルリクエストを作成
  • 前回のリリース以降にマージされたプルリクエストのタイトルのリストを記述したリリースタグのドラフトを作成

構成

Slack -> API Gateway -> Lambda01(同期) -> Lambda02(非同期) -> GitHub
  1. Slackからコマンドを叩くと、Lambda01にリクエストを送信します。
  2. Lambda01は、Lambda02に対象レポジトリとブランチ名を付与してリクエストを送信します。
  3. Lambda02で作業を実行します。

Lambdaを2つ使用している理由

Slackはリクエスト送信後3秒でタイムアウトするためです。

実行したいプログラムは3秒以上かかるため、実際の作業は非同期で実施する必要がありました。

そのため、Lambda01はLambda02に処理を投げて、Slackに200を返し、実際の処理はLambda02で実施します。

Lambda01はLambda02を非同期実行で呼び出すので、リクエストをキューに入れた後は、Lambda01は関数を終了することができます。

Lambdaの呼び出しタイプ(同期・非同期)

Lambdaは、呼び出しタイプ(InvocationType)を指定することで、同期実行や非同期実行を選択することができます。

例:InvocationTypeで"Event"を指定することで、非同期実行でLambdaを呼び出せます。

input := &lambda.InvokeInput{
FunctionName: aws.String("xxxx"),
Payload: jsonBytes,
InvocationType: aws.String("Event"),
}

※同期実行は"RequestResponse"を指定します

今回使用したGitHub操作のためのGoライブラリ

その他ハマったポイント

  • APIGatewayの統合リクエストのマッピングテンプレートを使いこなせず。デバッグのやり方もわからず、使うのを諦めました。

まとめ

  • 少しの手間が自動化されるだけで、すごく楽になります。これからももっとやっていきたいです。
  • GitHub操作のライブラリはとても便利でした。
  • シタテルのサービスはRails + vue.jsが主ですが、自分の好きなGo言語を使えたので楽しかったです。

参考

slack slash-command

Lambda 呼び出しタイプ