Herokuで「Allowed memory size of ○○ bytes exhausted」が出るのは必要なパッケージがインストールされていないからかも!


どうも、たかふみです。
個人で開発していたアプリケーションをHerokuへデプロイしたところ、色々エラーが生じました。エラーが起きたのはslackへの通知処理で、メッセージには「メモリーを使い果たしたよ!」という文字。slack通知ってそんなに重いのか...?と思いながら試行錯誤した記録です。

【目次】
・今回の問題
・原因
・解決方法
・解決に至るまでにやったこと
・まとめ
・参考サイト

■今回の問題

Herokuへデプロイしたらメモリーのエラーで動かなくなった

個人で開発していた書籍管理アプリケーションがひと段落ついたのでherokuにデプロイしたところ、貸し出し申請の処理でエラー画面に遷移してしまいました。

申請画面で申請ボタンをポチッとな。

「oh...」

Herokuでログを見るとばっちりエラーメッセージが出ていました。そのエラーメッセージがこちら。

2019-08-08T12:24:20.947169+00:00 app[web.1]: [08-Aug-2019 12:24:20 UTC] PHP Fatal error:  Allowed memory size of 134217728 bytes exhausted (tried to allocate 32768 bytes) in /app/vendor/symfony/debug/Exception/FatalErrorException.php on line 1
Google翻訳
> PHP致命的エラー:1行目の/app/vendor/symfony/debug/Exception/FatalErrorException.phpで134217728バイトのメモリサイズを使い果たしました(32768バイトを割り当てようとしました)。

「メモリを使い果たしているだと...!」

■原因

必要なパッケージが本番環境でインストールされてなかった

エラーが生じた貸し出し処理では、ユーザーから貸し出し申請があったときに管理者にslackで通知が届く仕様でした。Laravelのslack通知には、それ専用のパッケージが必要です。そのパッケージが本番環境ではインストールされていなかったためエラーが起きていたのです。

■解決方法

composer.jsonのrequireにlaravel/slack-notification-channel を追加&extraに laravel/duskを追加して、コマンドを実行。

composer.json
    "require": {
        "php": "^7.1.3",
        "fideloper/proxy": "^4.0",
        "laravel/framework": "5.8.*",
        "laravel/tinker": "^1.0",
        "laravel/slack-notification-channel": "^2.0" // 追加箇所
    }
composer.json
    "extra": {
        "laravel": {
            "dont-discover": [
                "laravel/dusk" // 追記
            ]
        }
    }

実行コマンド

heroku run composer update

■解決に至るまでにやったこと

1. Controller内のslack通知処理をコメントアウトする
2. Herokuの「Config Vars」にenvファイル内の値を追加
3. 参考サイトを見直し
4. 本番環境でcomposer updateを実行  
5. composer.jsonとcomposer.lockの内容を確認
6. heroku run composer update実行で成功

1. Controller内のslack通知処理をコメントアウトする

問題なく動作しました。このことから、slack通知処理で問題が生じていることが分かりました。

2. Herokuの「Config Vars」にenvファイル内の値を追加

slack通知処理ではenvから値を取得して使う処理をしていました。そこで、Herokuのマイページ > {{$ アプリケーション名 }} > SettingのConfig Varsへenvファイルで設定していた4つのパラメータを追加しました。

1. SLACK_USERNAME
2. SLACK_ICON
3. SLACK_CHANNEL
4. SLACK_URL

3. 参考サイトを見直し

それでも動かなかったので、改めてプログラムを見直すとともに、実装のときに参考にしたサイトを見返すことにしました。すると、composerでslack-notification-channelをインストールしていることが分かりました。「そういえば開発の時に、composer requireでインストールしたなぁ。」ということを思い出しました。ということは、本番環境でインストールすれば動くのでは...?

4.本番環境でcomposer updateを実行

herokuの本番環境にインストールするために下記コマンドを実行。

heroku run require composer slack-notification-channel

これで解決!だと思ったのですが、下記のエラーが表示されました。

> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi

In DuskServiceProvider.php line 43:

  It is unsafe to run Dusk in production.  

Script @php artisan package:discover --ansi handling the post-autoload-dump event returned with error code 1

Installation failed, reverting ./composer.json to its original content.
Google翻訳
> 本番環境でDuskを実行することは安全ではありません。

「本番でduskを実行しようとしているだと...!」

5. composer.jsonとcomposer.lockの内容を確認

ここでcomposer.jsonとcomposer.lockについて調べました。

composer.json : インストールしたいパッケージを記述する
composer.lock : インストールされたパッケージの情報が記述されている

composer.lock が存在する場合はcomposer.lockの内容が優先されることを知りました。ということは、既にduskが記述されたcomposer.lockを見ているからエラーが起きているのではないか?

そこで、composer.jsonに下記2点を追記。composer.lockから「laravel/dusk」を削除して再度デプロイしました。

⬇︎インストールするための追記。

composer.json
    "require": {
        "php": "^7.1.3",
        "fideloper/proxy": "^4.0",
        "laravel/framework": "5.8.*",
        "laravel/tinker": "^1.0",
        "laravel/slack-notification-channel": "^2.0" // 追記
    }

⬇︎本番環境でduskを実行しないようにするための追記。

composer.json
    "extra": {
        "laravel": {
            "dont-discover": [
                "laravel/dusk" // 追記
            ]
        }
    }

6. heroku run composer update実行で成功

Writing lock file
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi
Discovered Package: beyondcode/laravel-dump-server
Discovered Package: fideloper/proxy
Discovered Package: laravel/slack-notification-channel
Discovered Package: laravel/tinker
Discovered Package: nesbot/carbon
Discovered Package: nunomaduro/collision
Package manifest generated successfully.

「successfully キタァァァァァァァァァァァァァァァ!!」
「いや、まだガッツポーズは早い...。」

「ポチッ」

「おっ!!」

「通知キタァァァァァァァァァァァァァァァ!!(ガッツポーズ)」
勝ちました。

■まとめ requireでインストールしたものはcomposer.jsonに書いておく

今回はローカル環境では行ったことを本番環境で実行していなかったことが原因でした。開発でインストールしたものがちゃんと使えることが分かった時点でcomposer.jsonに書いておいた方が良いですね。今回のエラーは良い学びになりました。

みなさんもslack連携の際にはお気をつけくださいませ!それでは!

■参考サイト

【 slack通知で参考にしたサイト 】
Laravel 5.8 通知
https://readouble.com/laravel/5.8/ja/notifications.html

LaravelでFacadeを作ってSlackに通知してみた
https://qiita.com/freeneer/items/a78fb7e270b141c793b1

【 本番環境にslack-notification-channelをインストールするために参考にしたサイト 】
composer.json、composer.lockって何なの?という人向けのまとめ
https://qiita.com/masarufuruya/items/23131a465b7e9c8f3060

【 本番環境でdusk実行エラー解決で参考にしたサイト 】
Laravel環境をインポートしたときに”artisan package:discover handling the post-autoload-dump event returned with error code 1″エラーが出た時に確認したいこと
https://cpoint-lab.co.jp/article/201812/6788/

How to solve Exception It is unsafe to run Dusk in production in laravel 5.5?
https://stackoverflow.com/questions/49622200/how-to-solve-exception-it-is-unsafe-to-run-dusk-in-production-in-laravel-5-5