しょんぼり技術メモ

まいにちがしょんぼり

Rindaで遊ぶ

LindaのRuby実装、Rindaを使うことになったのでそのメモ。Rindaすげーよ!

Rindaについては

http://www.druby.org/ilikeruby/d208.htmlをご覧ください。非常に丁寧な解説があります。

TupleSpaceデーモンを作ってみる

いきなりかよ、って感じですが、今回作ろうとしてるシステムでは、どこかに「常時走りっぱなしになってるTupleSpace保持プロセス」が必要だったので…

tsd.rb (TupleSpaceDaemon)を次のようにして書きます。手抜き。

#!/usr/bin/ruby
require 'rinda/tuplespace'

drb_host = ARGV.shift
drb_host ||= "127.0.0.1"

drb_port = ARGV.shift
drb_port ||= "6456"

pid_filepath = ARGV.shift
pid_filepath ||= "/usr/local/tsd/pid"
pid_file = File.open(pid_filepath, 'w')

$druby_listen="#{drb_host}:#{drb_port}"

fork{
  Process::setsid
  pid = fork{
    STDIN.reopen("/dev/null",  "r+")
    STDOUT.reopen("/dev/null", "w")
    STDERR.reopen("/dev/null", "w")
    ts = Rinda::TupleSpace.new
    DRb.start_service("druby://#{$druby_listen}", ts)
    DRb.thread.join
    sleep
  }
  pid_file.puts pid
  pid_file.close
}

で、rc.dのデーモンとして登録したいので、次のようなシェルスクリプト tsd.sh を作ります。squidのものをパクってます。

#!/bin/bash
# tsd           This shell script takes care of starting and stopping
#               Tuple-Space daemon
#
# chkconfig: - 90 25
# description: This shell script takes care of starting and stopping \
#              Tuple-Space daemon
# pidfile: /usr/local/tsd/tsd.pid
# config: /usr/local/tsd/tsd.conf


. /etc/rc.d/init.d/functions

prog="tsd"

CONF="/usr/local/tsd/tsd.conf"
LTSD="/usr/local/tsd/tsd.rb"
PID="/usr/local/tsd/tsd.pid"

# import config
. $CONF

RETVAL=0

start() {
    # check ltsd is already working
    if [ -f $PID ] ; then
        # pid file exists. check the process is working.
        ps -p `cat $PID` >/dev/null 2>&1
        if [ $? = 0 ] ; then
            # process is still working!
            echo "ltsd is still working. aborting..." 1>&2
            exit 1
        fi
        # pid file is invalid now.
        rm -f $PID
    fi

    echo -n $"Starting $prog: "
    $LTSD $LISTEN $PORT $PID
    RETVAL=$?
    [ $RETVAL -eq 0 ] && echo_success
    [ $RETVAL -ne 0 ] && echo_failure
    echo
    return $RETVAL
}

stop() {
    # check the pid file exists
    if [ ! -f $PID ] ; then
        # pid file is missing
        echo "pid file is not found. aborting..." 1>&2
        return 3
    fi

    echo -n $"Stopping $prog: "
    kill `cat $PID` >/dev/null 2>&1
    RETVAL=$?
    [ $RETVAL -eq 0 ] && rm -f $PID
    [ $RETVAL -eq 0 ] && echo_success
    [ $RETVAL -ne 0 ] && echo_failure
    echo
    return $RETVAL
}

case "$1" in
start)
    start
    ;;

stop)
    stop
    ;;

restart)
    stop
    start
    ;;

probe)
    exit 0
    ;;

*)
    echo $"Usage: $0 {start|stop|restart}"
    exit 2
esac

exit $?

あとは

# ln -s tsd.sh /etc/rc.d/init.d/tsd
# chkconfig --add tsd
# service tsd start

で動くはずです。たぶん。

デーモン動作確認

irbでちゃちゃっとやりましょう。

# irb
irb(main):001:0> require 'drb'
=> true
irb(main):002:0> ts = DRbObject.new_with_uri('druby://127.0.0.1:6456')
=> #<DRb::DRbObject:0xb7f16b68 @ref=nil, @uri="druby://127.0.0.1:6456">
irb(main):003:0> ts.write(["take-test",1])
=> #<DRb::DRbObject:0xb7bc88f8 @ref=-604674008, @uri="druby://127.0.0.1:6456">
irb(main):004:0> ts.take(["take-test",nil])
=> ["take-test", 1]
irb(main):005:0> ts.read_all(["take-test",nil])
=> []
irb(main):006:0> 1.upto(10){|i| ts.write(["take-test", i]) }
=> 1
irb(main):007:0> ts.read_all(["take-test",nil])
=> [["take-test", 1], ["take-test", 2], ["take-test", 3], ["take-test", 4], ["take-test", 5], ["take-test", 6], ["take-test", 7], ["take-test", 8], ["take-test", 9], ["take-test", 10]]
irb(main):008:0> ts.read_all(["take-test",nil]).each{|tuple| puts tuple[1] }
1
2
3
4
5
6
7
8
9
10
=> [["take-test", 1], ["take-test", 2], ["take-test", 3], ["take-test", 4], ["take-test", 5], ["take-test", 6], ["take-test", 7], ["take-test", 8], ["take-test", 9], ["take-test", 10]]
irb(main):009:0> exit

ね、簡単でしょ?