2013年1月26日土曜日

UbuntuへのCeleryのインストール

Ubuntu12.10にCeleryをインストール。
Djangoアプリのバックエンドのバッチ処理用に。
Cronでも十分だけど、今後を考えて。

pipでインストール。

sudo pip install celery django-celery
インストール中にネイティブライブラリのコンパイルにPython.hが無い、という
コンパイルエラーが出る場合、python-devをaptでインストールします。

sudo apt-get install python-dev
settings.pyは
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'django.contrib.humanize',
    'south',
+    'kombu.transport.django',
+    'djcelery',
    'myapp',
)


+#celery
+BROKER_URL = "django://" 
+import djcelery
+djcelery.setup_loader()
 
こんな感じで追加。

そしてmyapp/tasks.pyを作り、
from celery.task.schedules import crontab 
from celery.decorators import periodic_task

@periodic_task(run_every=crontab(hour="*", minute="*", day_of_week="*")) 
def test(*args, **kwargs):
    print "TEST!"
こんなふうに書く。

試す。

>python manage.py celery worker -B

死ぬ。こんな感じのが出る。
*** glibc detected *** /usr/bin/python: munmap_chunk(): invalid pointer: 0x00007f5b9ee73fd4 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f5b9fe10b96]
/usr/local/lib/python2.7/dist-packages/_billiard.so(+0x40db)[0x7f5b9eebd0db]

