sweatshop 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +6 -0
- data/LICENSE +20 -0
- data/README.markdown +103 -0
- data/Rakefile +43 -0
- data/VERSION.yml +4 -0
- data/bin/sweatd +3 -0
- data/config/defaults.yml +8 -0
- data/config/sweatshop.yml +15 -0
- data/install.rb +20 -0
- data/lib/message_queue/base.rb +17 -0
- data/lib/message_queue/kestrel.rb +32 -0
- data/lib/message_queue/rabbit.rb +108 -0
- data/lib/sweat_shop.rb +179 -0
- data/lib/sweat_shop/daemoned.rb +405 -0
- data/lib/sweat_shop/metaid.rb +5 -0
- data/lib/sweat_shop/sweatd.rb +76 -0
- data/lib/sweat_shop/worker.rb +162 -0
- data/script/initd.sh +108 -0
- data/script/kestrel +93 -0
- data/script/kestrel.sh +93 -0
- data/script/sweatshop +17 -0
- data/test/hello_worker.rb +13 -0
- data/test/test_functional_worker.rb +72 -0
- data/test/test_helper.rb +4 -0
- data/test/test_sweatshop.rb +78 -0
- metadata +91 -0
@@ -0,0 +1,162 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/metaid'
|
2
|
+
|
3
|
+
module SweatShop
|
4
|
+
class Worker
|
5
|
+
def self.inherited(subclass)
|
6
|
+
self.workers << subclass
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.method_missing(method, *args, &block)
|
10
|
+
if method.to_s =~ /^async_(.*)/
|
11
|
+
method = $1
|
12
|
+
expected_args = instance.method(method).arity
|
13
|
+
if expected_args != args.size
|
14
|
+
raise ArgumentError.new("#{method} expects #{expected_args} arguments")
|
15
|
+
end
|
16
|
+
return instance.send(method, *args) unless config['enable']
|
17
|
+
|
18
|
+
uid = ::Digest::MD5.hexdigest("#{name}:#{method}:#{args}:#{Time.now.to_f}")
|
19
|
+
task = {:args => args, :method => method, :uid => uid, :queued_at => Time.now.to_i}
|
20
|
+
|
21
|
+
log("Putting #{uid} on #{queue_name}")
|
22
|
+
enqueue(task)
|
23
|
+
|
24
|
+
uid
|
25
|
+
elsif instance.respond_to?(method)
|
26
|
+
instance.send(method, *args)
|
27
|
+
else
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.instance
|
33
|
+
@instance ||= new
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.config
|
37
|
+
SweatShop.config
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.queue_name
|
41
|
+
@queue_name ||= self.to_s
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.delete_queue
|
45
|
+
queue.delete(queue_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.queue_size
|
49
|
+
queue.queue_size(queue_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.enqueue(task)
|
53
|
+
queue.enqueue(queue_name, task)
|
54
|
+
end
|
55
|
+
|
56
|
+
def self.dequeue
|
57
|
+
queue.dequeue(queue_name)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.confirm
|
61
|
+
queue.confirm(queue_name)
|
62
|
+
end
|
63
|
+
|
64
|
+
def self.subscribe
|
65
|
+
queue.subscribe(queue_name) do |task|
|
66
|
+
do_task(task)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.do_tasks
|
71
|
+
while task = dequeue
|
72
|
+
do_task(task)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.do_task(task)
|
77
|
+
begin
|
78
|
+
call_before_task(task)
|
79
|
+
|
80
|
+
queued_at = task[:queued_at] ? "(queued #{Time.at(task[:queued_at]).strftime('%Y/%m/%d %H:%M:%S')})" : ''
|
81
|
+
log("Dequeuing #{queue_name}::#{task[:method]} #{queued_at}")
|
82
|
+
task[:result] = instance.send(task[:method], *task[:args])
|
83
|
+
|
84
|
+
call_after_task(task)
|
85
|
+
confirm
|
86
|
+
rescue SystemExit
|
87
|
+
exit
|
88
|
+
rescue Exception => e
|
89
|
+
log("Caught Exception: #{e.message}, \n#{e.backtrace.join("\n")}")
|
90
|
+
call_exception_handler(e)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.queue
|
95
|
+
SweatShop.queue(queue_group.to_s)
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.workers
|
99
|
+
SweatShop.workers
|
100
|
+
end
|
101
|
+
|
102
|
+
def self.config
|
103
|
+
SweatShop.config
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.log(msg)
|
107
|
+
SweatShop.log(msg)
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.call_before_task(task)
|
111
|
+
superclass.call_before_task(task) if superclass.respond_to?(:call_before_task)
|
112
|
+
before_task.call(task) if before_task
|
113
|
+
end
|
114
|
+
|
115
|
+
def self.call_after_task(task)
|
116
|
+
superclass.call_after_task(task) if superclass.respond_to?(:call_after_task)
|
117
|
+
after_task.call(task) if after_task
|
118
|
+
end
|
119
|
+
|
120
|
+
def self.call_exception_handler(exception)
|
121
|
+
superclass.call_exception_handler(exception) if superclass.respond_to?(:call_exception_handler)
|
122
|
+
on_exception.call(exception) if on_exception
|
123
|
+
end
|
124
|
+
|
125
|
+
def self.before_task(&block)
|
126
|
+
if block
|
127
|
+
@before_task = block
|
128
|
+
else
|
129
|
+
@before_task
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.after_task(&block)
|
134
|
+
if block
|
135
|
+
@after_task = block
|
136
|
+
else
|
137
|
+
@after_task
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.on_exception(&block)
|
142
|
+
if block
|
143
|
+
@on_exception = block
|
144
|
+
else
|
145
|
+
@on_exception
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def self.stop
|
150
|
+
instance.stop
|
151
|
+
end
|
152
|
+
|
153
|
+
# called before we exit -- subclass can implement this method
|
154
|
+
def stop; end;
|
155
|
+
|
156
|
+
|
157
|
+
def self.queue_group(group=nil)
|
158
|
+
group ? meta_def(:_queue_group){ group } : _queue_group
|
159
|
+
end
|
160
|
+
queue_group :default
|
161
|
+
end
|
162
|
+
end
|
data/script/initd.sh
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
# chkconfig: 345 80 20
|
4
|
+
# description: Sweatshop starts the sweatd daemon
|
5
|
+
|
6
|
+
# Source function library.
|
7
|
+
if [ -f /etc/init.d/functions ] ; then
|
8
|
+
. /etc/init.d/functions
|
9
|
+
elif [ -f /etc/rc.d/init.d/functions ] ; then
|
10
|
+
. /etc/rc.d/init.d/functions
|
11
|
+
else
|
12
|
+
exit 0
|
13
|
+
fi
|
14
|
+
|
15
|
+
DAEMON=/opt/current/script/sweatshop
|
16
|
+
NAME=sweatshop
|
17
|
+
PID_DIR=/opt/current/log
|
18
|
+
LOG_FILE=$PID_DIR/sweatshop.log
|
19
|
+
INSTANCES=3
|
20
|
+
#QUEUE_GROUPS=test
|
21
|
+
export RAILS_ENV=dev
|
22
|
+
|
23
|
+
[ -f /etc/sysconfig/${NAME} ] && . /etc/sysconfig/${NAME}
|
24
|
+
|
25
|
+
|
26
|
+
# Gracefully exit if the package has been removed.
|
27
|
+
if [ ! -x $DAEMON ]; then
|
28
|
+
echo "$DAEMON does not exist"
|
29
|
+
exit 0
|
30
|
+
fi;
|
31
|
+
|
32
|
+
|
33
|
+
function start() {
|
34
|
+
num=$1
|
35
|
+
pidfile=$PID_DIR/$NAME.$num.pid
|
36
|
+
echo $"Starting ${NAME}:${num} "
|
37
|
+
if [ -z $QUEUE_GROUPS ]; then
|
38
|
+
$DAEMON -d start --log-file $LOG_FILE --pid-file $pidfile
|
39
|
+
else
|
40
|
+
$DAEMON -d start --log-file $LOG_FILE --pid-file $pidfile --groups $QUEUE_GROUPS
|
41
|
+
fi
|
42
|
+
RETVAL=$?
|
43
|
+
[ $RETVAL -eq 0 ] && success || failure
|
44
|
+
echo
|
45
|
+
return $RETVAL
|
46
|
+
}
|
47
|
+
|
48
|
+
function stop() {
|
49
|
+
num=$1
|
50
|
+
pidfile=$PID_DIR/$NAME.$num.pid
|
51
|
+
echo $"Stopping ${NAME}:${num}: "
|
52
|
+
$DAEMON -d stop --log-file $LOG_FILE --pid-file $pidfile
|
53
|
+
RETVAL=$?
|
54
|
+
[ $RETVAL -eq 0 ] && success || failure
|
55
|
+
echo
|
56
|
+
return $RETVAL
|
57
|
+
}
|
58
|
+
|
59
|
+
function reload() {
|
60
|
+
num=$1
|
61
|
+
pidfile=$PID_DIR/$NAME.$num.pid
|
62
|
+
echo $"Reloading ${NAME}:${num}: "
|
63
|
+
$DAEMON -d reload --log-file $LOG_FILE --pid-file $pidfile
|
64
|
+
RETVAL=$?
|
65
|
+
[ $RETVAL -eq 0 ] && success || failure
|
66
|
+
echo
|
67
|
+
return $RETVAL
|
68
|
+
}
|
69
|
+
|
70
|
+
function zap() {
|
71
|
+
num=$1
|
72
|
+
pidfile=$PID_DIR/$NAME.$num.pid
|
73
|
+
rm -f $pidfile
|
74
|
+
}
|
75
|
+
|
76
|
+
function doAll() {
|
77
|
+
func=$1
|
78
|
+
ii=0
|
79
|
+
while [ "$ii" -lt $INSTANCES ] ; do
|
80
|
+
eval "$func $(($ii))"
|
81
|
+
ii=$(($ii + 1))
|
82
|
+
done
|
83
|
+
}
|
84
|
+
|
85
|
+
case "$1" in
|
86
|
+
start)
|
87
|
+
doAll start
|
88
|
+
;;
|
89
|
+
stop)
|
90
|
+
doAll stop
|
91
|
+
;;
|
92
|
+
restart)
|
93
|
+
doAll stop
|
94
|
+
sleep 1
|
95
|
+
doAll start
|
96
|
+
;;
|
97
|
+
reload)
|
98
|
+
doAll reload
|
99
|
+
;;
|
100
|
+
zap)
|
101
|
+
doAll zap
|
102
|
+
;;
|
103
|
+
*)
|
104
|
+
echo "Usage: $0 {start|stop|restart|reload|zap}"
|
105
|
+
exit 1
|
106
|
+
esac
|
107
|
+
|
108
|
+
exit $RETVAL
|
data/script/kestrel
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
#
|
3
|
+
# chkconfig: 345 80 20
|
4
|
+
# description: kestrel is a light-weight queue written in scala
|
5
|
+
#
|
6
|
+
|
7
|
+
# Source function library.
|
8
|
+
if [ -f /etc/init.d/functions ] ; then
|
9
|
+
. /etc/init.d/functions
|
10
|
+
elif [ -f /etc/rc.d/init.d/functions ] ; then
|
11
|
+
. /etc/rc.d/init.d/functions
|
12
|
+
else
|
13
|
+
exit 0
|
14
|
+
fi
|
15
|
+
|
16
|
+
prog=kestrel
|
17
|
+
USER=daemon
|
18
|
+
KESTREL_HOME=/opt/kestrel
|
19
|
+
VERSION=1.0
|
20
|
+
JAR=$KESTREL_HOME/kestrel-$VERSION.jar
|
21
|
+
|
22
|
+
if [ ! -r $JAR ]; then
|
23
|
+
echo "FAIL"
|
24
|
+
echo "*** jar missing - not starting"
|
25
|
+
exit 1
|
26
|
+
fi
|
27
|
+
|
28
|
+
PIDFILE=/var/run/${prog}.pid
|
29
|
+
LOCKFILE=/var/lock/subsys/$prog
|
30
|
+
|
31
|
+
HEAP_OPTS="-Xmx2048m -Xms1024m -XX:NewSize=256m"
|
32
|
+
JAVA_OPTS="-server -verbosegc -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC -XX:+UseParNewGC $HEAP_OPTS"
|
33
|
+
|
34
|
+
start() {
|
35
|
+
echo -n $"Starting $prog: "
|
36
|
+
java $JAVA_OPTS -jar $JAR > /var/log/$prog-startup.log 2>&1 &
|
37
|
+
RETVAL=$?
|
38
|
+
if [ $RETVAL -eq 0 ]; then
|
39
|
+
echo $! > $PIDFILE
|
40
|
+
success $"$prog startup"
|
41
|
+
touch $LOCKFILE
|
42
|
+
else
|
43
|
+
failure $"$prog startup"
|
44
|
+
fi
|
45
|
+
echo
|
46
|
+
return $RETVAL;
|
47
|
+
}
|
48
|
+
|
49
|
+
stop() {
|
50
|
+
echo -n $"Stopping $prog: "
|
51
|
+
if [ -f $PIDFILE ]; then
|
52
|
+
killproc -p $PIDFILE $prog
|
53
|
+
RETVAL=$?
|
54
|
+
if [ $RETVAL -eq 0 ]; then
|
55
|
+
rm -f $LOCKFILE
|
56
|
+
rm -f $PIDFILE
|
57
|
+
fi;
|
58
|
+
else
|
59
|
+
RETVAL=1
|
60
|
+
failure;
|
61
|
+
fi
|
62
|
+
echo
|
63
|
+
return $RETVAL;
|
64
|
+
}
|
65
|
+
|
66
|
+
|
67
|
+
case "$1" in
|
68
|
+
start)
|
69
|
+
start
|
70
|
+
;;
|
71
|
+
|
72
|
+
stop)
|
73
|
+
stop
|
74
|
+
;;
|
75
|
+
|
76
|
+
restart)
|
77
|
+
stop
|
78
|
+
start
|
79
|
+
;;
|
80
|
+
|
81
|
+
condrestart)
|
82
|
+
if [ -f $LOCKFILE ]; then
|
83
|
+
stop
|
84
|
+
start
|
85
|
+
fi
|
86
|
+
;;
|
87
|
+
|
88
|
+
*)
|
89
|
+
echo $"Usage: $0 {start|stop|restart|condrestart}"
|
90
|
+
exit 1
|
91
|
+
esac
|
92
|
+
|
93
|
+
exit $RETVAL
|
data/script/kestrel.sh
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
#
|
3
|
+
# chkconfig: 345 80 20
|
4
|
+
# description: kestrel is a light-weight queue written in scala
|
5
|
+
#
|
6
|
+
|
7
|
+
# Source function library.
|
8
|
+
if [ -f /etc/init.d/functions ] ; then
|
9
|
+
. /etc/init.d/functions
|
10
|
+
elif [ -f /etc/rc.d/init.d/functions ] ; then
|
11
|
+
. /etc/rc.d/init.d/functions
|
12
|
+
else
|
13
|
+
exit 0
|
14
|
+
fi
|
15
|
+
|
16
|
+
prog=kestrel
|
17
|
+
USER=daemon
|
18
|
+
KESTREL_HOME=/opt/kestrel
|
19
|
+
VERSION=1.0
|
20
|
+
JAR=$KESTREL_HOME/kestrel-$VERSION.jar
|
21
|
+
|
22
|
+
if [ ! -r $JAR ]; then
|
23
|
+
echo "FAIL"
|
24
|
+
echo "*** jar missing - not starting"
|
25
|
+
exit 1
|
26
|
+
fi
|
27
|
+
|
28
|
+
PIDFILE=/var/run/${prog}.pid
|
29
|
+
LOCKFILE=/var/lock/subsys/$prog
|
30
|
+
|
31
|
+
HEAP_OPTS="-Xmx2048m -Xms1024m -XX:NewSize=256m"
|
32
|
+
JAVA_OPTS="-server -verbosegc -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC -XX:+UseParNewGC $HEAP_OPTS"
|
33
|
+
|
34
|
+
start() {
|
35
|
+
echo -n $"Starting $prog: "
|
36
|
+
java $JAVA_OPTS -jar $JAR > /var/log/$prog-startup.log 2>&1 &
|
37
|
+
RETVAL=$?
|
38
|
+
if [ $RETVAL -eq 0 ]; then
|
39
|
+
echo $! > $PIDFILE
|
40
|
+
success $"$prog startup"
|
41
|
+
touch $LOCKFILE
|
42
|
+
else
|
43
|
+
failure $"$prog startup"
|
44
|
+
fi
|
45
|
+
echo
|
46
|
+
return $RETVAL;
|
47
|
+
}
|
48
|
+
|
49
|
+
stop() {
|
50
|
+
echo -n $"Stopping $prog: "
|
51
|
+
if [ -f $PIDFILE ]; then
|
52
|
+
killproc -p $PIDFILE $prog
|
53
|
+
RETVAL=$?
|
54
|
+
if [ $RETVAL -eq 0 ]; then
|
55
|
+
rm -f $LOCKFILE
|
56
|
+
rm -f $PIDFILE
|
57
|
+
fi;
|
58
|
+
else
|
59
|
+
RETVAL=1
|
60
|
+
failure;
|
61
|
+
fi
|
62
|
+
echo
|
63
|
+
return $RETVAL;
|
64
|
+
}
|
65
|
+
|
66
|
+
|
67
|
+
case "$1" in
|
68
|
+
start)
|
69
|
+
start
|
70
|
+
;;
|
71
|
+
|
72
|
+
stop)
|
73
|
+
stop
|
74
|
+
;;
|
75
|
+
|
76
|
+
restart)
|
77
|
+
stop
|
78
|
+
start
|
79
|
+
;;
|
80
|
+
|
81
|
+
condrestart)
|
82
|
+
if [ -f $LOCKFILE ]; then
|
83
|
+
stop
|
84
|
+
start
|
85
|
+
fi
|
86
|
+
;;
|
87
|
+
|
88
|
+
*)
|
89
|
+
echo $"Usage: $0 {start|stop|restart|condrestart}"
|
90
|
+
exit 1
|
91
|
+
esac
|
92
|
+
|
93
|
+
exit $RETVAL
|