進捗管理ってどうしたらいいんだろうか

数年前から、PJリーダーとして仕事をすることが多くなり、「進捗管理」で悩むことが多かったのですが、以下の記事を読んで、少し光明が見えた気がしたので、忘れないように書いておこうと思います。


SEの残業しない仕事術 : モニタリング&コントロール(1)
SEの残業しない仕事術 : モニタリング&コントロール(2)
SEの残業しない仕事術 : モニタリング&コントロール(3)

基本的な考え方

基本的な考え方としては、CMMIがベースになっています。CMMIには「進捗管理」という項目はなく、進捗管理に相当するものとして、「Project Monitoring and Control(PMC)」という定義があるようです。

  • ちゃんと状況を見て(=モニタリング)
  • 状況に応じて対処しなさい(=コントロール

定期的に、メンバーの進捗を確認するのではなく、リアルタイムに状況を把握し、問題が発生した時点で対策を打てるように心掛けることが大事ということだと感じました。

モニタリング

状況を把握することが大事というのは、誰もが分かっていることだと思います。では何を把握すればいいのでしょう?上記の記事では、以下の項目が挙げられています。これらの項目をWBSに追加した上で日々集計し、その状況を観察し続けます。

  • サイズの初期見積
  • サイズの現在見積
  • 工数の初期見積
  • 工数の現在見積
  • 経過時間
  • 残り時間

※この項目は、有名な「Joel on Software」を参考にしたそうです。

Joel on Software

コントロール

リアルタイムに状況を把握(観察)し続けるだけでは意味がありません。そのPJがスケジュール的にヤバイかどうかをどう判断すればいいでしょうか?その判断ポイントとなるのが、「残工数 = 残り時間の合計」と「残稼動時間 =(納期までの残り日数)×(1日の稼動時間)」です。


工数/残稼動時間


このように、この2つの値を比較することにより、「自分たちに残された時間(残稼動時間)に対して、やらなければならない残タスクのボリューム(残工数)が溢れていないか」をチェックすることができるようになります。


これは、普段自分たちが行っている進捗管理とはかなり観点が異なると思いました。普段は、「何が終わったか?」という報告をさせることが多いですが、よく考えれば、「何が残っているか?」「エンドまでにそのタスクをやり切れるのか」という視点に切り替える必要がありますね。

まとめ

もちろん、単純に上記の比率だけでは判断はできないかもしれません。各タスクには因果関係があるので、PJ全体の工数計算上は辻褄が合っていても、ボトルネックのタスクに絡んだものが多いと、結局納期に間に合わないということが考えられるからです。


ですが、重要なことは、リーダーがそのPJに対して明確な判断基準を持つ必要があり、そのために必要な数字を把握するために、日々観察を続けなければならないということだと思いました。


最後に、


以下の引用にもある通り、プレイヤー⇒リーダーになる段階での育成について、もっと組織的な取り組みが必要だと思いました。リーダー研修に参加させるだけでは、身につかないでしょう。OJT的な取り組みを取り入れる方向がいいのかもしれません。

ほとんどの人は、進捗管理の仕方について、トレーニングをうけないまま、リーダーとなっていきます。だいたい、きちんと進捗管理された覚えもない人も、多いのです。わからないのも当然です。

SEの残業しない仕事術 : モニタリング&コントロール(1)

MySQLのクエリキャッシュについて

今まで、MySQLのクエリキャッシュを利用することに何の懸念も持っていなかったのだけど、以下のような意見があり、今後は少し気をつけようと思っています。


確かにヒット率という観点でみると、エンドユーザ向けのWebサービスでは、意味が無さそう。

今までMySQLのクエリキャッシュはは有効にしてたんですが、Webサービスだとキャッシュヒットするようなクエリはそんなに多くないし、どこかで見かけたんですが(失念…)クエリキャッシュをオフにしたら(逆に)パフォーマンスが上がっただか負荷が下がっただかというのも目にしたので、今度クエリキャッシュはオフにしようと思ってました。(どのみちヒット率悪いし)

MySQLで、指定したときだけクエリキャッシュする - (ひ)メモ


マルチコア環境という視点でも見てみると、DBサーバにある程度のCPU数があるならば、変にクエリキャッシュすると、マルチコア環境を活かせない可能性があるということですかね。

クエリキャッシュはCPUスケーラビリティが悪いので、8コアぐらいのマシンでInnoDB Pluginを入れて単純なクエリをゴリゴリ回すとクエリキャッシュなしの方が速い場合があります

はてなブックマーク - sh2のブックマーク / 2010年4月6日

設定方法

my.cnfの「query_cache_type」パラメータで設定するようです。「DEMAND」で設定しておくのがいいのかもしれません。

参考URL:MySQL :: MySQL 5.6 リファレンスマニュアル :: 5.1.4 サーバーシステム変数

  • 0 または OFF
    • キャッシュを使用しない。注意:これはクエリ キャッシュのバッファの割当を解除しない。解除するには query_cache_size を 0 にセットする。
  • 1 または ON(※デフォルト
    • SELECT SQL_NO_CACHE を除くすべての結果をキャッシュする。
  • 2 または DEMAND
    • SELECT SQL_CACHE で始まるクエリだけをキャッシュする。

FTP用ユーザの作成時の考慮点

FTP用のユーザを作成する時に考慮すべきポイントは、以下の2つです。

シェルログインを不可に設定

この設定は、セキュリティの観点で必要な設定です。
FTP用ユーザにまで、ログインさせる権限を与える必要はありません。従って、そのようなユーザの作成時には、以下のコマンドで設定します。

[root]# useradd -s /sbin/nologin*1 testuser

homeディレクトリを変更

FTPで受信したファイルの冗長化をどう実現するかについては、いくつか方法があります。
例えば、HA構成にして、DRBDを用いてミラーリングする方法がありますが、DRBDではある特定のディレクトリ配下をミラーリング対象とします。従って、FTPで利用されるディレクトリは、DRBD領域に変更する必要があります。

そのような場合に、以下のコマンドで、FTP用ユーザのhomeディレクトリを変更します。

[root]# usermod -d /var/ftp/data testuser ※/var/ftp/data以下がDRBD領域だと仮定

*1:/sbin/nologinは、シェルログインを禁止できるプログラムで、アカウントは必要だがログインはさせたくない、というユーザーのデフォルトシェルとして設定すると、シェルログインを禁止できます。

PgpoolでのPreparedStatementのDEALLOCATE問題

Pgpool(ver 2.3.3)を使っていて、たまにDEALLOCATE*1に関するエラーが発生するので調査していました。

状況

  • Pgpoolログに、「DEALLOCATE pdo_stmt_00000001 message: prepared statement "pdo_stmt_00000001" does not exist」とエラー出力される
  • PostgreSQLログに、「ERROR: prepared statement "pdo_stmt_00000001" does not exist」とエラー出力される
  • このエラーが検知されるのは、全てスレーブノード

原因

以下、引用にもある通り、Pgpoolを「マスター/スレーブモード」で利用している場合、PreparedStatementがマスターノードで作成されたにも関わらず、DEALLOCATE処理をスレーブにも実行していることが原因だろうということです。

Some notices: First we issue a prepared SELECT NEXTVAL in a transaction.
This is only send to the master. Later we try to deallocate the prepared
statement. This works on the master, but fails on the slaves. Seems to
be a logic flaw.

http://pgfoundry.org/pipermail/pgpool-hackers/2010-May/000311.html

少し詳しく書くと、以下のようになります。

  1. 更新系SQL、または、トランザクション中のSELECTは、(Pgpoolの機能によって)マスタノードで実行される。
  2. そのSQLがPreparedStatementを用いている場合、PreparedStatementもマスタノードで作成される。
  3. にも関わらず、DEALLOCATE処理は、マスタ、そしてスレーブにも実行されてしまう。
  4. そのため、スレーブ側で存在しないPreparedStatement(SQLの雛形)の削除(メモリの解放)に失敗する。


下記の通りこの件は、ver2.3.2で修正されている*2ようなのですが、2.3.3では発生してしまいます。。

2.3.2 (tomiteboshi) 2010/02/07
バグ修正
master/slaveモードの際に、DEALLOCATEをすべてのノードに送らないようにして、kind mismatchエラーを防ぐようにしました(Tatsuo)

http://pgpool.projects.postgresql.org/pgpool-II/doc/pgpool-ja.html

影響

このエラーについて、有識者に確認したところ、

  • PDOなどの接続ライブラリが、名前付きのPreparedStatementを作成して、それを明示的に DEALLOCATE するタイプの場合に発生する。
  • このエラーが発生したからと言って、データ不整合が発生しているというわけではない。
  • また、このエラーによって、データ不整合が発生してしまうこともない。
  • この不具合は、Pgpool3.0 で修正されている。

対策

  • (できれば使いたいが)PreparedStatementを使用しない
  • (実害は無いようなので)サーバ監視でこのエラーを無視
  • Pgpool3.0以上にバージョンアップ(または2.3.2にダウン)

*1:「DEALLOCATE=確保したメモリーを解放する」という意味で、ここではPreparedStatement用に確保したメモリの解放するために実行したSQLコマンド(DEALLOCATE)が失敗したということになります。

*2:確かに、Pgpool2.3.2であれば発生しないようでした。

Apacheで圧縮してコンテンツ配信しよう

最近、スマートフォン向けのサイトなどが多くなりつつありますが、スマートフォンの場合、「(携帯キャリアの3G回線などの)細い回線」かつ「(JavaScriptなどを含んだ)リッチコンテンツ」という事情から、コンテンツのダウンロードが重く感じるということがあります。


その対策として、Webサイトの高速化 ルール4 コンポーネントを圧縮しよう! にある通り、JavaScriptCSSの外部ファイルを圧縮して送信することで、パフォーマンスを向上しようという話です。


但し、導入時には、運用しているサーバのCPUリソース状況を確認する必要があります。なぜなら、圧縮する度にCPU消費する事になり、結果CPU使用率は上がるからです。CPU使用率は余裕で、かつ、ネットワーク帯域は節約したい場合にはいい手段だと思います。


以降で、Apacheへの圧縮用モジュール追加、設定内容、動作確認の順で説明していきます。

Apacheへのモジュール追加

mod_so の確認

まず、モジュール追加するには、「mod_so」というモジュールが必須ですので、その存在確認を行います。*1

[root]# /usr/local/apache2/bin/httpd -l
  ・
 ・
  mod_alias.c
  mod_so.c
追加モジュールのコンパイル

今回利用するモジュールは、以下の2つです。

  • mod_deflate.so(※要モジュール追加)
    • コンテンツを圧縮するモジュール
  • mod_filter.so(※Apache本体に組み込まれているはずなので追加不要)
    • コンテンツタイプによって、圧縮対象を指定するためのモジュール

apxs を使って、mod_deflate.so をコンパイルします。「-c」オプションはコンパイル、「-i」オプションはインストール(/usr/local/apache/modules に移動などしてくれる)という意味です。
参考にしたサイトでは、「-a」オプションがつけられていることが多かったのですが、個人的には勝手に、httpd.confにLoadModuleディレクティブを追加されたりするのは嫌なのでつけていません。

[root]# /usr/local/apache2/bin/apxs -c -i 
            /root/modules/httpd-2.2.11/modules/filters/mod_deflate.c

/usr/local/apache2/build/libtool --silent --mode=compile gcc -prefer-pic
    -DLINUX=2 -D_REENTRANT -D_GNU_SOURCE -D_LARGEFILE64_SOURCE -g -O2
    -pthread -I/usr/local/apache2/include  -I/usr/local/apache2/include
    -I/usr/local/apache2/include   -c -o 
    /root/modules/httpd-2.2.11/modules/filters/mod_deflate.lo
    /root/modules/httpd-2.2.11/modules/filters/mod_deflate.c && 
    touch /root/modules/httpd-2.2.11/modules/filters/mod_deflate.slo
/usr/local/apache2/build/libtool --silent --mode=link gcc -o 
    /root/modules/httpd-2.2.11/modules/filters/mod_deflate.la  
    -rpath /usr/local/apache2/modules -module -avoid-version
    /root/modules/httpd-2.2.11/modules/filters/mod_deflate.lo
/usr/local/apache2/build/instdso.sh SH_LIBTOOL='/usr/local/apache2/build/libtool'
    /root/modules/httpd-2.2.11/modules/filters/mod_deflate.la
    /usr/local/apache2/modules
    /usr/local/apache2/build/libtool --mode=install 

cp /root/modules/httpd-2.2.11/modules/filters/mod_deflate.la
    /usr/local/apache2/modules/
cp /root/modules/httpd-2.2.11/modules/filters/.libs/mod_deflate.so
    /usr/local/apache2/modules/mod_deflate.so
cp /root/modules/httpd-2.2.11/modules/filters/.libs/mod_deflate.lai
    /usr/local/apache2/modules/mod_deflate.la
cp /root/modules/httpd-2.2.11/modules/filters/.libs/mod_deflate.a
    /usr/local/apache2/modules/mod_deflate.a

chmod 644 /usr/local/apache2/modules/mod_deflate.a
ranlib /usr/local/apache2/modules/mod_deflate.a
PATH="$PATH:/sbin" ldconfig -n /usr/local/apache2/modules
                                                                                                                                          • -
Libraries have been installed in: /usr/local/apache2/modules If you ever happen to want to link against installed libraries in a given directory, LIBDIR, you must either use libtool, and specify the full pathname of the library, or use the `-LLIBDIR' flag during linking and do at least one of the following: - add LIBDIR to the `LD_LIBRARY_PATH' environment variable during execution - add LIBDIR to the `LD_RUN_PATH' environment variable during linking - use the `-Wl,--rpath -Wl,LIBDIR' linker flag - have your system administrator add LIBDIR to `/etc/ld.so.conf' See any operating system documentation about shared libraries for more information, such as the ld(1) and ld.so(8) manual pages.
                                                                                                                                          • -
chmod 755 /usr/local/apache2/modules/mod_deflate.so

mod_deflate.so ができたかどうか確認してみます。

[root]# pwd
/usr/local/apache2/modules

[root]# ls -ltr
 -rwxr-xr-x 1 root root   129705  5月 14  2009 mod_rewrite.so
 -rwxr-xr-x 1 root root    42292  5月 14  2009 mod_headers.so
 -rwxr-xr-x 1 root root    30367  5月 14  2009 mod_expires.so
 -rwxr-xr-x 1 root root 13191193  5月 14  2009 libphp5.so
 -rwxr-xr-x 1 root root    48770 11月 12 12:44 mod_deflate.so

Apache設定変更

モジュールのコンパイルが完了したので、httpd.confを修正します。設定の際に配慮するのは、以下の4点です。

  • 追加モジュールのロード
  • 圧縮コンテンツ非対応ブラウザ(古いブラウザ)への配慮
  • 画像コンテンツは圧縮しない(元々圧縮されているので)
  • 対象コンテンツのタイプを指定して圧縮を行う
[root]# vi /usr/local/apache2/conf/httpd.conf

##### 追加モジュールのロード #####
# mod_filterは「BASE」モジュールなので含まれているはずです。
# LoadModule filter_module modules/mod_filter.so*2
LoadModule deflate_module modules/mod_deflate.so

##### 圧縮コンテンツ非対応ブラウザ(古いブラウザ)への配慮 #####
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

##### 画像コンテンツは圧縮しない(CPUを節約) #####
SetEnvIfNoCase Request_URI\.(?:gif|jpe?g|png)$ no-gzip dont-vary

##### 対象コンテンツのタイプを指定して圧縮 #####
FilterDeclare Compression CONTENT_SET
FilterProvider Compression DEFLATE Content-Type $text/css
FilterProvider Compression DEFLATE Content-Type $application/javascript
FilterChain Compression

[設定内容の補足]

  • 環境変数「no-gzip」「gzip-only-text/html」
    • これらの環境変数mod_deflateモジュール内で参照され、no-gzipが設定されていれば、自動的にフィルターが外れます。
  • FilterDeclareディレクティブ
    • Compressionという名前のフィルター群のタイプがCONTENT_SETであると宣言しています。
  • FilterProviderディレクティブ
    • Compressionにフィルターを追加しています。
      • 第一引数はフィルター群に付ける名前(今回はCompression)
      • 第二引数はフィルターのプロバイダー名*3
      • 第三引数はフィルターを実行する条件を指定*4
  • FilterChainディレクティブ
    • Compressionフィルター群がApacheのリクエストを通じて呼び出されるようにします。*5


修正後、Apacheプロセスを再起動します。

[root@sidgen01 conf]# /etc/init.d/httpd restart
apache restart use /usr/local/apache2/conf/httpd.conf...   OK.

動作確認

FireFoxの「Live HTTP headers」で確認できます。確認の観点は以下の3点です。

  • HTTPリクエストヘッダー
    • Accept-Encoding: gzip,deflate
      • このリクエストヘッダーを送信されていること。送信されないブラウザでは圧縮されません。
  • HTTPレスポンスヘッダー
    • Content-Encoding:
      • gzip」となっていること
    • Content-Length:
      • 元ファイルのサイズよりも削減されていること

以下が「Live HTTP headers」での確認例です。

http://example.com/prototype.js

GET /prototype.js HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.2.10) Gecko/20100914 Firefox/3.6.10
Accept: */*
Accept-Language: ja,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive

HTTP/1.0 200 OK
Date: Fri, 12 Nov 2010 05:37:27 GMT
Last-Modified: Wed, 24 Oct 2007 01:33:59 GMT
Etag: "41da34-17837-43d331c950fc0"-gzip
Accept-Ranges: bytes
x-ua-compatible: IE=7
Cache-Control: no-cache,max-age=0
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 22037
Content-Type: application/javascript
Connection: close

または、Apacheアクセスログでも確認可能です。例えば、「prototype.js」で絞り込んだ上で、ファイルサイズの部分を確認するといいでしょう。設定変更前よりも、ファイルサイズが小さくなっていると思います。

[root]# grep prototype.js accesslog.20101112
 ・
 ・
192.168.1.1 - - [12/Nov/2010:16:58:29 +0900] "GET /prototype.js HTTP/1.0" 200 96311
192.168.1.1 - - [12/Nov/2010:16:58:31 +0900] "GET /prototype.js HTTP/1.0" 200 96311

 ---------- 設定変更を実施 ----------

192.168.1.1 - - [12/Nov/2010:17:00:57 +0900] "GET /prototype.js HTTP/1.0" 200 22037
192.168.1.1 - - [12/Nov/2010:17:00:57 +0900] "GET /prototype.js HTTP/1.0" 200 22037
負荷検証

今回の対応によるサーバ負荷状況について、以下の観点で確認しておいたほうがいいと思います。

  • CPU消費
  • Apacheの各プロセスのメモリ消費

方法としては、Apacheのabコマンドを使って、負荷をかけます。

[root]# /usr/local/apache2/bin/ab -n 1000 -c 50 
        -H 'Accept-Encoding: gzip,deflate' 'http://localhost/prototype.js'

そして、負荷をかけている状態で、topコマンドを使って、以下の3つの値を確認します。

  • 「%CPU」各プロセスのCPU使用率
  • 「VIRT」各プロセスの仮想メモリサイズ(kbytes単位)
  • 「RES」各プロセスが使用している物理(スワップされていない)メモリサイズ(kbytes単位)

参考URL:httpd.confによるWebサーバの最適化 (3/3):実用 Apache 2.0運用・管理術(3) - @IT


環境によって異なりますが、おそらく、この対応で極端に負荷が上昇することはないと思います。手元の環境では、CPU使用率が元の2割程度(4X%⇒5X%)上昇していました。
但し、サーバ構成として、前段にキャッシュサーバがあれば、圧縮された結果をキャッシュしてくれますので、毎回圧縮処理が走ることにはなりません。JavaScriptCSSの外部ファイルはほとんどの画面で共通に読み込まれるものですので、高いキャッシュヒット率が期待できます。

この対応の効果

大きめのJavaScriptライブラリであるprototype.js(約95K)のサイズが、75%程度削減され、22K程度になっていました。大量にアクセスがあるサイトで考えるとかなりのネットワークリソースの節約になります。サーバのCPUにある程度余裕があれば、ぜひ導入すべき設定だと思います。

おまけ

最近試したところでは、Android端末でも問題なく、圧縮コンテンツを解凍できるようでした。スマートフォン向けには、特に重要な設定になると思います。

*1:mod_so は、apache コンパイル時にしか組み込む事ができないため、もし存在しなければApache本体の再コンパイルになります。

*2:この行を有効にすると、設定ファイル修正後、Apache再起動の際、「httpd: Syntax error on line 19 of /usr/local/apache2/conf/httpd-rewrite.conf: module filter_module is built-in and can't be loaded」というエラーが出ます。つまりもう組み込まれているよというエラーです。「/usr/local/apache2/bin/httpd -l」で確認しておくとよいです。もし無ければ、「/usr/local/apache2/bin/apxs -c -i /root/modules/httpd-2.2.11/modules/filters/mod_filter.c」でコンパイルしましょう。

*3:mod_deflateモジュールを読み込むと、ap_register_output_filter関数でDEFLATEというプロバイダー名が自動的に登録されます(そのプロバイダーがdeflateを行います)

*4:今回はHTTPレスポンスヘッダのContent-typeがtext /plainに部分一致した場合のみ、フィルターを実行するという条件をつけています。

*5:つまりFilterChainディレクティブを使わないと、定義されたフィルター群は実行されません

CakePHPで複数テーブルに対するトランザクションを使う場合

CakePHPトランザクションを使用する必要があったのですが、一般的に用いられている方法だと、複数のテーブルを1つのトランザクションとして更新したい場合、コントローラ内での実装がとても分かりにくくなると感じ、異なる実装方法をとってみたので、ご紹介します。

一般的な実装方法とその課題

一般的な実装方法としては、app/models/app_model.phpに、下記のようなトランザクション管理用のメソッドを追加することが多いと思います。基本的に、各モデルクラスは、AppModelクラスを継承しているため、これらのメソッドをどのモデルからも利用可能になります。

function begin() {
    $db = & ConnectionManager::getDataSource($this->useDbConfig);
    $db->begin($this);
}
function commit() {
    $db = & ConnectionManager::getDataSource($this->useDbConfig);
    $db->commit($this);
}
function rollback() {
    $db = & ConnectionManager::getDataSource($this->useDbConfig);
    $db->rollback($this);
}


しかし、この方法では、各モデルクラスのトランザクション管理用メソッドを利用するため、下記の例のようになります。

$this->User->begin();
$this->User->save($userData);
$this->Company->save($companyData);
$this->User->commit();

どうでしょうか?上記の実装を見て、Userモデルと、Companyモデルのトランザクションの関係を判断できますか?
答えは、Userモデルと、Companyモデルが同じDB接続設定(database.phpの設定)を利用していれば、同じトランザクションとなります。*1
ですが、そうは見えませんよね?これは混乱の元ですし、不具合につながる危険性もあります。

トランザクションの管理をコントローラ層に

コントローラ層でトランザクション境界を明確にする目的で、コンポーネントとして新たに「Transactionクラス」を用意します。
beginメソッドだけ抜粋して載せておきます。この実装であれば、もし、Userモデルと、Companyモデルが異なる接続先設定を参照していたとしても、基本的には問題なく動作します。*2

public function begin($models) {
    // インスタンス変数へ格納⇒commit,rollback時に利用する
    $this->models = $models;

    //各モデル毎にトランザクションを開始
    foreach ($models as $model) {
        if (!$this->_begin($model)) {
            //トランザクション開始失敗時の処理
            break;
        }
    }
}

※$this->_beginの中で、各モデルの接続先単位でトランザクション開始するように実装されるイメージ。


コントローラでの実装は以下のようになります。このように、Userモデルと、Companyモデルが同じトランザクションにいるということがハッキリします。

$this->Transaction->begin(array($this->User,$this->Company));

$user = $this->User->save($userData);
$company = $this->Company->save($companyData);

if($user !== false && $company !== false){
  /*
     * Transactionコンポーネントの内部実装としては、
     * ・両モデルが同じ接続先:1度だけcommitが実行される
     * ・両モデルが異なる接続先:2つのDBにcommitが実行される
     */
    $this->Transaction->commit();
}else{
    // commitと同様の動作
    $this->Transaction->rollback();
}

*1:CakePHPではDB接続設定(database.phpの設定)の単位でコネクションを使い回すため、こうなります。言い換えれば、Userモデルと、Companyモデルが異なる接続先設定を参照していれば、違うトランザクションとなります。

*2:異なる接続先設定の場合、厳密には2フェーズコミットとして処理しなければなりませんが、ここではそこまで厳密なコードにはなっていません。

プロセス確認に便利なコマンド

プロセス確認する時、こんな感じでgrepしたりしますよね。でも若干面倒ですね。

[root]# ps -aef | grep httpd | grep -v grep

そこで、「pgrep」コマンドを使います。

[root]# pgrep -lf httpd
1890 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start
1912 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start
1913 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start
1914 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start
1915 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start
1924 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start
16275 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start
17307 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start
19698 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start
25100 /usr/local/apache2/bin/httpd -f /usr/local/apache2/conf/httpd.conf -k start

以上です。
参考URL:pgrep