(中略)
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python2.7/dist-packages/billiard/forking.py", line 528, in main
    self = load(from_parent)
  File "/usr/lib/python2.7/pickle.py", line 1378, in load
    return Unpickler(file).load()
  File "/usr/lib/python2.7/pickle.py", line 858, in load
    dispatch[key](self)
  File "/usr/lib/python2.7/pickle.py", line 1133, in load_reduce
    value = func(*args)
  File "/usr/local/lib/python2.7/dist-packages/celery/app/utils.py", line 130, in _unpickle_app
    return pickler()(cls, *args)
  File "/usr/local/lib/python2.7/dist-packages/celery/app/utils.py", line 109, in __call__
    self.prepare(app, **kwargs)
  File "/usr/local/lib/python2.7/dist-packages/celery/app/utils.py", line 113, in prepare
    app.conf.update(kwargs['changes'])
  File "/usr/local/lib/python2.7/dist-packages/kombu/utils/__init__.py", line 293, in __get__
    value = obj.__dict__[self.__name__] = self.__get(obj)
  File "/usr/local/lib/python2.7/dist-packages/celery/app/base.py", line 473, in conf
    return self._get_config()
  File "/usr/local/lib/python2.7/dist-packages/celery/app/base.py", line 338, in _get_config
    s = Settings({}, [self.prepare_config(self.loader.conf),
  File "/usr/local/lib/python2.7/dist-packages/kombu/utils/__init__.py", line 293, in __get__
    value = obj.__dict__[self.__name__] = self.__get(obj)
  File "/usr/local/lib/python2.7/dist-packages/celery/app/base.py", line 485, in loader
    return get_loader_cls(self.loader_cls)(app=self)
  File "/usr/local/lib/python2.7/dist-packages/celery/loaders/__init__.py", line 23, in get_loader_cls
    return symbol_by_name(loader, LOADER_ALIASES)
  File "/usr/local/lib/python2.7/dist-packages/kombu/utils/__init__.py", line 80, in symbol_by_name
    module = imp(module_name, package=package, **kwargs)
  File "/usr/lib/python2.7/importlib/__init__.py", line 37, in import_module
    __import__(name)
  File "/usr/local/lib/python2.7/dist-packages/djcelery/loaders.py", line 15, in <module>
    from django import db
  File "/usr/local/lib/python2.7/dist-packages/django/db/__init__.py", line 11, in <module>
    if DEFAULT_DB_ALIAS not in settings.DATABASES:
  File "/usr/local/lib/python2.7/dist-packages/django/utils/functional.py", line 184, in inner
    self._setup()
  File "/usr/local/lib/python2.7/dist-packages/django/conf/__init__.py", line 42, in _setup
    self._wrapped = Settings(settings_module)
  File "/usr/local/lib/python2.7/dist-packages/django/conf/__init__.py", line 95, in __init__
    raise ImportError("Could not import settings '%s' (Is it on sys.path?): %s" % (self.SETTINGS_MODULE, e))
ImportError: Could not import settings 'myproj.settings' (Is it on sys.path?): cannot import name connection
ImportErrorではあるけども、その前にglibcのエラーがドバドバ出るので
sys.path云々ではなく拡張モジュールがおかしいんだろう。

githubのissueを色々みたところ、
/usr/local/lib/python2.7/dist-packages/_billiard.so を消せ
というのがあって、たしかにそれを消すとOKなんだけども、
そうすると起動時に
[2013-01-26 22:46:14,897: WARNING/MainProcess] /usr/local/lib/python2.7/dist-packages/billiard/__init__.py:318: RuntimeWarning: force_execv is not supported as the billiard C extension is not installed
とか出てなんかちょっと気分が悪い。

個人的な趣味で、オプション付ける方を選ぶ。

>python manage.py celery worker -B
 -------------- celery@ubuntu v3.0.13 (Chiastic Slide)
---- **** -----
--- * ***  * -- [Configuration]
-- * - **** --- . broker:      django://localhost//
- ** ---------- . app:         default:0x3885090 (djcelery.loaders.DjangoLoader)
- ** ---------- . concurrency: 2 (processes)
- ** ---------- . events:      OFF (enable -E to monitor this worker)
- ** ----------
- *** --- * --- [Queues]
-- ******* ---- . celery:      exchange:celery(direct) binding:celery
--- ***** -----

[2013-01-26 22:53:13,887: WARNING/MainProcess] celery@ubuntu ready.
[2013-01-26 22:54:04,286: WARNING/PoolWorker-2] TEST!
動いた。

djceleryをsouthと使ってschemamigrationが上手くいかない場合の対処法

Djangoのプロジェクトで、バックエンド処理にCeleryを使い始めました。
Southも使っています。

celeryとdjango-celeryはpipでインストールしました。


settings.pyはこんな感じです。
INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'django.contrib.humanize',
    'south',
    "kombu.transport.django",
    'djcelery',
    'myapp',
)
動かすにはdjcelery用のテーブルを作る必要があります。
manage.py schemamigration djcelery --init
しかし、pipでインストールした事により、djceleryは
/usr/local/lib/python2.7/dist-packages/djcelery
にインストールされるので、ユーザ権限でmigrationディレクトリが作成できません。

回避策は、それらサードパーティーのアプリをsouthの管理下から外すことです。
settings.pyに以下を書き足します。
SOUTH_MIGRATION_MODULES = {
    'django': 'ignore',    #kombu.transport.djangoのこと
    'djcelery': 'ignore',
}
あとは普通にmanage.py syncdbでOK。

kombu.transport.django が "django" になるのは若干気になるのだけど。

2012年10月31日水曜日

xmodmapでvimっぽくカーソル動かせるようにした

左手マウスのおすすめ
http://www.biwa.ne.jp/~chiro/kannkyou/mausu.htm
これを見て、試してみました。

気付いたことは
・左手は案外不器用で、軽いマウスだとなかなかポインタが定まらない
・これまでCtrlキーを常にインレンジにおさめていた左手が動くことで
 ショートカットキーを案外打ち損ねる
・右手をあまり動かさないようになると、思ったよりカーソルやPage Up/Down,Home/Endが
 遠く感じるようになる

特に最後のが結構意外で、結構右手首を小指側にぐっと曲げるような動きになってしまいます。

私はデスクのできる限り奥にモニタとキーボードを置き、
デスクの上に両肘をがっちりついてタイピングするのですが、
これまではマウスを動かすため右腕は頻繁に肘を浮かさざるを得ず、
そのためカーソルなどへも特に気にせず手を動かしていました。
ですが、右手の動きが減ると今度はそこが気になり、
しばらくすると少し右手首が痛くなってきてしまいました。

カーソルをvimっぽくhjklあたりで動かせればいいのにな…と思い、
xmodmapを書いてみました。

CapsLockを押しながらhjklでカーソル、
y/bをHome/End、u/nをPageUp/Downにしてみました。
間違って押すと鬱陶しいCapsLockも殺せて一石二鳥。

ついでに勢い余ってgにBackSpace,スペースバーにEnterまで割り当ててみたものが以下。

~/.Xmodmap
clear Lock
remove Control = Mode_switch
keycode 66 = Mode_switch
keycode 29 = y Y Home Home
keycode 30 = u U Prior Prior
keycode 42 = g G BackSpace BackSpace
keycode 43 = h H Left Left
keycode 44 = j J Down Down
keycode 45 = k K Up Up
keycode 46 = l L Right Right
keycode 56 = b B End End
keycode 57 = n N Next Next
keycode 65 = space NoSymbol Return
ちなみに一応書いておくと環境はUbuntu 12.10、英語キーボードです。

慣れたら相当快適なんじゃないかという予感を感じております。

#HHK使えばいいんじゃねとか禁止w

ちなみにエントリの趣旨的にもはやどうでもいいことですが
個人的にはマウスのボタンは入れ替えない方が使いやすく感じました。

2012年10月21日日曜日

Ubuntu 12.10入れた(VirtualBox編)

Ubuntu 12.10。

というわけでまずはメインの職場の開発環境であるVirtualBox (on Win7) に
クリーンインストールしてみた。

以前のバージョンまで、VirtualBoxのゲストでは3Dアクセラレータを有効にすると
フルスクリーンにした時に描画がフリーズしてしまうという現象が出てしまい、
(参照→ http://www.youtube.com/watch?v=WOLv-9VwcTc
Unity 2Dでしか使えず。
まあその後結局 xubuntu で使っている。
とりあえずインストールは普通に終了。
その後VirtualBox Guest Additionをインストールする必要があるが、
VirtualBox 4.1.22に付属のGuest Additionは、
Ubuntu 12.10のXの方がバージョンが新しいせいかインストールに失敗。

さてどうしようかなと思ったが、 何のことはなく
sudo apt-get install virtualbox-guest-additions
でOK。

そして問題のフルスクリーン。
一応フリーズはせずちゃんと動く…が。
重い。重いぞこれ。
とりあえずCompiz ConfigでFadingやAnimationを切って
何とかまあ許容できるかなというレスポンスになった。

そして次にランチャー。
画面は出来るだけ広く使いたくてランチャーは隠れていてほしいので
System SettingsのAppearanceのBehaviorタブで(私は英語でインストールしているので)で
Auto-hide the Launcherをonにした…ら、残念なことが。


ランチャーが非表示になったところの壁紙の色がおかしいまでなら全然構わないのだが、
そこにウィンドウを持っていったらその謎の帯の下に入ってしまうという残念な現象。
これは致命的。

というわけでさっさと諦めてxubuntuにする。さようなら新Unity。
色々新機能付いたLensとか見るまで行かなかったよ。

sudo apt-get install xubuntu-desktop
そしてXubuntuで再起動し、色々アプリをapt-get install。
それと私は開発用のIDEにはAptana Studio 3を使っているのでダウンロードして展開。
ランチャーに登録。同梱のアイコンを設定…


なんだこれ。
どうやらxpm形式の扱いがうまくいかなくなってる。
convert icon.xpm -resize 48x48 icon.png
変換したpngを割り当てればOK。

そして、仕事上Google Talkをよく使うため、Empathyを設定。
Empathyを起動し、アカウントを追加しようとしたところ、
こんなダイアログが表示される。


うん?

Empathyは、今回のUbuntuの目玉の一つである「ネットワークサービスアカウントの管理」に
関係していたはず。
ここの「Personal」の並びに「Online Accounts」というのがあったはずだが、それがない。
kupferでOnline Accounts打ってみるとアイコンは出るが、
やはり同じ画面に。

どうやらまあ要するにXubuntuだとだめ、という状態である模様。
ログアウトしてUbuntuで入りなおして設定したら、
Xubuntuの方でもEmpathyがちゃんと動いた。
まあ一度設定したらしばらく変更する事はないものなのでよしとする。

というわけでUbuntuというかXubuntu12.10。
特に何が変わった感じはしません。
そりゃXubuntuだしね。

変わったか?と思ったこととすれば、mozcの変換候補で
同音異議語に「用例」が出るようになってる。
これはありがたい。

あとXubuntuの壁紙はグラデーションの右下に○がいくつか並んでるようなものだけど
これはシンプルかつスタイリッシュでいいと思う。

以上、何かあんまり他の人の役に立たなそうなUbuntuインストール記。

2012年9月21日金曜日

PHPのarrayの入れ子を作るのに苦労して=&とunsetを使って何とかした話

PHPで、

こんな感じのDBから読んできたデータから、


こんな構造を作りたいなと思ったのです。

こんな感じかな。
<?php
//ここから
function row($type,$typeName,$value1,$value2){
    return array("type" => $type,
                 "typeName" => $typeName,
                 "value1" => $value1,
                 "value2" => $value2);
}
$rows = array(row(1,"あ","ABC","DEF"),
            row(1,"あ","AAA","BBB"),
            row(1,"あ","XXX","YYY"),
            row(2,"い","BEEF","PORK"),
            row(2,"い","COFFEE","TEA"),
            row(2,"い","MILK","COCOA"));
//ここまではサンプルデータを作っているところなので本題とは関係なし。
//データはソートはされているものとする。

$tree = array();    // $treeが最終的なルート配列オブジェクト
$prevType = null;   // Typeが変わったらこの処理をする…というためのもの
foreach($rows as $r){  //1行ずつ読む
    if($prevType !== $r["type"]){ //もしTypeが変わったら
        // 変更チェック用の変数を更新し
     $prevType = $r["type"];
        // 親のノードを新規作成し、$typenodeを差し替え
        $typenode = array("type" => $r["type"],
                          "typeName" => $r["typeName"],
                          "values" => array()); // 親のノードは子を格納する配列を持つ
        // 作った親のノードをルート配列に追加
        $tree[] = $typenode;
    }
    // 子のノードを作成
    $valuenode = array("value1" => $r["value1"],
                        "value2" => $r["value2"]);
    // 今の時点で $typenode で親ノードが参照出来るはずで、
    // それに対して"values"で引ける子ノード格納用配列に、
    // 子のノードを追加
    $typenode["values"][] = $valuenode;
}
実行してみた結果。
( ಠ益ಠ)
ステップ実行してみると、
        :
        // 作った親のノードをルート配列に追加
        $tree[] = $typenode;
    }
        :
    // 今の時点で $typenode で親ノードが参照出来るはずで、
    // それに対して"values"で引ける子ノード格納用配列に、
    // 子のノードを追加
    $typenode["values"][] = $valuenode;
}
この下の方の$valuenodeを追加しているところで、
「$typenode」には追加されるものの、
「$treeからたどれる『$typenodeと同じものであるはずのもの』」
には追加されているように見えない。
        $tree[] = $typenode;
