fileq 0.1.3

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/lib/job.rb ADDED
@@ -0,0 +1,181 @@
1
+ # FileQ
2
+ require 'yaml'
3
+ #require 'fcntl'
4
+
5
+ module Xxeo
6
+
7
+ class WrongStatus < StandardError; end
8
+
9
+ class Job
10
+
11
+ def Job.create(queue, name, path, status)
12
+ raise unless queue.class == Xxeo::FileQ
13
+
14
+ Job.new(queue, name, path, status)
15
+ end
16
+
17
+ def name
18
+ return @name
19
+ end
20
+
21
+ def data
22
+ raise WrongStatus.new('cannot disown a non-owned job') unless @own
23
+ data = nil
24
+ File.open(@path + '/data') { |f| data = f.read }
25
+ return data
26
+ end
27
+
28
+ def owning_pid
29
+ @owning_pid
30
+ end
31
+
32
+ def is_file?
33
+ meta = read_meta
34
+ raise unless meta
35
+ return meta[:XX_type] == 'file'
36
+ end
37
+
38
+ def original_pathname
39
+ meta = read_meta
40
+ raise unless meta
41
+ return meta[:XX_original_file_name] if meta[:XX_type] == 'file'
42
+ return nil
43
+ end
44
+
45
+ def read_meta
46
+ return @fq.meta_for_job(@name)
47
+ end
48
+
49
+ def own?
50
+ @own
51
+ end
52
+
53
+ def disown
54
+ raise WrongStatus.new('cannot disown a non-owned job') unless @own
55
+ @own = false
56
+ File.unlink(@path + '/pid')
57
+ @owning_pid = nil
58
+ end
59
+
60
+ def set_status(path, status)
61
+ @path = path
62
+ @status = status
63
+ end
64
+
65
+ def pull
66
+ return self if @own
67
+
68
+ # This is kinda wonky, obviously
69
+ # since the @fq already called set_as_active on an object
70
+ if @fq.pull_job(@name)
71
+ @own = true
72
+ @path = @fq.run_que_path + @name
73
+ @status = ST_RUN
74
+ @owning_pid = $$
75
+ return self
76
+ end
77
+ return nil
78
+ end
79
+
80
+ def set_as_active
81
+ @own = true
82
+ # Record
83
+ @path = @fq.run_que_path + @name
84
+ @status = ST_RUN
85
+ File.open(@path + '/pid', "w") { |f| f.write("#{$$}\n") }
86
+ @owning_pid = $$
87
+ end
88
+
89
+ # TODO: this could be stale
90
+ def status
91
+ return @status if @own
92
+ return @fq.status(@name)
93
+ end
94
+
95
+ # TODO: this could be stale
96
+ def status_mesg
97
+ return @status_mesg if @own
98
+ return @fq.status_mesg_for_job(@name)
99
+ end
100
+
101
+ # The @fq locks and then does a callback here
102
+ def callback_status_mesg
103
+ data = ''
104
+ File.open(@path + '/status', "r") do
105
+ |f|
106
+ data = f.read
107
+ end
108
+ return data
109
+ end
110
+
111
+ def status_mesg=(msg)
112
+ raise WrongStatus.new('cannot set status mesg on non-owned job') unless @own
113
+ @status_mesg = msg
114
+ File.open(@path + '/status', "w") { |f| f.write(msg) }
115
+ end
116
+
117
+ def status_all
118
+ return [@status, @owning_pid, status_mesg]
119
+ end
120
+
121
+ def log(msg)
122
+ raise WrongStatus.new('cannot log on non-owned job') unless @own
123
+ File.open(@path + '/log', "a") do
124
+ |f|
125
+ log_msg = Time.now.to_s + " == " + msg + "\n"
126
+ f.write(log_msg)
127
+ @logs << log_msg
128
+ end
129
+ end
130
+
131
+ def read_log
132
+ return @logs.join('') if @own
133
+ return @fq.status_logs_for_job(@name)
134
+ end
135
+
136
+ # The @fq locks and then does a callback here
137
+ def callback_read_logs
138
+ data = ''
139
+ File.open(@path + '/log', "r") do
140
+ |f|
141
+ data = f.read
142
+ end
143
+ return data
144
+ end
145
+
146
+ def mark_done
147
+ raise WrongStatus.new('cannot mark job as done on non-owned job') unless @own
148
+ status_mesg = "finishing"
149
+ @fq.mark_job_done(self)
150
+ end
151
+
152
+ def mark_error
153
+ raise WrongStatus.new('cannot mark job as error on non-owned job') unless @own
154
+ status_mesg = "finishing"
155
+ @fq.mark_job_error(self)
156
+ end
157
+
158
+ def reinsert
159
+ raise WrongStatus.new('cannot reinsert on non-owned job') unless @own
160
+ status_mesg = "reinserting"
161
+ log("reinserting job")
162
+ @fq.reinsert_job(self)
163
+ end
164
+
165
+ private
166
+
167
+ def initialize(queue, name, path, status)
168
+ @fq = queue
169
+ @name = name
170
+ @path = path
171
+ @own = false
172
+ @owning_pid = nil
173
+ @status = status
174
+ @status_mesg = ''
175
+ @logs = []
176
+ end
177
+
178
+ end
179
+
180
+ end
181
+
data/lib/lockfile.rb ADDED
@@ -0,0 +1,88 @@
1
+ # LockFile`
2
+ #
3
+ # This assumes that a single threaded process is using
4
+ # this object to use a file on disk as a lock/mutex
5
+ # for synchronization.
6
+ #
7
+ # class User < ActiveRecord::Base
8
+ # acts_as_audited
9
+ # end
10
+ #
11
+ # See <tt>CollectiveIdea::Acts::Audited::ClassMethods#acts_as_audited</tt>
12
+ # for configuration options
13
+ #http://rails.techno-weenie.net/tip/2005/11/19/validate_your_forms_with_a_table_less_model
14
+ #http://lists.vanruby.com/pipermail/discuss/2006-January/000050.html
15
+
16
+ # class Order < InActiveRecord
17
+ # column :id, :integer
18
+ # column :name, :string
19
+ # column :address, :string
20
+ # ...
21
+ # validates_presence_of :name, :address ....
22
+ #
23
+ #
24
+
25
+ require 'fcntl'
26
+
27
+ module Xxeo
28
+
29
+ class LockFile
30
+
31
+ def initialize(pathname, options = {})
32
+ options[:env] ||= 'development'
33
+
34
+ raise "lockfile not writable" if not File.writable? pathname
35
+
36
+ @f = File.open(pathname, 'r')
37
+
38
+ raise "could not open file" if not @f
39
+
40
+ @lock_count = 0
41
+ end
42
+
43
+ # We allow a process that holds a lock to recursively
44
+ # acquire the lock, the allows the higher level programs
45
+ # to not have to keep track of the lock status
46
+ # This is becase the flock mechanism doesn't do reference
47
+ # counting.
48
+
49
+ def lock
50
+ # already locked, just increase the ref count
51
+ if @lock_count > 0
52
+ @lock_count += 1
53
+ return
54
+ end
55
+
56
+ # THIS COULD BLOCK
57
+ @f.flock(File::LOCK_EX)
58
+ @lock_count = 1
59
+ end
60
+
61
+ def unlock
62
+ if @lock_count > 1
63
+ @lock_count -= 1
64
+ return
65
+ end
66
+
67
+ if @lock_count == 1
68
+ @f.flock(File::LOCK_UN)
69
+ @lock_count -= 1
70
+ return
71
+ end
72
+
73
+ if @lock_count < 1
74
+ raise "Attempt to unlock an unlocked LockFile"
75
+ end
76
+ end
77
+
78
+ def locked?
79
+ return @lock_count > 0
80
+ end
81
+
82
+ def lock_count
83
+ return @lock_count
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,83 @@
1
+ #require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+
4
+ class FileQCreateDirTests < Test::Unit::TestCase
5
+
6
+ def setup
7
+ @fq = Xxeo::FileQ.new('test', {:dir => 'test/test_fq'})
8
+ @fq.create_queue_dirs
9
+ end
10
+
11
+ def teardown
12
+ FileUtils.rm_rf 'test/test_fq'
13
+ end
14
+
15
+ def test_create
16
+ assert(FileTest.directory?('test/test_fq'))
17
+ assert(FileTest.writable?('test/test_fq'))
18
+ assert(FileTest.readable?('test/test_fq/_lock'))
19
+ assert(FileTest.writable?('test/test_fq/_log'))
20
+ assert(FileTest.directory?('test/test_fq/_tmp'))
21
+ assert(FileTest.directory?('test/test_fq/que'))
22
+ assert(FileTest.directory?('test/test_fq/run'))
23
+ assert(FileTest.directory?('test/test_fq/pause'))
24
+ assert(FileTest.directory?('test/test_fq/done'))
25
+ assert(FileTest.directory?('test/test_fq/_err'))
26
+ end
27
+
28
+ def test_create_verify
29
+ assert(@fq.verify_store, 'Failed to verify')
30
+ assert_equal('', @fq.last_error, 'Failed to have empty error message')
31
+ end
32
+
33
+ def test_bad_lock_file
34
+ FileUtils.rm_rf('test/test_fq/_lock')
35
+ assert(! @fq.verify_store, 'Failed to verify as false')
36
+ assert_equal('bad queue dir: file \'_lock\' does not exist', @fq.last_error, 'Failed to have correct error message')
37
+ end
38
+
39
+ #TODO: test lock file writable
40
+
41
+ def test_bad_log_file
42
+ FileUtils.rm_rf('test/test_fq/_log')
43
+ assert(! @fq.verify_store, 'Failed to verify as false')
44
+ assert_equal('bad queue dir: file \'_log\' does not exist', @fq.last_error, 'Failed to have correct error message')
45
+ end
46
+
47
+ def test_bad_tmp_dir
48
+ FileUtils.rm_rf('test/test_fq/_tmp')
49
+ assert(! @fq.verify_store, 'Failed to verify as false')
50
+ assert_equal('bad queue dir: \'_tmp\' not a directory', @fq.last_error, 'Failed to have correct error message')
51
+ end
52
+
53
+ def test_bad_q_dir
54
+ FileUtils.rm_rf('test/test_fq/que')
55
+ assert(! @fq.verify_store, 'Failed to verify as false')
56
+ assert_equal('bad queue dir: \'que\' not a directory', @fq.last_error, 'Failed to have correct error message')
57
+ end
58
+
59
+ def test_bad_run_dir
60
+ FileUtils.rm_rf('test/test_fq/run')
61
+ assert(! @fq.verify_store, 'Failed to verify as false')
62
+ assert_equal('bad queue dir: \'run\' not a directory', @fq.last_error, 'Failed to have correct error message')
63
+ end
64
+
65
+ def test_bad_pause_dir
66
+ FileUtils.rm_rf('test/test_fq/pause')
67
+ assert(! @fq.verify_store, 'Failed to verify as false')
68
+ assert_equal('bad queue dir: \'pause\' not a directory', @fq.last_error, 'Failed to have correct error message')
69
+ end
70
+
71
+ def test_bad_done_dir
72
+ FileUtils.rm_rf('test/test_fq/done')
73
+ assert(! @fq.verify_store, 'Failed to verify as false')
74
+ assert_equal('bad queue dir: \'done\' not a directory', @fq.last_error, 'Failed to have correct error message')
75
+ end
76
+
77
+ def test_bad_err_dir
78
+ FileUtils.rm_rf('test/test_fq/_err')
79
+ assert(! @fq.verify_store, 'Failed to verify as false')
80
+ assert_equal('bad queue dir: \'_err\' not a directory', @fq.last_error, 'Failed to have correct error message')
81
+ end
82
+
83
+ end
@@ -0,0 +1,74 @@
1
+
2
+ class FileQFindTests < Test::Unit::TestCase
3
+
4
+ def setup
5
+ @fq = Xxeo::FileQ.new('test', {:dir => 'test/test_fq'})
6
+ @fq.create_queue_dirs
7
+
8
+ @tmp_fname1 = 'tmp_file1'
9
+ @tmp_name1 = 'test/test_fq/' + @tmp_fname1
10
+ @data1 = "blah blah1\nblah blah1\n"
11
+ File.open(@tmp_name1, "w") { |f| f.write(@data1) }
12
+
13
+ @tmp_fname2 = 'tmp_file2'
14
+ @tmp_name2 = 'test/test_fq/' + @tmp_fname2
15
+ @data2 = "blah blah2\nblah blah2\n"
16
+ File.open(@tmp_name2, "w") { |f| f.write(@data2) }
17
+
18
+ @job1 = @fq.insert_data('This is a test')
19
+ end
20
+
21
+ def teardown
22
+ FileUtils.rm_rf 'test/test_fq'
23
+ end
24
+
25
+ def test_find
26
+ assert(@fq.find_job(@job1.name))
27
+ end
28
+
29
+ def test_find_fail
30
+ assert(!@fq.find_job('dldldld'))
31
+ end
32
+
33
+ def test_find_que
34
+ job = @fq.find_job(@job1.name)
35
+ assert(job)
36
+ assert_equal(job.status, Xxeo::ST_QUEUED)
37
+ assert_equal(false, job.own?)
38
+ end
39
+
40
+ def test_find_run
41
+ @job1.pull
42
+ job = @fq.find_job(@job1.name)
43
+ assert(job)
44
+ assert_equal(job.status, Xxeo::ST_RUN)
45
+ assert_equal(false, job.own?)
46
+ end
47
+
48
+ def test_find_and_run
49
+ job = @fq.find_job(@job1.name)
50
+ assert(job)
51
+ assert(job.pull, @fq.read_log)
52
+ assert_equal(job.status, Xxeo::ST_RUN)
53
+ assert_equal(true, job.own?)
54
+ end
55
+
56
+ def test_find_done
57
+ @job1.pull
58
+ @job1.mark_done
59
+ job = @fq.find_job(@job1.name)
60
+ assert(job)
61
+ assert_equal(job.status, Xxeo::ST_DONE)
62
+ assert_equal(false, job.own?)
63
+ end
64
+
65
+ def test_find_err
66
+ @job1.pull
67
+ @job1.mark_error
68
+ job = @fq.find_job(@job1.name)
69
+ assert(job)
70
+ assert_equal(job.status, Xxeo::ST_ERROR)
71
+ assert_equal(false, job.own?)
72
+ end
73
+
74
+ end
@@ -0,0 +1,33 @@
1
+ #require File.expand_path(File.join(File.dirname(__FILE__), 'test_helper'))
2
+
3
+ class FileQFirstTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ FileUtils.mkdir 'test/test_fq'
7
+ FileUtils.touch 'test/test_fq/_lock'
8
+ FileUtils.touch 'test/test_fq/_log'
9
+ FileUtils.mkdir 'test/test_fq/_tmp'
10
+ FileUtils.mkdir 'test/test_fq/que'
11
+ FileUtils.mkdir 'test/test_fq/run'
12
+ FileUtils.mkdir 'test/test_fq/pause'
13
+ FileUtils.mkdir 'test/test_fq/done'
14
+ FileUtils.mkdir 'test/test_fq/_err'
15
+ File.open('test/test_fq/lock', "w") { |f| f.close }
16
+ end
17
+
18
+ def teardown
19
+ FileUtils.rm_rf 'test/test_fq'
20
+ end
21
+
22
+ def test_instantiate
23
+ fq = Xxeo::FileQ.new('test', { :dir => 'test/test_fq'})
24
+ assert_not_nil(fq)
25
+ end
26
+
27
+ def test_instantiate_verify
28
+ fq = Xxeo::FileQ.new('test', { :dir => 'test/test_fq'})
29
+ assert_not_nil(fq)
30
+ assert(fq.verify_store)
31
+ end
32
+
33
+ end