background_queue 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/.rvmrc +48 -0
  4. data/Gemfile +19 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +69 -0
  7. data/Rakefile +42 -0
  8. data/TODO +2 -0
  9. data/VERSION +1 -0
  10. data/background_queue.gemspec +158 -0
  11. data/bin/bg_queue +26 -0
  12. data/lib/background_queue.rb +8 -0
  13. data/lib/background_queue/client.rb +96 -0
  14. data/lib/background_queue/client_lib/command.rb +36 -0
  15. data/lib/background_queue/client_lib/config.rb +109 -0
  16. data/lib/background_queue/client_lib/connection.rb +105 -0
  17. data/lib/background_queue/client_lib/job_handle.rb +19 -0
  18. data/lib/background_queue/command.rb +49 -0
  19. data/lib/background_queue/config.rb +118 -0
  20. data/lib/background_queue/server_lib/balanced_queue.rb +108 -0
  21. data/lib/background_queue/server_lib/config.rb +339 -0
  22. data/lib/background_queue/server_lib/event_connection.rb +133 -0
  23. data/lib/background_queue/server_lib/event_server.rb +35 -0
  24. data/lib/background_queue/server_lib/job.rb +252 -0
  25. data/lib/background_queue/server_lib/job_registry.rb +30 -0
  26. data/lib/background_queue/server_lib/lru.rb +193 -0
  27. data/lib/background_queue/server_lib/owner.rb +54 -0
  28. data/lib/background_queue/server_lib/priority_queue.rb +156 -0
  29. data/lib/background_queue/server_lib/queue_registry.rb +123 -0
  30. data/lib/background_queue/server_lib/server.rb +314 -0
  31. data/lib/background_queue/server_lib/sorted_workers.rb +52 -0
  32. data/lib/background_queue/server_lib/task.rb +79 -0
  33. data/lib/background_queue/server_lib/task_registry.rb +51 -0
  34. data/lib/background_queue/server_lib/thread_manager.rb +121 -0
  35. data/lib/background_queue/server_lib/worker.rb +18 -0
  36. data/lib/background_queue/server_lib/worker_balancer.rb +97 -0
  37. data/lib/background_queue/server_lib/worker_client.rb +94 -0
  38. data/lib/background_queue/server_lib/worker_thread.rb +70 -0
  39. data/lib/background_queue/utils.rb +40 -0
  40. data/lib/background_queue/worker/base.rb +46 -0
  41. data/lib/background_queue/worker/calling.rb +59 -0
  42. data/lib/background_queue/worker/config.rb +35 -0
  43. data/lib/background_queue/worker/environment.rb +70 -0
  44. data/lib/background_queue/worker/worker_loader.rb +94 -0
  45. data/lib/background_queue_server.rb +21 -0
  46. data/lib/background_queue_worker.rb +5 -0
  47. data/spec/background_queue/client_lib/command_spec.rb +75 -0
  48. data/spec/background_queue/client_lib/config_spec.rb +156 -0
  49. data/spec/background_queue/client_lib/connection_spec.rb +170 -0
  50. data/spec/background_queue/client_spec.rb +95 -0
  51. data/spec/background_queue/command_spec.rb +34 -0
  52. data/spec/background_queue/config_spec.rb +134 -0
  53. data/spec/background_queue/server_lib/balanced_queue_spec.rb +122 -0
  54. data/spec/background_queue/server_lib/config_spec.rb +443 -0
  55. data/spec/background_queue/server_lib/event_connection_spec.rb +190 -0
  56. data/spec/background_queue/server_lib/event_server_spec.rb +48 -0
  57. data/spec/background_queue/server_lib/integration/full_test_spec.rb +247 -0
  58. data/spec/background_queue/server_lib/integration/queue_integration_spec.rb +98 -0
  59. data/spec/background_queue/server_lib/integration/serialize_spec.rb +127 -0
  60. data/spec/background_queue/server_lib/job_registry_spec.rb +65 -0
  61. data/spec/background_queue/server_lib/job_spec.rb +525 -0
  62. data/spec/background_queue/server_lib/owner_spec.rb +33 -0
  63. data/spec/background_queue/server_lib/priority_queue_spec.rb +182 -0
  64. data/spec/background_queue/server_lib/server_spec.rb +353 -0
  65. data/spec/background_queue/server_lib/sorted_workers_spec.rb +122 -0
  66. data/spec/background_queue/server_lib/task_registry_spec.rb +69 -0
  67. data/spec/background_queue/server_lib/task_spec.rb +20 -0
  68. data/spec/background_queue/server_lib/thread_manager_spec.rb +106 -0
  69. data/spec/background_queue/server_lib/worker_balancer_spec.rb +127 -0
  70. data/spec/background_queue/server_lib/worker_client_spec.rb +196 -0
  71. data/spec/background_queue/server_lib/worker_thread_spec.rb +125 -0
  72. data/spec/background_queue/utils_spec.rb +27 -0
  73. data/spec/background_queue/worker/base_spec.rb +35 -0
  74. data/spec/background_queue/worker/calling_spec.rb +103 -0
  75. data/spec/background_queue/worker/environment_spec.rb +67 -0
  76. data/spec/background_queue/worker/worker_loader_spec.rb +103 -0
  77. data/spec/background_queue_spec.rb +7 -0
  78. data/spec/resources/config-client.yml +7 -0
  79. data/spec/resources/config-serialize.yml +12 -0
  80. data/spec/resources/config.yml +12 -0
  81. data/spec/resources/example_worker.rb +4 -0
  82. data/spec/resources/example_worker_with_error.rb +4 -0
  83. data/spec/resources/test_worker.rb +8 -0
  84. data/spec/shared/queue_registry_shared.rb +216 -0
  85. data/spec/spec_helper.rb +15 -0
  86. data/spec/support/default_task.rb +9 -0
  87. data/spec/support/private.rb +23 -0
  88. data/spec/support/simple_server.rb +28 -0
  89. data/spec/support/simple_task.rb +58 -0
  90. data/spec/support/test_worker_server.rb +205 -0
  91. metadata +254 -0
