background_queue 0.2.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.
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