さくらインターネットさんが値段を下げてにわかに活気づく VPS。
VPS のよいところは、root 権限があることで、もう Web サーバやら PHP やら MySQL やらの束縛からは解放されて、好きな言語や環境でインターネットのアプリケーションがつくれる環境が整いました。 🙂
たぶん VPS で動かして一番面白いのは、デーモンとして常駐してリアルタイムで処理を行うアプリケーション。 じゃーってことで、Groovy でやってみることにしましょう。
まずは UNIX Daemon のつくりかた。 C でやれば fork して tty 切り離してみたいな感じになるとおもいますが、ここは Groovy ってことで、JVM 上のアプリを daemon 扱いにしてシグナルをとばしてくれる Apache Commons の commons-daemon を使うとよいです。
Daemon : Java based daemons or services
Daemon is made of 2 parts. One written in C that makes the interface to the operating system and the other in Java that provides the Daemon API.
commons-daemon には jsvc という UNIX Daemon と Java を取り持つバイナリのソースが入っています。 まずはこれを VPS の環境なりでコンパイルします。 Java のホームディレクトリを指定して configure をかけるのがポイントです。
src/unix$ ./configure --with-java=/usr/lib/jvm/java-6-sun
make すると jsvc のバイナリができます。
次に Java でデーモン用のソースをかきます。 ここでは Groovy で。
org.apache.commons.daemon.Daemon を implements してシグナルハンドラと結びつく規定のインターフェースを実装してあげればOKです。 サービスクラスはスレッドにして、ちゃんと途中でとまるようにつくる感じになるでしょう。
ここではおなじみ twitter4j のストリーミング API をサービスクラスにしています。 VPS とは関係ないですが、ストリーミング API でうけたメッセージを Ubuntu の NotifyOSD で通知するサンプルです。 (画面ならデーモンじゃなくて UI スレッドでやれって感じですが、サンプルということで…)
package net.maple4ever.daemon
import java.security.MessageDigest
import org.apache.commons.daemon.*
import org.apache.log4j.Logger
import org.gnome.gtk.Gtk
import org.gnome.gdk.Pixbuf
import org.gnome.notify.Notify
import org.gnome.notify.Notification
import twitter4j.Status
import twitter4j.TwitterFactory
import twitter4j.TwitterStream
import twitter4j.TwitterStreamFactory
import twitter4j.User
import twitter4j.UserStreamAdapter
import twitter4j.conf.ConfigurationBuilder
class TwitterDaemon implements Daemon {
private static TwitterDaemon daemon = new TwitterDaemon()
private static Logger logger =
Logger.getLogger(TwitterDaemon.class)
private TwitterStream stream = null
// twitter oAuth 設定(取得して入れます)
def consumer = ""
def consumerSecret = ""
def accessToken = ""
def accessTokenSecret = ""
@Override
public void init(DaemonContext arg0)
throws DaemonInitException, Exception {
// twitter 認証設定
def builder = new ConfigurationBuilder()
builder.setOAuthConsumerKey(consumer)
builder.setOAuthConsumerSecret(consumerSecret)
builder.setOAuthAccessToken(accessToken)
builder.setOAuthAccessTokenSecret(accessTokenSecret)
def config = builder.build()
// GTK 初期化
Gtk.init([] as String[])
Notify.init("notify.groovy")
// Strinming API 取得
def twitter = new TwitterFactory(config).getInstance()
stream =
new TwitterStreamFactory(config).getInstance(
twitter.getOAuthAccessToken())
// Strinming API イベント登録
stream.addListener(new UserStreamAdapter() {
@Override
public void onStatus(Status status) {
User user = status.getUser()
def url = user.getProfileImageURL()
def screenname = user.getScreenName()
def text = status.getText()
try {
// twitter アイコン取得
MessageDigest md5 =
MessageDigest.getInstance("MD5")
def md5str
md5.with {
md5str = new BigInteger(
1,
digest(new File(url.file).name.bytes))
.toString(16).padLeft(32, '0')
}
def filename = "/tmp/" + md5str
File file = new File(filename)
if(!file.exists()) {
file << url.getBytes()
}
def pixbuf = new Pixbuf(
filename, 40, 40, true)
// NotifyOSD 通知
def notify = new Notification(
"@${screenname}", "${text}", null)
notify.setIcon(pixbuf)
notify.show()
} catch (e) {
logger.error(e.message)
}
}
})
}
@Override
public void start() throws Exception {
stream.user()
}
@Override
public void stop() throws Exception {
stream.cleanUp()
}
@Override
public void destroy() {
}
static main(args) {
daemon.init(null)
daemon.start()
}
}
# こんなの動かす人いないと思いますが、GTK-Java のライブラリ jar は sudo apt-get install libjava-gnome-java で /usr/share/java かその辺に入ると思います。
デーモンではなく、通常実行でも動作させてデバッグしやすいように static main(args) もいれています。
で、できたら次のように jsvc にクラスを渡してデーモン化してもらいます。
/opt/twitter-daemon/bin/jsvc-ubuntu \
-pidfile /opt/twitter-daemon/bin/TwitterDaemon.pid \
-user hiromasa \
-home /usr/lib/jvm/java-6-sun/ \
-cp /opt/twitter-daemon/lib/*:/opt/twitter-daemon/classes \
-Dlog.home=/opt/twitter-daemon/logs/TwitterDaemon.log \
-Dstream.user.repliesAll=false \
net.maple4ever.daemon.TwitterDaemon
次のように Java のプロセスが 2つ常駐すれば成功です。
hiromasa 6975 1 0 23:09 ? 00:00:00 jsvc.exec -pidfile
hiromasa 6976 6975 17 23:09 ? 00:00:01 jsvc.exec -pidfile
NotifyOSD で twitter の投稿がリアルタイムに通知されてきます。 🙂
停止は以下のようにします。 start / stop/ restart 用のシェルをつくることになるでしょう。
/opt/twitter-daemon/bin/jsvc-ubuntu \
-stop \
-pidfile /opt/twitter-daemon/bin/TwitterDaemon.pid \
net.maple4ever.daemon.TwitterDaemon
ここではソースのサンプルとして画面通知にしてしまっていますが、たとえば twitter 関係で VPS で動かすようなものなら、 bot 的なものも cron とかの無理な方法をとることなく簡単に扱いやすいアプリケーションが作れると思います。
常時インターネットにつながっている VPS でリアルタイム処理ができるのは、いろいろ夢が広がりますね。
GroovyClassLoader をうまくつかって Java と Groovy のインターフェースをつくってあげれば、スクリプトテキストファイルのまま、コンパイルすることなくデーモンをつくるようなことも可能です。
え、最後のそれ、らい子ちゃんを載せたかっただけだろって、、、。はい。 orz