PHP FPM のチューニング

このサイトはNginx + WordPress で運用しているだが、設置当初はサイトが重くて仕方なかった。
top コマンドで状況を調べてみるとメモリを使い切っていたので、途方に暮れて解決策をググったところ、以下の記事を発見。 有用な記事をありがとうございました。

CentOS php-fpmの設定を変更してメモリ消費を減らした方法 | CrystalSnowman.com

サーバーはさくらのVPS (Cent OS 6、メモリ 1GB) なので、この記事とまさに同じ状況らしい。 これを参考に PHP FPM の設定 (/etc/php-fpm.d/www.conf) を以下のように変更し、現状運用中。

pm = dynamic
pm.max_children = 10 ; default 50
pm.start_servers = 5
pm.min_spare_servers = 2 ; default 5
pm.max_spare_servers = 6 ; default 35

設定変更前と比較にならないくらい軽く(というか普通に)なった。ここのようにアクセス数の少ないサイトはこういった設定で問題ないらしい。

PHP FPM はデフォルトで最大50ものプロセスを立ち上げようとするということは、比較的ハイスペックな環境を想定して設計されているのだろうか。果たして。

[React.js] setStateしても直ちにstateは変更されない

最近仕事でReactをやっている。
今回のネタはひとこと(ひとコード?)で言うと以下のようなこと。

getInitialState () {
  return { clicked: false };
},
clickHandler () {
  this.setState({ clicked: true });
  console.log(this.state.clicked); // -> false
},
render () {
  console.log(this.state.clicked); // -> true
  return <button onClick={this.clickHandler}>Click Me</button>;
}

インタラクションのハンドラで this.setState したとして、そのハンドラ内でthis.state を参照しても、まだ更新後の値は取れない。render() が呼ばれるタイミングでは更新後の値になっている。実際にステートが更新されるタイミングは意図的に制御されているらしい。トリッキーだ。

更新後の値は変数に入れておいて this.setState しつつ、ハンドラ内ではその変数の値を使うのがおそらく正解だろう。

getInitialState () {
  return { clicked: false };
},
clickHandler () {
  var value = true;
  this.setState({ clicked: value });
  console.log(value); // -> true
},
render () {
  console.log(this.state.clicked); // -> true
  return <button onClick={this.clickHandler}>Click Me</button>;
}

Chrome 43 からは DOM attribute が prototype プロパティに変更される

DOM Attributes now on the prototype chain

それによって…

  • hasOwnProperty()/getOwnPropertyDescriptor()/JSON.stringify() で、DOM attribute が検出できなくなる
  • read-only な DOM attribute を上書きしようとすると例外を投げるようになる

だそうな。
他人が作ったフレームワークは特に、それで動かなくなったりするものも出てくるかもしれないので頭の片隅に置いておくとよい。

Maxのドキュメントを読む その1 (Javascript in Max 01 – Basic Techniques)

最近 Max というビジュアルプログラミング言語を学んでいる。js / jsui オブジェクトというのがあり、その中で JavaScript が書ける、ということでドキュメントを読んでいる。 正直流行っていない言語なので情報が少なく、とにかく公式ドキュメントを読むしかないのである。

読んだドキュメントを備忘録的にエントリーしておく。その第1弾。


注意事項

  • JavaScriptファイルを更新した場合、MAXパッチを開き直さないと変更が反映されない

Arguments

Document

js オブジェクトに渡した引数は JavaScript 内では jsarguments[] 配列で参照できる。

  • jsarguments[0] => ファイル名 (required)
  • jsarguments[1] 以降 => その他の引数 (optional)

ということになる。

Test Code

function bang() {
  post(jsarguments[0], jsarguments[1], jsarguments[2], jsarguments[3]);
}

Arguments test


How Input to the js Object is Handled

Document

js オブジェクトの inlet に foo 1 2 3 というメッセージを送った場合、グローバルスコープの foo() 関数を引数 1,2,3 と共に実行するということになる。

Test Code

function foo(a, b, c) {
  post(a, b, c);
}

How Input to the js Object is Handled

なお、グローバルスコープは jsthis オブジェクト(ブラウザ JavaScript でいう window オブジェクト)とドキュメントには書いてあるが、jsthisオブジェクトを呼び 出そうとしてもMAXウィンドウに Javascript ReferenceErrod: jsthis is not defined と出て怒られる。なんだこれは。 一方、一般的な this オブジェクトは機能している。

function foo() { }
post(this.foo === foo); // 1 (true)

Special Function Names

Document

msg_int, msg_float

Document

inlet に int が入力されると msg_int() が呼ばれる。inlet に float が入力されると msg_float() が呼ばれる。msg_float() が未定義の場合、 msg_int() が代用で呼ばれるが、少数点以下は切り飛ばされる。 なお msg_float() は少数点第3位以下を受け取ることができない。

Test Code 1

function msg_int(a) { // a == 1
  post(a); // 1
}

msg_int

Test Code 2

function msg_int(a) { // a == 1
  post(a); // 1
}
function msg_float(a) { // a == 1.23456
  post(a); // 1.23
}

msg_float


list

Document

inlet に最初の値が int もしくは float の list が入力されると list() が呼ばれる。 上記の例のように最初の値が String の list はその String 名の関数が呼ばれる。

Test Code 1

function list(a, b, c) { // a == 1, b == 2, c == hoge
  post(a, b, c); // 1 2 hoge
  post(arguments.length); // 3
}

list


anything