で、$typenodeそのものがコピーされてしまっているように見える。
本当は違っててその後変更が発生しそうになった時にコピーされるんだろうけど。

なのでこうしてみた。=&で参照渡し的な何かになるはずと聞いて。
        $tree[] =& $typenode;
実行してみた結果。
(╬ಠ益ಠ)

今度は、二週目の
        // 親のノードを新規作成し、$typenodeを差し替え
        $typenode = array("type" => $r["type"],
                          "typeName" => $r["typeName"],
                          "values" => array()); // 親のノードは子を格納する配列を持つ
        // 作った親のノードをルート配列に追加
        $tree[] =& $typenode;
の上の方のところで「新しいノードを作って$typenodeを差し替えた」だけのつもりが、
既に一周目でセットした$tree[0]の要素までも差し替わってしまった。

参照渡し…ってそこまで参照なの!?
これ、そもそもマインドモデルが上の図と違ってて、模式図で表せない。

最終的にこうしたら何とかなった。
$tree = array();
$prevType = null;
foreach($rows as $r){
    if($prevType !== $r["type"]){
        $prevType = $r["type"];
        unset($typenode);
        $typenode = array("type" => $r["type"],
                          "typeName" => $r["typeName"],
                          "values" => array());
        $tree[] =& $typenode;
    }
    $valuenode = array("value1" => $r["value1"],
                        "value2" => $r["value2"]);
    $typenode["values"][] = $valuenode;
}
差し替える前にunsetをする事で、
$typenodeというシンボルと実体との紐付けが解放されるので、
あらためて作ったarrayをセットしても既存のデータ構造に影響を与えない。

