gearmandをソースからインストールして、Cライブラリのlibgearmanが使えるようになった。

これでC言語でworkerを作ってRubyのclientから呼び出せる。環境はUbuntu9.04とgearmand0.11


■Cでworkerを書く
str_reverseというアビリティを持つworkerを作る。
ほぼAPIドキュメントのままだが、jobの引数を受け取るのと、値を返せるようにがんばった。ジョブ失敗した時とかのエラー処理全然書いてない。たぶんenum gearman_return_tを返せばいいんだろうけど

strreverse-worker.c

// 文字列をreverseして返すworker
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libgearman/gearman.h>

void *job_str_reverse(gearman_job_st *job, void *cb_arg, size_t *result_size,
       gearman_return_t *ret_ptr)
{
  char *str = (char *)gearman_job_workload(job);
  int len = strlen(str);
  printf("str:%s  length:%d\n", str, len);

  char reverse[len];
  for(int i = 0; i < len; i++){
    reverse[i] = str[len-i-1]; // 文字列を逆にする
  }

  char *result = strdup(reverse); // 結果の文字列はコピーしてポインタで返す
  *result_size= gearman_job_workload_size(job);
  *ret_ptr= GEARMAN_SUCCESS;
  return result;
}


int main(int argc, char *argv[])
{
  gearman_return_t ret;
  gearman_worker_st worker;

  gearman_worker_create(&worker);
  gearman_worker_add_server(&worker, "127.0.0.1", 7003);
  gearman_worker_add_function(&worker, "str_reverse", 0, job_str_reverse, NULL);
  
  while(1) gearman_worker_work(&worker); // ジョブ登録したらループで待つ

  gearman_worker_free(&worker);
  return 0;
}


Makefile
# Linux用Makefile
SRC = strreverse-worker.c
DST = strreverse-worker

prefix=/usr/local
INCPATH=$(prefix)/include
LIBPATH=$(prefix)/lib

GEAR_LIBS=$(LIBPATH)/libgearman.a

all:
g++ -O $(SRC) -o $(DST) -I$(INCPATH)/libgearman -L. -L$(LIBPATH) $(GEAR_LIBS)
makeするとstrreverse-workerができる。


■Rubyでclientを書く
xing-gearman-serverを使うといい

client書く。実行時引数を一つずつstr_reverseに登録するclient。
strreverse-client.rb
#!/usr/bin/env ruby
require 'rubygems'
require 'gearman'

c = Gearman::Client.new(['localhost:7003'])
taskset = Gearman::TaskSet.new(c)

ARGV.each{|str|
  puts "add task #{str}"
  task = Gearman::Task.new('str_reverse', str)
  task.on_complete{|result|
    puts "return: #{str} => #{result}" # 文字列が逆になって返ってくる
  }
  taskset.add_task(task)
}
taskset.wait(100) # wait 100(sec)


■動かしてみる
worker動かす
./strreverse-worker

clientから3つ文字列登録
ruby strreverse-client.rb hello konitiwa asdfhujiko

すると文字列返ってくる
add task hello
add task konitiwa
return: hello => olleh
add task asdfhujiko
return: konitiwa => awitinok
return: asdfhujiko => okijuhfdsa

worker側の標準出力はこうなってた
str:hello  length:5
str:konitiwa length:8
str:asdfhujiko length:10


workerを3つバックグラウンドで起動しておく
./strreverse-worker&
./strreverse-worker&
./strreverse-worker&


凄い勢いで処理されてるので非同期になってるのかよくわからない
ruby strreverse-client.rb hello konitiwa asdfhujiko aaiiaaiiaaii hogehogehogehoge mmmasdffajkl23rwdfv ahsdga9sd8uf9p8u nbjkasdoif98pu
add task hello
add task konitiwa
return: hello => olleh
add task asdfhujiko
return: konitiwa => awitinok
add task aaiiaaiiaaii
return: asdfhujiko => okijuhfdsa
add task hogehogehogehoge
return: aaiiaaiiaaii => iiaaiiaaiiaa
add task mmmasdffajkl23rwdfv
return: hogehogehogehoge => egohegohegohegoh
add task ahsdga9sd8uf9p8u
return: mmmasdffajkl23rwdfv => vfdwr32lkjaffdsammm
add task nbjkasdoif98pu
return: ahsdga9sd8uf9p8u => vfdu8p9fu8ds9agd
return: nbjkasdoif98pu => vfdu8up89fiods