Amplify SNS Workshopをやってみた

GW期間中にAmplify SNS Workshopをやってみた。とても面白い内容だったが、ちょっとおかしな挙動をする部分もあった。

本ワークショップのゴール :: Amplify SNS Workshop

ここの図にある通り、AppSync / Cognito / Lambda / DynamoDB等々様々なAWSのサービスをAmplify CLIを使ってTwitterっぽいものを作るチュートリアル。最終的にはgithubにpushするとCIでE2Eテストが動いてその動画をAWSコンソールからダウンロードできる。すごい。 CognitoやLambdaは単体では使ったことがあるので、これ単体でもいろいろノウハウがあって動かすの大変なのに、うまくインテグレートされてるなあと感心した。

ボリュームとしては多くはない。ただデプロイするのに結構時間がかかるので、その間に別のこと始めちゃったりしてだらだらやっていたら3日くらいかかりました。

Timeline上のPostが重複する

Timelineを表示しながらPostすると、Postが重複してしまうという現象が発生した。

f:id:iakio:20200510152925p:plain

PostはLambdaによって

  1. PostTableにSaveされる
  2. 自分と自分のFollowerのTimelineに保存される

この2の処理が意図せず複数回呼び出されているようだ。ただし保存している内容は同じなので結果的には上書きされているだけなんだけど、クライアント側ではこれをsubscribeしてTimelineを表示しているため重複して表示してしまう。その後リロードするとTimelineを読み直すので重複は解消される。

f:id:iakio:20200510161005p:plain

CloudWatchでLambdaのログを見るとこのようになっていた。

2020-05-10T06:27:49.322Z d130970d-d15d-496c-9344-42c58f5c40ad    INFO    [ { followerId: 'iakio' },
  { followerId: 'iakio' },
  { followerId: 'iakio' },
  { followerId: 'iakio' } ]

followerに自分自身が複数入っている。しかしDynamoDBのFollowRelationshipには何も入っていない。どうもLambdaの中で何かが起きているようだ。

   const listFollowRelationshipsResult = await graphqlClient.query({
        query: gql(listFollowRelationships),
        fetchPolicy: 'network-only',
        variables: queryInput,
    });
    console.log(listFollowRelationshipsResult);
    const followers = listFollowRelationshipsResult.data.listFollowRelationships.items;
    console.log(followers);

    //post to timeline
    followers.push({
        followerId: post.owner,
    })
    const results = await Promise.all(followers.map((follower)=> createTimelineForAUser({follower: follower, post: post})));

Timeline機能: @function :: Amplify SNS Workshop

LabmdaやAppSyncについて詳しくないのだが、どうも

  • graphqlClient.query()の戻り値の中のfollwersにpushで破壊的変更をしたら、次にgraphqlClient.queryした時の結果に影響する?
  • しかもそれが次のLamdaの呼び出しにも影響している? graphqlClientがglobalスコープなんだけど、Lambdaでglobalスコープってどうなるんだっけ

という感じがしている。ちなみにpushをやめたら現象は発生しなくなった。

    const followersAndI = followers.concat({
        followerId: post.owner,
    });
    const results = await Promise.all(followersAndI.map((follower)=> createTimelineForAUser({follower: follower, post: post})));

Amplify SNS Workshop :: Amplify SNS Workshop