【続編】Spotify APIを使ってLINEBotであなたにおすすめプレイリストを全自動で作ってもらう

昨日書いた以下記事。
<TABLE ALIGN=CENTER><TR><TD WIDTH=400px>
 <A HREF="http://qiita.com/momochan/items/459c95d075f12c6e6b77" TARGET="_blank"><STRONG>Spotify APIを使ってLINEBotであなたにおすすめプレイリストを全自動で作ってもらう - Qiita</STRONG></A>
 <A HREF="http://b.hatena.ne.jp/entry/http://qiita.com/momochan/items/459c95d075f12c6e6b77" TARGET="_blank">
 <IMG BORDER="0" SRC="http://b.hatena.ne.jp/entry/image/http://qiita.com/momochan/items/459c95d075f12c6e6b77" BORDER="0" ALT="" /></a>
 <BR>
 Spotify APIを使ってLINEBotであなたにおすすめプレイリストを全自動で作ってもらう - Qiita... 
 </TD>
 <TD WIDTH=150px>
 <IMG STYLE="float:left;margin-right:.5em;" SRC="http://capture.heartrails.com/120x120/cool?http://qiita.com/momochan/items/459c95d075f12c6e6b77" ALT="" WIDTH="120" HEIGHT="120" />
 </TD></TR>
</TABLE>

とにかくSpotify APIを利用することに注力していたため全くレスポンスなどを考えていなかった。
昨日も書いたがとにかく素早くレスポンスを返すことを目指して、しかもPHPでできるのかわからなかったけど、とりあえず非同期で処理させることができたので記載する。


# キーワード

- 非同期
- Que
- SQS
- Supervisor