@@ -0,0 +1,36 @@
1
+ require 'json'
2
+
3
+ module BackgroundQueue::ClientLib
4
+
5
+ #store a command and all its parameters as a hash to be serialized when passing to the server.
6
+ module Command
7
+
8
+ #create an 'add task' command
9
+ def self.add_task_command(worker, owner_id, job_id, task_id, priority, task_parameters={}, options={} )
10
+ BackgroundQueue::Command.new(:add_task, options, :worker=>worker, :owner_id=>owner_id, :job_id=>job_id, :task_id=>task_id, :priority=>priority, :params=>task_parameters)
11
+ end
12
+
13
+ #create an 'add tasks' command
14
+ def self.add_tasks_command(worker, owner_id, job_id, tasks, priority, shared_parameters={}, options={} )
15
+ raise BackgroundQueue::InvalidCommand, "No Tasks In List" if tasks.nil? || tasks.length == 0
16
+ BackgroundQueue::Command.new(:add_tasks, options, :worker=>worker, :owner_id=>owner_id, :job_id=>job_id, :tasks=>tasks, :priority=>priority, :shared_parameters=>shared_parameters)
17
+ end
18
+
19
+ #create an 'get_status' command
20
+ def self.get_status_command(job_id, options={} )
21
+ BackgroundQueue::Command.new(:get_status, options, {:job_id=>job_id})
22
+ end
23
+
24
+ #create an 'stats' command
25
+ def self.stats_command(options={})
26
+ BackgroundQueue::Command.new(:stats, options, {})
27
+ end
28
+
29
+ #create a 'remove tasks' command
30
+ #is this needed?
31
+ #def self.remove_tasks_command(tasks, options={})
32
+ # raise BackgroundQueue::InvalidCommand, "No Tasks In List" if tasks.nil? || tasks.length == 0
33
+ # BackgroundQueue::Command.new(:remove_tasks, options, {:tasks=>tasks})
34
+ #end
35
+ end
36
+ end
@@ -0,0 +1,109 @@
1
+ module BackgroundQueue::ClientLib
2
+
3
+ #The client configuration which is stored as a YAML file containing a root key for each environments configuration, much like database.yml.
4
+ #
5
+ #Example
6
+ #=======
7
+ #
8
+ # development:
9
+ # server:
10
+ # host: 127.0.0.1
11
+ # port: 3000
12
+ # memcache: 127.0.0.1:9999
13
+ # production:
14
+ # server:
15
+ # host: 192.168.3.56
16
+ # port: 3000
17
+ # failover:
18
+ # -
19
+ # host: 192.168.3.57
20
+ # port: 3000
21
+ # -
22
+ # host: 192.168.3.58
23
+ # memcache: 192.168.3.1:9999, 192.168.3.3:9999
24
+ class Config < BackgroundQueue::Config
25
+
26
+ #the primary {BackgroundQueue::Config::Server}
27
+ attr_reader :server
28
+ #an array of failover {BackgroundQueue::Config::Server}
29
+ attr_reader :failover
30
+ #an array of Strings defining memcache server address
31
+ attr_reader :memcache
32
+
33
+ #load the configration using a hash just containing the environment
34
+ def self.load_hash(env_config, path)
35
+ BackgroundQueue::ClientLib::Config.new(
36
+ build_primary_server_entry(env_config, path),
37
+ build_failover_server_entries(env_config, path),
38
+ build_memcache_array(env_config, path)
39
+ )
40
+ end
41
+
42
+ class << self
43
+ private
44
+
45
+ def build_primary_server_entry(env_config, path)
46
+ server_entry = BackgroundQueue::Utils.get_hash_entry(env_config, :server)
47
+ if server_entry
48
+ begin
49
+ BackgroundQueue::ClientLib::Config::Server.new(server_entry)
50
+ rescue Exception=>e
51
+ raise BackgroundQueue::LoadError, "Error loading 'server' entry from background queue configuration file #{full_path(path)}: #{e.message}"
52
+ end
53
+ else
54
+ raise BackgroundQueue::LoadError, "Missing 'server' entry in background queue configuration file #{full_path(path)}"
55
+ end
56
+ end
57
+
58
+ def build_failover_server_entries(env_config, path)
59
+ entries = []
60
+ failover_entry = BackgroundQueue::Utils.get_hash_entry(env_config, :failover)
61
+ if failover_entry && failover_entry.kind_of?(Array)
62
+ failover_entry.each_with_index do |entry, index|
63
+ begin
64
+ entries << BackgroundQueue::ClientLib::Config::Server.new(entry)
65
+ rescue Exception=>e
66
+ raise BackgroundQueue::LoadError, "Error loading 'failover' entry (#{index + 1}) from background queue configuration file #{full_path(path)}: #{e.message}"
67
+ end
68
+ end
69
+ elsif failover_entry
70
+ raise BackgroundQueue::LoadError, "Error loading 'failover' entries configuration file #{full_path(path)}: invalid data type (#{failover_entry.class.name}), expecting Array"
71
+ end
72
+ entries
73
+ end
74
+
75
+ end
76
+
77
+
78
+ #do not call this directly, use a load_* method
79
+ def initialize(server, failover, memcache)
80
+ @server = server
81
+ @failover = failover
82
+ @memcache = memcache
83
+ end
84
+
85
+ #A server entry in the configuration
86
+ class Server
87
+
88
+ attr_reader :host
89
+ attr_reader :port
90
+
91
+ def initialize(config_entry)
92
+ if config_entry.kind_of?(Hash)
93
+ @host = BackgroundQueue::Utils.get_hash_entry(config_entry, :host)
94
+ raise BackgroundQueue::LoadError, "Missing 'host' configuration entry" if @host.nil?
95
+
96
+ @port = BackgroundQueue::Utils.get_hash_entry(config_entry, :port)
97
+ if @port
98
+ @port = @port.to_i
99
+ else
100
+ @port = BackgroundQueue::Config::DEFAULT_PORT
101
+ end
102
+ else
103
+ raise BackgroundQueue::LoadError, "Invalid data type (#{config_entry.class.name}), expecting Hash"
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ end
@@ -0,0 +1,105 @@
1
+ require 'timeout'
2
+
3
+ module BackgroundQueue::ClientLib
4
+ #A connection to a backend queue server
5
+ #Handles sending the command to the server and receiving the reply
6
+ #For now connections are not pooled/reused
7
+ class Connection
8
+ def initialize(client, server)
9
+ @client = client
10
+ @server = server
11
+ @socket = nil
12
+ end
13
+
14
+ #send a command to the server
15
+ def send_command(command)
16
+ check_connected
17
+ send_with_header(command.to_buf)
18
+ response = receive_with_header
19
+ BackgroundQueue::Command.from_buf(response)
20
+ end
21
+
22
+ private
23
+
24
+ def connect
25
+ begin
26
+ Timeout::timeout(3) {
27
+ @socket = TCPSocket.open(@server.host, @server.port)
28
+ true
29
+ }
30
+ rescue Timeout::Error
31
+ raise BackgroundQueue::ClientLib::ConnectionError, "Timeout Connecting to #{@server.host}:#{@server.port}"
32
+ rescue Exception=>e
33
+ raise BackgroundQueue::ClientLib::ConnectionError, "Error Connecting to #{@server.host}:#{@server.port}: #{e.message}"
34
+ end
35
+ end
36
+
37
+ def check_connected
38
+ connect if @socket.nil?
39
+ end
40
+
41
+ def send_data(data)
42
+ written = 0
43
+ to_write = data.length
44
+ while written < to_write do
45
+ begin
46
+ Timeout::timeout(5) {
47
+ amt_written = @socket.write(data)
48
+ written += amt_written
49
+ if written < to_write
50
+ data = data[amt_written, data.length - amt_written ]
51
+ end
52
+ }
53
+ rescue Timeout::Error
54
+ raise BackgroundQueue::ClientLib::ConnectionError, "Timeout Sending to #{@server.host}:#{@server.port}"
55
+ rescue Exception=>e
56
+ raise BackgroundQueue::ClientLib::ConnectionError, "Error Sending to #{@server.host}:#{@server.port}: #{e.message}"
57
+ end
58
+ end
59
+ true
60
+ end
61
+
62
+ def self.add_header(data)
63
+ length = data.length
64
+ [1,length, data].pack("SLZ#{length}")
65
+ end
66
+
67
+ def send_with_header(data)
68
+ send_data(BackgroundQueue::ClientLib::Connection.add_header(data))
69
+ end
70
+
71
+ def receive_data(length)
72
+ to_read = length
73
+ amt_read = 0
74
+ sbuf = ""
75
+ while amt_read < to_read do
76
+ begin
77
+ Timeout::timeout(5) {
78
+ read_amt = to_read - amt_read
79
+ tbuf = @socket.recvfrom(read_amt)[0]
80
+ sbuf << tbuf
81
+ amt_read += tbuf.length
82
+ }
83
+ rescue Timeout::Error
84
+ raise BackgroundQueue::ClientLib::ConnectionError, "Timeout Receiving #{length} bytes from #{@server.host}:#{@server.port}"
85
+ rescue Exception=>e
86
+ raise BackgroundQueue::ClientLib::ConnectionError, "Error Receiving #{length} bytes from #{@server.host}:#{@server.port}: #{e.message}"
87
+ end
88
+ end
89
+ sbuf
90
+ end
91
+
92
+ def receive_with_header
93
+ header = receive_data(6).unpack("SL")
94
+ receive_data(header[1])
95
+ end
96
+
97
+
98
+ end
99
+
100
+
101
+ #Error raised when communication failure occurs
102
+ class ConnectionError < Exception
103
+
104
+ end
105
+ end
@@ -0,0 +1,19 @@
1
+ module BackgroundQueue::ClientLib
2
+ #returned from add_task to describe what the job/server was added.
3
+ #this is becuase you can call add_task without a job_id, and not know what server was used.
4
+ #this is passed to get_status
5
+ class JobHandle
6
+
7
+ attr_reader :owner_id
8
+ attr_reader :job_id
9
+ attr_reader :server
10
+
11
+ def initialize(owner_id, job_id, server)
12
+ @owner_id = owner_id
13
+ @job_id = job_id
14
+ @server = server
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,49 @@
1
+ require 'json'
2
+
3
+ module BackgroundQueue
4
+
5
+ #store a command and all its parameters as a hash to be serialized when passing to/from the server.
6
+ class Command
7
+
8
+ attr_accessor :code
9
+ attr_accessor :options
10
+ attr_accessor :args
11
+
12
+ def initialize(code, options, args)
13
+ @code = code
14
+ @options = BackgroundQueue::Utils::AnyKeyHash.new(options)
15
+ @args = BackgroundQueue::Utils::AnyKeyHash.new(args)
16
+ end
17
+
18
+ #convert the command to a string (currently json) to get sent
19
+ def to_buf
20
+ {:c=>@code, :a=>@args.hash, :o=>@options.hash}.to_json
21
+ end
22
+
23
+ #load a command from a string
24
+ def self.from_buf(buf)
25
+ hash_data = nil
26
+ begin
27
+ hash_data = JSON.load(buf)
28
+ rescue Exception=>e
29
+ raise InvalidCommand, "Invalid data format (should be json) when loading command from buffer: #{e.message}"
30
+ end
31
+ begin
32
+ raise "Missing 'c' (code)" if hash_data['c'].nil?
33
+ code = hash_data['c'].intern
34
+ raise "Missing 'a' (args)" if hash_data['a'].nil?
35
+ args = hash_data['a']
36
+ raise "Missing 'o' (options)" if hash_data['o'].nil?
37
+ options = hash_data['o']
38
+ BackgroundQueue::Command.new(code, options, args)
39
+ rescue Exception=>e
40
+ raise InvalidCommand, "Error loading command from buffer: #{e.message}"
41
+ end
42
+ end
43
+ end
44
+
45
+ #Error raised when command is invalid
46
+ class InvalidCommand < Exception
47
+
48
+ end
49
+ end
@@ -0,0 +1,118 @@
1
+ require "erb"
2
+ require "yaml"
3
+
4
+ module BackgroundQueue
5
+
6
+ #Base class that loads configuration files for client/server
7
+ class Config
8
+
9
+ #the default port that is used if the configuration does not specify a port
10
+ DEFAULT_PORT = 2222
11
+
12
+ #load the configuration using a file path
13
+ def self.load_file(path)
14
+ string = get_string_from_file(path)
15
+ load_string(string, path)
16
+ end
17
+
18
+ #load the configuration using a string that may contain ERB syntax
19
+ def self.load_string(string, path)
20
+ evaled_string = evaluate_erb(string, path)
21
+ load_yaml(evaled_string, path)
22
+ end
23
+
24
+ #load the configuration using a string of YAML
25
+ def self.load_yaml(yaml_string, path)
26
+ all_configs = convert_yaml_to_hash(yaml_string, path)
27
+ env_config = extract_enviroment_entry(all_configs, path)
28
+ load_hash(env_config, path)
29
+ end
30
+
31
+ #load the configration using a hash just containing the environment. Overridden by Client/Server class.
32
+ def self.load_hash(env_config, path)
33
+ raise "Invalid Loading of Ciguration using abstract base class. Use Server or Client subclass."
34
+ end
35
+
36
+
37
+ class << self
38
+ private
39
+
40
+ #nothing more annoying than not understanding where the library thinks path is pointing to...
41
+ def full_path(path)
42
+ if path.nil?
43
+ '<unknown>'
44
+ else
45
+ begin
46
+ File.expand_path(path)
47
+ rescue
48
+ '<unknown>'
49
+ end
50
+ end
51
+ end
52
+
53
+ def get_string_from_file(path)
54
+ if File.exist?(path)
55
+ File.open(path) { |f| f.read }
56
+ else
57
+ raise BackgroundQueue::LoadError, "Failed to open background_queue configuration file at '#{full_path(path)}'"
58
+ end
59
+ end
60
+
61
+ def evaluate_erb(string, path)
62
+ begin
63
+ message = ERB.new(string)
64
+ message.result
65
+ rescue Exception=>ex
66
+ raise BackgroundQueue::LoadError, "Error executing ERB for background_queue configuration file at '#{full_path(path)}': #{ex.message}"
67
+ end
68
+ end
69
+
70
+
71
+
72
+ def convert_yaml_to_hash(string, path)
73
+ begin
74
+ result = YAML::load(string)
75
+ raise "Root of config should be a hash of environment configurations" unless result.kind_of?(Hash)
76
+ result
77
+ rescue Exception=>ex
78
+ raise BackgroundQueue::LoadError, "Error loading YAML for background_queue configuration file at '#{full_path(path)}': #{ex.message}"
79
+ end
80
+ end
81
+
82
+ def current_environment
83
+ if ENV.has_key?('RAILS_ENV')
84
+ ENV['RAILS_ENV']
85
+ elsif defined? Rails
86
+ Rails.env
87
+ end
88
+ end
89
+
90
+ def extract_enviroment_entry(all_configs, path)
91
+ env_str = current_environment
92
+ if all_configs.has_key?(env_str)
93
+ all_configs[env_str]
94
+ elsif all_configs.has_key?(env_str.to_s.intern)
95
+ all_configs[env_str.to_s.intern]
96
+ else
97
+ raise BackgroundQueue::LoadError, "Error loading YAML for background_queue configuration file at '#{full_path(path)}': missing enviroment root entry: #{env_str}"
98
+ end
99
+ end
100
+
101
+ def build_memcache_array(env_config, path)
102
+ memcache_entry = BackgroundQueue::Utils.get_hash_entry(env_config, :memcache)
103
+ if memcache_entry && memcache_entry.kind_of?(String)
104
+ memcache_entry.split(',').collect { |entry| entry.strip }.select { |entry| !entry.nil? && entry.length > 0 }
105
+ elsif memcache_entry
106
+ raise BackgroundQueue::LoadError, "Error loading 'memcache' entry in configuration file #{full_path(path)}: invalid data type (#{memcache_entry.class.name}), expecting String (comma separated)"
107
+ else
108
+ raise BackgroundQueue::LoadError, "Missing 'memcache' entry in configuration file #{full_path(path)}"
109
+ end
110
+ end
111
+ end
112
+ end
113
+
114
+ #Error raised when unable to load configuration
115
+ class LoadError < Exception
116
+
117
+ end
118
+ end
@@ -0,0 +1,108 @@
1
+ require 'thread'
2
+ module BackgroundQueue::ServerLib
3
+
4
+ class BalancedQueue < PriorityQueue
5
+ include BackgroundQueue::ServerLib::QueueRegistry
6
+
7
+ attr_reader :server
8
+
9
+ def initialize(server)
10
+ @task_registry = BackgroundQueue::ServerLib::TaskRegistry.new
11
+ @condvar = ConditionVariable.new
12
+ @mutex = Mutex.new
13
+ @server = server
14
+ @thread_manager = server.thread_manager
15
+ super()
16
+ end
17
+
18
+ def add_task(task)
19
+ @thread_manager.protect_access {
20
+ status, existing_task = @task_registry.register(task)
21
+ if status != :waiting
22
+ if status == :existing
23
+ remove_item(existing_task)
24
+ end
25
+ add_item(task)
26
+ @thread_manager.signal_access #wake anything reading from the queue
27
+ end
28
+ }
29
+ end
30
+
31
+ def remove_task(task)
32
+ @thread_manager.protect_access {
33
+ remove_item(task)
34
+ }
35
+ end
36
+
37
+ def finish_task(task)
38
+ @thread_manager.protect_access {
39
+ finish_item(task)
40
+ existing_task = @task_registry.de_register(task.id)
41
+ if existing_task
42
+ add_item(task)
43
+ end
44
+ }
45
+ end
46
+
47
+ def next_task
48
+ task = nil
49
+ @thread_manager.control_access {
50
+ task = next_item
51
+ if task.nil?
52
+ @thread_manager.wait_on_access
53
+ end
54
+ }
55
+ task
56
+ end
57
+
58
+ def self.queue_class
59
+ BackgroundQueue::ServerLib::Owner
60
+ end
61
+
62
+ def register_job(job)
63
+ @server.jobs.register(job)
64
+ end
65
+
66
+ def synchronous?
67
+ false
68
+ end
69
+
70
+ def save_to_file(io)
71
+ data = []
72
+ @server.logger.debug("Saving task queue to file")
73
+ @thread_manager.protect_access {
74
+ each_item { |owner|
75
+ owner.each_item { |job|
76
+ job.each_item { |task|
77
+ data << task.to_json_object(true)
78
+ }
79
+ }
80
+ }
81
+ }
82
+ @server.logger.debug("Writing #{data.length} entries to file")
83
+ io.write(JSON.fast_generate(data))
84
+ end
85
+
86
+ def load_from_file(io)
87
+ @server.logger.debug("Loading task queue from file")
88
+ tasks = JSON.parse(io.read, :symbolize_names=>true)
89
+ @server.logger.debug("Adding #{tasks.length} tasks from file")
90
+ for task_data in tasks
91
+ task = Task.new(task_data[:owner_id], task_data[:job_id], task_data[:id], task_data[:priority], task_data[:worker], task_data[:params], task_data[:options])
92
+ add_task(task)
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ def get_queue_id_from_item(item)
99
+ item.owner_id
100
+ end
101
+
102
+ def add_item_to_queue(queue, item)
103
+ queue.add_item(item)
104
+ end
105
+
106
+
107
+ end
108
+ end