Heroku 上の Django アプリで django_session が溢れた

ある日 HHTQA が 500 を返して動かなくなってた.

$ heroku logs

の末尾にあやしいメッセージが.

OperationalError: (1142, "INSERT command denied to user 'user'@'hostname' for table 'django_session'")

MySQL の権限が変わるわけがない (ClearDB という add-on なので, ユーザとかは俺はいじれない) し, MySQLWorkbench では同じユーザで見れているので, 権限が根本原因ではない.

MySQLWorkbench で色々見てみると django_session というテーブルが肥大化している. テーブル名や expire_date というカラム名から, 明らかに不要なデータが溜まっている.

SELECT count(*) FROM django_session; -- 15677

このテーブル名で検索すると https://docs.djangoproject.com/en/dev/topics/http/sessions/?from=olddocs/#clearing-the-session-table という情報が見付かり, 手作業で削除することもできるそうだ.

heroku コマンド使って, Heroku 上の環境で削除操作を行った.

$ heroku run find / -name django-admin.py
Running find / -name django-admin.py attached to terminal... up, run.1
find: `/proc/tty/driver': Permission denied
find: `/proc/1/task/1/fd': Permission denied
find: `/proc/1/task/1/fdinfo': Permission denied
find: `/proc/1/fd': Permission denied
find: `/proc/1/fdinfo': Permission denied
find: `/lost+found': Permission denied
find: `/etc/ssl/private': Permission denied
/app/.heroku/venv/bin/django-admin.py
/app/.heroku/venv/lib/python2.7/site-packages/django/bin/django-admin.py

$ heroku run .heroku/venv/bin/django-admin.py cleanup
DJANGO_SETTINGS_MODULE が無いと怒られるので設定.

あくまでモジュール名. ファイル名ではないので注意.
$ heroku config:add DJANGO_SETTINGS_MODULE=settings
$ heroku run ls '$DJANGO_SETTINGS_MODULE'
確認
$ heroku run .heroku/venv/bin/django-admin.py cleanup
SELECT count(*) FROM django_session; -- 1933

予想通り django_session テーブルが小さくなったので, Heroku アプリを再起動.

$ heroku restart
$ heroku logs

まだ何かエラーが出る. 以下 heroku logs の結果.

2012-07-14T12:52:29+00:00 heroku[web.1]: Starting process with command `python manage.py run_gunicorn 0.0.0.0:33646`
2012-07-14T12:52:30+00:00 app[web.1]: Unknown command: 'run_gunicorn'
2012-07-14T12:52:30+00:00 app[web.1 ...

Heroku の動作変更? Django の DATABASES 設定でコケた

以前 この記事 で書きましたが, Heroku の上で OSQA という Django アプリを動かしました.

最近また Heroku に静的ファイルを追加するため, git レポジトリにファイルを追加し, Heroku に再デプロイ (git push) しました.

これでアプリが再起動され, 無事動くはずだったのですが, Internal Server Error が出てしまいほとほと困りました.

heroku logs で見てみると不可解なことに, 使ってないはずの PostgreSQL に接続しようとしてエラーになっています.

2012-06-10T04:04:13+00:00 app[web.1]: /app/.heroku/venv/lib/python2.7/site-packages/gunicorn/glogging.py TIME: 2012-06-10 13:04:13,215 MSG: glogging.py:exception:143 Error handling request
2012-06-10T04:04:13+00:00 app[web.1]:   File "/app/.heroku/venv/lib/python2.7/site-packages/gunicorn/workers/sync.py", line 99, in handle_request
2012-06-10T04:04:13+00:00 app[web.1]:     respiter = self.wsgi(environ, resp.start_response)
2012-06-10T04:04:13+00:00 app[web.1]:   File "/app/.heroku/venv/lib/python2.7/site-packages/django/contrib/staticfiles/handlers.py", line 68, in __call__
2012-06-10T04:04:13+00:00 app[web.1]:     return self.application(environ, start_response)
2012-06-10T04:04:13+00:00 app[web.1]:   File "/app/.heroku/venv/lib/python2.7/site-packages/django/core/handlers/wsgi.py", line 250, in __call__
2012-06-10T04:04:13+00:00 app[web.1]:   File "/app/.heroku/venv/lib/python2.7/site-packages/django/core/handlers/base.py", line 45, in load_middleware
2012-06-10T04:04:13+00:00 app[web.1]:     self.load_middleware()
2012-06-10T04:04:13+00:00 app[web.1]:     mod = import_module(mw_module)
2012-06-10T04:04:13+00:00 app[web ...

OSQA on Heroku

processes

$ mkdir osqa
$ cd osqa

$ brew install mysql
$ unset TMPDIR
$ mysql_install_db --verbose --user=`whoami` --basedir="$(brew --prefix mysql)" --datadir=/usr/local/var/mysql --tmpdir=/tmp
$ mysql.server start
$ mysql -uroot
mysql> CREATE USER 'osqa'@'localhost' IDENTIFIED BY '***';
mysql> CREATE DATABASE osqa DEFAULT CHARACTER SET UTF8 COLLATE utf8_general_ci;
mysql> GRANT ALL ON osqa.* to 'osqa'@'localhost';

$ svn co http://svn.osqa.net/svnroot/osqa/trunk .
$ virtualenv venv --distribute
$ source ./venv/bin/activate
$ pip install South django==1.3 django-debug-toolbar mysql-python markdown html5lib python-openid gunicorn
$ cp settings_local.py.dist settings_local.py

$ emacs settings_local.py
import os.path
import os
import sys
import urlparse
...
↓消す
DATABASES = {
...
↓heroku 用の DB 設定を追加
# Register database schemes in URLs.
urlparse.uses_netloc.append('mysql')

try:

    # Check to make sure DATABASES is set in settings.py file.
    # If not default to {}

    if 'DATABASES' not in locals():
        DATABASES = {}

    if 'CLEARDB_DATABASE_URL' in os.environ:
        url = urlparse.urlparse(os.environ['CLEARDB_DATABASE_URL'])

        # Ensure default database exists.
        DATABASES['default'] = DATABASES.get('default', {})

        # Update with environment configuration.
        DATABASES['default'].update({
            'NAME': url.path[1:].split('?')[0],
            'USER': url.username,
            'PASSWORD': url.password,
            'HOST': url.hostname,
            'PORT': url.port,
        })
        if url.scheme == 'postgres':
            DATABASES['default']['ENGINE'] = 'django.db.backends.postgresql_psycopg2'

        if url.scheme == 'mysql':
            DATABASES['default']['ENGINE'] = 'django.db ...

Licenses