# フローチャート
![Flowchart.png](https://qiita-image-store.s3.amazonaws.com/0/120983/f621bf22-3a7c-f3df-7551-334563cec713.png)

# メッセージをキューにためる（送信側）
今回サーバにはAWSを利用していたので、いろいろ調べたところ、非同期処理にはSQSを利用している情報が多かった。
またSQSを利用するときにはSNSを前に噛ますといいよと言う事で調べてみた。

PHPでもaws-sdkを利用すれば随分簡単に利用することができた。

```php:front.php
require __DIR__."/vendor/autoload.php";
use Aws\Sns\SnsClient;

// object to array
$data = messageEventToJson($events);

// push SNS -> SQS
try{
    $sns = SnsClient::factory(array(
      'key'    => '{YOUR_KEY}',
      'secret' => '{YOUR_SECRET}',
      'region' => 'ap-northeast-1'
    ));
    $response = $sns->publish(array(
        'TopicArn' => '{YOUR_ARN}',
        'Message' => $data
    ));

}catch (Exception $e){
    //
    getLog($e->getMessage());
}

//
function messageEventToJson($events) {
  $eventArray = array();
  foreach($events as $event) {
    if($event instanceof TextMessage) {
      array_push($eventArray, array(
        'type' => $event->getMessageType(),
        'timestamp' => $event->getTimestamp(),
        'replyToken' => $event->getReplyToken(),
        'userId' => $event->getUserId(),
        'text' => $event->getText()
      ));
    }
    else if($event instanceof PostbackEvent) {
      array_push($eventArray, array(
        'type' => $event->getType(),
        'timestamp' => $event->getTimestamp(),
        'replyToken' => $event->getReplyToken(),
        'userId' => $event->getUserId(),
        'postBackData' => $event->getPostbackData()
      ));
    }
  }

  return json_encode($eventArray);
}

```
下の汚いコードはObjectをJson化できなかったので仕方なくこうやってみたが、たぶん間違っているんだろうと思う。ほんとはObjectそのままをシリアライズしてSQSのメッセージに放り込みたかった。

以上だ。とても簡単。AWS最高。

# 非同期でキューを取得（受信側）
こちらはSQSから直接取り出す。
非同期については全く知識がなかったのでいろいろ調べた。PHPじゃだめだ、Node.jsだ！Rubyだ！などの情報があって回り道をしたが、結局挫折してPHPでやってみた。
このソースは全く自信がないので真似しないほうがいいです。自分で調べてください。

```php:woker.php
require __DIR__."/vendor/autoload.php";

use Aws\Sqs\SqsClient;

$sqs = SqsClient::factory(array(
      'key'    => '{YOUR_KEY}',
      'secret' => '{YOUR_SECRET}',
    'region'    => 'ap-northeast-1',
    'version' => 'latest',
));

$queueurl = $sqs->getQueueUrl(array(
    'QueueName' => '{YOUR_QUE_NAME}',
));


//メッセージを待機します
while(true){
  try {
    $result = $sqs->receiveMessage(array(
        'QueueUrl' => $queueurl['QueueUrl'],
    ));
    //
    if ($result['Messages'] == null) {
      sleep(1);
    }
    else {
        // Exec Something! # ここにSpotify連携とLINEへの返信処理を記述した


        // status ok is delete sqs message
        if($response->isSucceeded()) {
          try {
            $sqs->deleteMessage(array(
                'QueueUrl' => $queueurl['QueueUrl'],
                'ReceiptHandle' => $receiptHandle
            ));
          }
          catch(Exception $e) {
            echo $e->getMessage();
          }
        }
        else {
          // under construction
        }

      }

    }
  }
  catch(Exception $e) {
    echo $e->getMessage();
  }
}
exit(0);

```

```bash
$ php worker.php
```
なんと想定通りにうごいたよ！おかん！！
といってもここで半日ほど躓いたのは内緒の方向で。
非同期はPythonやNode.jsを使ったほうが良いかもしれないとは思った。勉強しなきゃ。

# 受信のプロセス化（デーモン化）
さて、うまくいったのはいいが、黒い画面を一日中立ちあげて眺めるわけにはいかない。
普通にinit.dとかに登録すればよいの？と思ったけれども、どうもSupervisorってのを使うとうまくいくらしい。
このあたりは全くわからないのでこちらの記事を参考にしてもらったほうが良い。
<TABLE ALIGN=CENTER><TR><TD WIDTH=400px>
 <A HREF="http://qiita.com/zaru/items/1b58210f604de0219773" TARGET="_blank"><STRONG>CakePHPでSQSを使って非同期にメール送信し、送信プロセスの監視を行う - Qiita</STRONG></A>
 <A HREF="http://b.hatena.ne.jp/entry/http://qiita.com/zaru/items/1b58210f604de0219773" TARGET="_blank">
 <IMG BORDER="0" SRC="http://b.hatena.ne.jp/entry/image/http://qiita.com/zaru/items/1b58210f604de0219773" BORDER="0" ALT="" /></a>
 <BR>
 CakePHPでSQSを使って非同期にメール送信し、送信プロセスの監視を行う - Qiita... 
 </TD>
 <TD WIDTH=150px>
 <IMG STYLE="float:left;margin-right:.5em;" SRC="http://capture.heartrails.com/120x120/cool?http://qiita.com/zaru/items/1b58210f604de0219773" ALT="" WIDTH="120" HEIGHT="120" />
 </TD></TR>
</TABLE>

参考にさせてもらってどうやらうまくいった。ビバSupervisor。勉強しなきゃ。

# 完成品
昨日と変化なし。
![Screenshot_2017-01-12-18-49-31-730_jp.naver.line.android.png](https://qiita-image-store.s3.amazonaws.com/0/120983/35ab769a-ce11-7721-99a4-7bad18aac5a4.png)


プレイリストを作るところは処理が多いのでレスポンスが遅い。
ただし非同期なので待ってたらたぶん返ってくるはず。

バックグラウンドは大きく変わったので記事にした。
あと、まだ工事中の部分もあるけれども晒してみる。

知らないうちにサービスやめてるかもだけど、その時はそっと友達外してください。

コメントにアドバイス頂けると非常にうれしいです。