なんだこの仕様。

array関数で新たに配列作って変数に代入する、って
「mallocしてそのポインタを返す」的な感覚かと思ってたら、
「返す先のポインタがあったら指している領域に上書きする」みたいな
日本語すら怪しくなるような動きもするとは。
理解に苦しむ。

2012年9月18日火曜日

mroongaのデータを壊してテーブルも消せなくなったのを何とかした風

先週末ハマった件のメモ書き。
これで合っているかどうか保証も何も全く無いので
参考にする場合は自己責任で。

mroongaをストレージモードで使った開発中、
安直な設計でテーブル作って膨大なデータのinsertクエリを実行してしまった。

全然戻ってこないのでクエリのキャンセルをしたのだがそれでも戻ってこず。
mysqldのrestartも実行したが戻ってこず。
仕方なくkill -9で抹殺。

その後再起動し、この設計じゃダメだなと思いdrop tableしようとしたら
drop tableも戻ってこない。

プロセスリストを見てみると
select count(*) into @discard from `information_schema`.`PARTITIONS`
というSQLをdebian-sys-maintが実行していて全然戻ってきていない。
こいつがロックしている線が濃厚。


当該のSQLやdebian-sys-maintでググってみると
「debian系のおせっかいだからスクリプトいじって黙らせちゃえよ」
みたいな記事が見つかるが、
それもなんだかイカン気がする。

