[日本語Alexa] Alexa-SDK Ver2 永続化情報の保存先をS3にしてみた 〜PersistenceAdapterの置き換え〜

Alexa SDK V2では、永続化情報を簡単に扱うためにAttributesManagerというオブジェクトが提供されています。 AttributesManagerは、セッションを跨いだ永続化データは、デフォルトでDynamoDBに保存されるようになっています。 今回は、「ASK SDK S3 Persistence Adapterパッケージ」を使用して、保存先をS3にする手順を確認してみました。
2018.10.20

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

1 はじめに

Alexa SDK V2では、永続化情報を簡単に扱うためにAttributesManagerというオブジェクトが提供されています。

参考:[日本語Alexa] Alexa-SDK Ver2(その4) スキル属性

AttributesManagerでは、セッションを跨いだ永続化データは、デフォルトでDynamoDBに保存されるようになっています。

今回は、ask-sdk-s3-persistence-adapter(ASK SDK S3 Persistence Adapterパッケージ)を使用して、保存先をS3にする手順を確認してみました。


https://github.com/alexa/alexa-skills-kit-sdk-for-nodejs/tree/2.0.x/ask-sdk-s3-persistence-adapter

注意:Amazon S3では、既存オブジェクトの更新は、結果整合性となるため、保存したデータのリアルタイムな整合性が必要な場合には、従来のDynamoDBの利用が必要です。

2 インストール

インストールは下記の要領となります。

npm install --save ask-sdk-s3-persistence-adapter

ASK SDK S3 Persistence Adapterは、単体では動作できないためask-sdk-core若しくは、ask-sdkが必要です。

コードでインポートする要領は、次のようになります。

TypeScript

import * as Adapter from 'ask-sdk-s3-persistence-adapter';

JavaScript

const Adapter = require('ask-sdk-s3-persistence-adapter');

3 使ってみた

TypeScriptで使ってみたコードは、下記のとおりです。

import * as Alexa from 'ask-sdk';
import { RequestEnvelope } from 'ask-sdk-model';
import * as Adapter from 'ask-sdk-s3-persistence-adapter';

let skill: Alexa.Skill;
exports.handler = async function (event: RequestEnvelope, context: any) {

    const s3PersistenceAdapter = new Adapter.S3PersistenceAdapter({  
        bucketName: 'alexa-s3-persistence-adapter'
    })

    if (!skill) {
        skill = Alexa.SkillBuilders.custom()
            .addRequestHandlers(TestHandler)
            .withPersistenceAdapter(s3PersistenceAdapter)  
            .create();
    }
    return skill.invoke(event, context);
}

const TestHandler: Alexa.RequestHandler = {
    canHandle(_h: Alexa.HandlerInput) {
        return true;
    },
    async handle(h: Alexa.HandlerInput) {
        // 永続化情報の取得
        let attributes = await h.attributesManager.getPersistentAttributes()
        if(!attributes.counter){ 
            attributes.counter = 0; 
        }
        attributes.counter++;
        // 永続化情報の保存
        h.attributesManager.setPersistentAttributes(attributes);
        await h.attributesManager.savePersistentAttributes();

        return h.responseBuilder
            .speak('カウンターは' + attributes.counter + 'です')
            .getResponse();
    }
}

SkillBuilderで.withPersistenceAdapterを使用して、永続化情報用のアダプタとして、S3PersistenceAdapterをセットしています。これで、デフォルトのDynamoDBを使用したDynamoDbPersistenceAdapterを置き換えたことになります。

アダプタを置き換えれば、AttributesManagerを使用したデータの保存場所は、S3となります。

ここで、少し注意が必要なのは、withAutoCreateTable(true) は、使えないため、バケットは、予め作成しておく必要があります。

4 Key名

S3PersistenceAdapterのコンストラクタを確認すると、ObjectKeyGeneratorが指定されていない場合、ObjectKeyGenerator.userIdで初期化されていることが確認できます。

ask-sdk-s3-persistence-adapter/lib/attributes/persistence/S3PersistenceAdapter.ts

export class S3PersistenceAdapter implements PersistenceAdapter {
    protected bucketName : string;
    protected s3Client : S3;
    protected objectKeyGenerator : ObjectKeyGenerator;
    protected pathPrefix : string;

    constructor(config : {
        bucketName : string,
        s3Client? : S3,
        objectKeyGenerator? : ObjectKeyGenerator,
        pathPrefix? : string,
    }) {
        this.bucketName = config.bucketName;
        this.s3Client = config.s3Client ? config.s3Client : new S3({apiVersion : 'latest'});
        this.objectKeyGenerator = config.objectKeyGenerator ? config.objectKeyGenerator : ObjectKeyGenerators.userId;
        this.pathPrefix = config.pathPrefix ? config.pathPrefix : '';
    }
・・・省略・・・

ObjectKeyGenerators.userIdは、DynamoDbPersistenceAdapterと同じように、AlexaからのリクエストからuserIdを抽出して利用しているのが分かります。

ask-sdk-s3-persistence-adapter/tst/attributes/persistence/ObjectKeyGenerators.spec.ts

export const ObjectKeyGenerators = {
    /**
     * Gets attributes id using user id.
     * @param {RequestEnvelope} requestEnvelope
     * @returns {string}
     */
    userId(requestEnvelope : RequestEnvelope) : string {
        if (!(requestEnvelope
              && requestEnvelope.context
              && requestEnvelope.context.System
              && requestEnvelope.context.System.user
              && requestEnvelope.context.System.user.userId)) {
            throw createAskSdkError(
                'PartitionKeyGenerators',
                'Cannot retrieve user id from request envelope!',
            );
        }

        return requestEnvelope.context.System.user.userId;
    },

この部分を置き換えることで、Key名を変更できるでしょう。要領としては、下記のブログで紹介した「プライマリーキーを変える」要領と同じです。

参考:[日本語Alexa] Alexa-SDK Ver2 DynamoDB利用時のTips 〜リージョンを指定したり、プライマリーキーを変えて、スキルで共通のデータを保存したり〜

5 最後に

今回は、Alexa SDK V2に提供されている、永続化情報の保存先をS3に変更する要領を確認してみました。このアダプターの置き換えを利用すると、DynamoDB,S3以外のリソースも、簡単に保存先に変更できることが分かります。

ほんと、このSDKの設計すごいと思います。勉強になります。