inlet に入力されたものに該当する function が定義されていなかった場合、anything() で受け取ることができる。例えば int が入力されたときに msg_int() が未定義だったら anything() が呼ばれる。float や list でも同様。
anything() 内部では messagenameinlet 変数が定義されており、それぞれ inlet に入ったメッセージの種類と、inlet 番号を参照できる。

Test Code 1

function anything(a, b, c) { // a == 1, b == 2, c == hoge
  post("messagename", messagename); // messagename list
  post("inlet", inlet); // inlet 0
  post("anything", a, b, c); // anything 1 2 hoge
}

anything


loadbang

Document

loadbang() はパッチ起動時に呼ばれる。js オブジェクトや jsui オブジェクトを追加した時ではなく、あくまでそれを予め含むパッチ起動時に呼ばれることに注意。
Cmd+Shiftを押しながらパッチを起動すると loadbang を無効化できるが、無効になっているかどうかは max.loadbangdisabled プロパティに 1 が入っているかどうかで分かる。

Test Code 1

function loadbang() {
  if (max.loadbangdisabled == 1) {
    post("no loadbang");
  } else {
    post("loadbang!");
  }
}
function bang() {
  post("bang!");
}

普通にパッチを起動した場合
loadbang

Cmd+Shiftを押しながらパッチを起動した場合
noloadbang


getvalueof

Document

JavaScript 内で定義した変数の値(String か Number)を pattr 関連オブジェクトから呼び出せるようにする関数。 → pattr オブジェクトのことがよく分からないので、テストコードが書けない。後で復習する。


setvalueof

Document

pattr 関連オブジェクトから JavaScript 内に変数(Number か String)をパスできるインターフェースを提供する関数。 value が複数の場合、jsthis オブジェクトの arrayfromargs() メソッドで引数を扱うと良いとのこと。
→ pattr オブジェクトのことがよく分からないので、テストコードが書けない。後で復習する。


save

Document

save() を定義すると、JavaScript 内の状態をパッチに保持することができる。 パッチが再読み込みされると、JavaScript 内の状態が復元される。

save() 内だけで使える embedmessage() を使い、値を保存する。

  • embedmessage() の第1引数には保存された値を渡したいコールバック関数名を文字列で渡す
  • embedmessage() の第2引数以降には保存したい値を渡し、これがコールバック関数の引数に渡される

Test Code 1

var valuetosave = 0;
function foo(v) {
  valuetosave = v;
}
function save() {
  embedmessage("callback", valuetosave);
}
function callback(v) {
  valuetosave = v;
  post(v);
}

foo 1 メッセージを送ったあと、パッチを再起動した場合
save

foo 2 メッセージを送ったあと、パッチを再起動した場合
save


notifydeleted

Document

js オブジェクトが削除されたときに呼ばれる

Test Code 1

function notifydeleted() {
  post('js object was deleted.');
}

notifydeleted


Global Code

Document

グローバルスコープに書かれたコードは編集された後、スクリプトがロードされるかコンパイルされたタイミングで評価される。 js / jsui オブジェクトが完全に作られる前に評価される。 js オブジェクトがいくつ inlet / outlet を持つかはグローバルコードからは分からない。これはグローバルコードから inlet / outlet をいくつにするか定義できることを意味する。しかし言い換えれば、まだ outlet が存在しなければ、使うことはできない。 初期化処理を書きたい場合は loadbang() の中に書くべし。

グローバルコードでやるべきこと

  • inlet / outlet の数を定義する
  • jsarguments[] プロパティ(js オブジェクトの引数)にアクセスする
  • inlet / outlet の値の操作
  • グローバル変数の定義と初期化
  • グローバルアプリケーション環境にアクセス&操作するため、Max オブジェクトを使う

グローバルコードでやるべきでないこと

  • outlet から何か出力すること
  • js オブジェクトが置かれたパッチ側を参照しようとすること

Private (Local) Function

Document

js オブジェクトへの inlet メッセージから参照されたくないローカル関数を作りたい場合、local プロパティに 1 をセットする。

Test Code 1

function foo() {
  post("Welcome to 'foo' method!");
}
foo.local = 1;

private function

grunt-contrib-jshint の設定

Gruntfile.coffee に以下のように書く。

grunt.loadNpmTasks 'grunt-contrib-jshint'
grunt.initConfig(
  jshint:
    main:
      options:
        jshintrc: true
      src: [ 'app' + sitePath + 'js/script.js' ]
  ...
  watch:
    js:
      options:
        livereload: true
      files: [ 'app' + sitePath + 'js/*' ]
      tasks: [ 'jshint' ]
)

options.jshintrc = true を設定するとそれ以外の options は無視され同階層に置かれた .jshintrc ファイルを参照するようになる。

.jshintrc はJSON形式で記述する。
結果的に以下のような設定に。

{
  "node": true,
  "esnext": true,
  "bitwise": true,
  "camelcase": true,
  "curly": true,
  ...
  "globals": {
    "window": true,
    "document": true,
    "jQuery": true,
    "$": true,
    "_": true,
    "Backbone": true
  },
  "-W116": true,
  "-W041": true
}

globals には「XXXグローバルオブジェクトがない」的な警告が出るときに、予め「このグローバルオブジェクトはあるから、警告出すな」とJSHint側に伝えておく設定。
-WXXX: true は特定のエラーを無視したいときに追加する設定。このエラーコード(ドキュメントの原文では warning code)は grunt --verbose(もしくは grunt -v)として verbose モードで Grunt タスクを起動すると表示されるようになる。

表示例:

^ [W116] Expected '!==' and instead saw '!='.

ここでは W116 というのが warning code なのでそれを "-W116": true のように options に追加すると、警告は出なくなる。