やけくそでmysql止めて
/var/lib/mysql/【スキーマ名】.mrn.*
のファイルを全消しして
再起動してdrop tableしてみる。
瞬時にdisconnected from server的なメッセージが出て、
mysqldのプロセスIDが変わってる。
悪化/(^o^)\

repair tableとかあがいてみる。
「このエンジンはリペアとかないよ」的なメッセージが出る。

そこでふと、以前mysqlのバージョンだけ上がってmroongaプラグインが読み込めなくなって
mysqlの起動が出来なくなってヒイコラした時、
その後drop tableは普通にできたよなーという記憶が。

ということでUNINSTALL PLUGINして、dropしてみる。
…成功!


あらためてINSTALL PLUGINして、テーブル作ってまともな量insert。
無事動作している模様。


多分こうなった場合、
  1. UNINSTALL PLUGIN
  2. drop table
  3. mrnファイル削除
  4. INSTALL PLUGIN
  5. create table
とすればいいのかなという気がしているけど
実はまずいのかもしれない。不明。


やってみる場合自己責任で。

2012年8月6日月曜日

ubuntuでusermod -Gでやらかしてsudo出来なくなった場合

開発PCの/var/lib/mysqlの中のファイルをいちいちsudoせずに参照したくなった。
ubuntuのユーザ名はadmin。
mysqlグループでの権限追加して、自分もmysqlグループに入ればいいだろ。
$ sudo chmod g+rx /var/lib/mysql
$ sudo usermod -G mysql admin
ログアウトしてログイン。
$ cd /var/lib/mysql
よし入れた。
おっと、見たいのはこの中のデータベースごとのディレクトリ内。
$ cd db1
bash: cd: db1: Permission denied
おおっと、データベースごとのディレクトリにも権限を足さないといけない。
$ sudo chmod g+rx db1
[sudo] password for admin:admin is not in the sudoers file.  This incident will be reported.
?…!! やっちまった!

usermod -G は所属グループを上書きするので,
元々所属していたsudoグループから引っ剥がされてしまった!
もとい、引っ剥がしてしまった orz


まあまあ、ありがちありがち。
一度深呼吸して、PCをブチ切り再起動。

grubで[recovery mode]を選択して起動し、rootシェルを選択。
# mount -o rw,remount /
# usermod -G adm,cdrom,sudo,dip,plugdev,mysql admin
# reboot
再起動で復活。

後の方のusermod -G以降は、ほぼ同じ設定で立てていたVMから拾ってきたもの。
そういうのが無い方でやらかしてすぐだった方は
/etc/group- に直前の設定が残っているので
rootシェルで入ったあとすぐ参照して控えましょう。

複数回usermodやっちゃった方は南無。
でもとりあえずadmとsudoぐらい入っておけば何とかなるでしょう。