Herokuに「ホームTL上の友利奈緒ツイートをエタフォするやつ」を334秒ぐらいでデプロイするまでの流れ

# 対象読者

- Composer名前だけは知ってるっていう人
- Herokuに登録したけど使い方分からない人<br />**(特にバックグラウンドワーカーを使ったことがない人)**
- TwitterAPI触りたい人
- 友利奈緒好きな人
- 友利奈緒

<a href="http://charlotte-anime.jp/" target="_blank" title="TVアニメ「Charlotte(シャーロット)」公式サイト" ><img src="http://charlotte-anime.jp/special/img/400x80.jpg" alt="TVアニメ「Charlotte(シャーロット)」公式サイト" width="400" height="80" /></a>

# 下準備

以下のコマンドラインユーティリティをインストールしておいてください。

## 必須

- [git](https://git-scm.com/)
- [php](http://www.php.net/)
- [Composer](https://getcomposer.org/)
- [Heroku Toolbelt](https://toolbelt.heroku.com/)

## 任意

- [mpyw/twhelp](https://github.com/mpyw/twhelp)<br />→ Twitterのアクセストークンの取得を補助

# ローカルでの作業

## ディレクトリを作成

```shell-session
example@localhost:~$ mkdir tomori-nao-love
example@localhost:~$ cd tomori-nao-love
example@localhost:~/tomori-nao-love$
```

## `.git`の生成

- gitディレクトリとして初期化しておかなければHerokuに対して一切の操作が出来ません。

```shell-session
example@localhost:~/tomori-nao-love$ git init
Initialized empty Git repository in ~/tomori-nao-love/.git/
example@localhost:~/tomori-nao-love$
```

## `composer.json`の生成

- 今回はTwistOAuthを利用するのでここで記入しておきます。
- もし利用するライブラリが無くても**`composer.json`が無いとHerokuにPHPアプリとして認識されません**。<br />[（詳細: HerokuでPHPを使うときに気を付けるところ）](http://qiita.com/hiro_y/items/bc631a27c9701f81a4f9#start)
- 最後で`vendor`を`.gitignore`に追記しておかないとライブラリまでプロジェクトのバージョン管理に飲み込まれてしまいます。

```shell-session
example@localhost:~/tomori-nao-love$ composer init

 ------------------------------------------
  Welcome to the Composer config generator  
 ------------------------------------------                                          


This command will guide you through creating your composer.json config.

Package name (<vendor>/<name>) [example/tomori-nao-love]: 
Description []: 
Author [example <example@example.com>]: 
Minimum Stability []: dev
Package Type []: project
License []: 

Define your dependencies.

Would you like to define your dependencies (require) interactively [yes]? yes
Search for a package: mpyw

Found 6 packages matching mpyw

   [0] mpyw/twistoauth
   [1] mpyw/comphar
   [2] mpyw/twhelp
   [3] mpyw/base-utf8
   [4] mpyw/twittertext
   [5] mpyw/php-type-trainer

Enter package # to add, or the complete package name if it is not listed: 0
Enter the version constraint to require (or leave blank to use the latest version): @dev
Search for a package: 
Would you like to define your dev dependencies (require-dev) interactively [yes]? no

{
    "name": "example/tomori-nao-love",
    "type": "project",
    "require": {
        "mpyw/twistoauth": "@dev"
    },
    "authors": [
        {
            "name": "example",
            "email": "example@example.com"
        }
    ],
    "minimum-stability": "dev"
}

Do you confirm generation [yes]? yes
Would you like the vendor directory added to your .gitignore [yes]? yes
example@localhost:~/tomori-nao-love$
```

## 依存性解決と`composer.lock`の生成

- ローカルでデバッグする必要が無ければ`vendor`は不要ですが、`composer.lock`は作っておかないとHerokuに怒られます。

```shell-session
example@localhost:~/tomori-nao-love$ composer install
Loading composer repositories with package information
Installing dependencies (including require-dev)
  - Installing mpyw/twistoauth (dev-master e625673)
    Cloning e625673d95c621a353ae5b2f57db4faf8b72222c

Writing lock file
Generating autoload files
example@localhost:~/tomori-nao-love$
```

## コードおよびそれを呼び出す`Procfile`を作成

- 適当なエディタで作成してください。

```php:run.php
<?php

require __DIR__ . '/vendor/autoload.php';

// twhelp --twist で生成したコードを貼り付け
$to = new \TwistOAuth(
    "XXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "XXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "XXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "XXXXXXXXXXXXXXXXXXXXXXXXXXX"
);

while (true) {
    try {
        $to->streaming('user', function ($status) use ($to) {
            switch (true) {
                case !isset($status->text):
                case strpos($status->text, '友利奈緒') === false:
                    return;
            }
            try {
                $to->post('favorites/create', array('id' => $status->id_str));
            } catch (\TwistException $e) { }
        });
    } catch (\TwistException $e) {
        sleep(60); // 切断されたら60秒眠って再接続
    }
}
```

```ruby:Procfile
worker: php run.php
```

## コミット

```shell-session
example@localhost:~/tomori-nao-love$ git add -A
example@localhost:~/tomori-nao-love$ git commit -m 友利奈緒
[master (root-commit) c4442ac] 友利奈緒
 5 files changed, 124 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 Procfile
 create mode 100644 composer.json
 create mode 100644 composer.lock
 create mode 100644 run.php
example@localhost:~/tomori-nao-love$
```

# Herokuに対する作業

## ログイン

- ターミナルを起動して最初の1回はログインが必要になります。

```shell-session
example@localhost:~/tomori-nao-love$ heroku login
Enter your Heroku credentials.
Email: example@example.com
Password (typing will be hidden): 
Authentication successful.
example@localhost:~/tomori-nao-love$
```

## アプリ作成

- `create`の後に名前を指定しない場合は自動的に重複しない名前がHerokuによって決定されます。

```shell-session
example@localhost:~/tomori-nao-love$ heroku create
Creating XXXXXXXXXXXXXXXXX... done, stack is cedar-14
https://XXXXXXXXXXXXXXXXX.herokuapp.com/ | https://git.heroku.com/XXXXXXXXXXXXXXXXX.git
Git remote heroku added
example@localhost:~/tomori-nao-love$
```

## プッシュ

- Heroku側のリポジトリにプッシュするとWebサービスとしてデプロイしたことになります。但し今回はWebサービスではなくバックグラウンドワーカーとして利用するので、この後設定を変更します。**(先に一度プッシュしておかないと変更できない)**

```shell-session
example@localhost:~/tomori-nao-love$ git push heroku master
Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 1.82 KiB | 0 bytes/s, done.
Total 7 (delta 0), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote: 
remote: -----> PHP app detected
remote: 
remote:  !     WARNING: Your 'composer.json' contains a non-'stable' setting
remote:        for 'minimum-stability'. This may cause the installation of
remote:        unstable versions of runtimes and extensions during this deploy.
remote:        It is recommended that you always use stability flags instead,
remote:        even if you have 'prefer-stable' enabled. For more information,
remote:        see https://getcomposer.org/doc/01-basic-usage.md#stability
remote: 
remote: -----> No runtime required in 'composer.json', defaulting to PHP 7.0.0RC1.
remote: -----> Installing system packages...
remote:        - PHP 7.0.0RC1
remote:        - Apache 2.4.10
remote:        - Nginx 1.6.0
remote: -----> Installing PHP extensions...
remote:        - zend-opcache (automatic; bundled)
remote: -----> Installing dependencies...
remote:        Composer version 1.0.0-alpha10 2015-04-14 21:18:51
remote:        Loading composer repositories with package information
remote:        Installing dependencies from lock file
remote:          - Installing mpyw/twistoauth (dev-master e625673)
remote:            Downloading: 100%
remote:        
remote:        Generating optimized autoload files
remote: -----> Preparing runtime environment...
remote: -----> Discovering process types
remote:        Procfile declares types -> worker
remote:        Default types for PHP   -> web
remote: 
remote: -----> Compressing... done, 81.7MB
remote: -----> Launching... done, v3
remote:        https://XXXXXXXXXXXXXXXXX.herokuapp.com/ deployed to Heroku
remote: 
remote: Verifying deploy.... done.
To https://git.heroku.com/XXXXXXXXXXXXXXXXX.git
 * [new branch]      master -> master
example@localhost:~/tomori-nao-love$ 
```

## バックグラウンドワーカーに変更

- Herokuは無料では1プロセスしか使えないので、まず`web`を無効にしてから`worker`を有効にします。

```shell-session
example@localhost:~/tomori-nao-love$ heroku scale web=0
Scaling dynos... done, now running web at 0:Free.
example@localhost:~/tomori-nao-love$ heroku scale worker=1
Scaling dynos... done, now running worker at 1:Free.
```

# 確認

- Twitterで「友利奈緒かわいい」ってツイートして自分にふぁぼられてたらOK
- Herokuには**「無料ワーカーくんは人間みたいに1日6時間眠ってね」**という決まりがあるのでたまに動かなくなってても文句言わない
- 言っておくけど自動ふぁぼ行為自体は僕嫌いだからね！友利奈緒ちゃんだから許されるんだよね！

<ins>重要な追記</ins><br />どうやら勝手に6時間眠らせてくれるのではなく超過して運用し続けたときに「課金はよ」ってメールが来るらしいです。[ここ](http://kayakuguri.github.io/blog/2015/02/05/one-off-dyno-excute-php/)によると無料のスケジューラはあるみたいなんですが、クレカの登録は必要なようで…クレカを持たない学生さんにとってはなかなか厳しい運営になりそうです。

# まとめ

![スクリーンショット 2015-08-30 21.17.38.png](https://qiita-image-store.s3.amazonaws.com/0/25060/98ff8a19-417f-9470-6bb1-35d82ff77e09.png)
![スクリーンショット 2015-08-30 21.19.55.png](https://qiita-image-store.s3.amazonaws.com/0/25060/e2b8adb8-9fe2-177c-830a-c8318c91f626.png)
![スクリーンショット 2015-08-30 21.20.11.png](https://qiita-image-store.s3.amazonaws.com/0/25060/67a6ddf2-5a17-dd2a-6548-f2bc230e661a.png)
![スクリーンショット 2015-08-30 21.20.28.png](https://qiita-image-store.s3.amazonaws.com/0/25060/022d89ec-a1ef-dac4-f26f-6a3fd8c85134.png)
![スクリーンショット 2015-08-30 21.20.45.png](https://qiita-image-store.s3.amazonaws.com/0/25060/ea4fe4b6-81d8-f524-67ed-5a21493f07fd.png)
![スクリーンショット 2015-08-30 21.20.59.png](https://qiita-image-store.s3.amazonaws.com/0/25060/493c111d-6f38-dcf9-62ca-59711299f61b.png)
![スクリーンショット 2015-08-30 21.21.24.png](https://qiita-image-store.s3.amazonaws.com/0/25060/035cbf9e-683f-903b-b8ed-b4ce9c12baec.png)
![スクリーンショット 2015-08-30 21.21.35.png](https://qiita-image-store.s3.amazonaws.com/0/25060/072a13a1-02af-c585-f747-56d414f43116.png)
![スクリーンショット 2015-08-30 21.21.49.png](https://qiita-image-store.s3.amazonaws.com/0/25060/75953597-cef1-3c5f-aa43-4ba087f2347e.png)
![スクリーンショット 2015-08-30 21.22.32.png](https://qiita-image-store.s3.amazonaws.com/0/25060/49a30545-02b5-958f-028d-a89aa01d6f12.png)
![スクリーンショット 2015-08-30 21.22.42.png](https://qiita-image-store.s3.amazonaws.com/0/25060/9749557c-7d76-6bd8-f645-14d3f6ea006f.png)

<blockquote class="twitter-tweet" lang="ja"><p lang="ja" dir="ltr">まあなんというかHerokuでバックグラウンドアプリ作ったことなかったので試してみたかっただけ感はある</p>&mdash; 進捗 (@mpyw) <a href="https://twitter.com/mpyw/status/637938441443897344">2015, 8月 30</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>