skyrunner 0.0.13 → 0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: acab7006b6eec4ef27bb95523a7731881a2c137a
4
- data.tar.gz: b6d2dafafa9aa2c779c4ae5023720e32756924c0
3
+ metadata.gz: b6d11252dc57758004a10bba1e6d9321f07a6629
4
+ data.tar.gz: fe23c5593a322c8a39a90db60b8d0f6632768a19
5
5
  SHA512:
6
- metadata.gz: 33db221875b2e2fb7f195ce792b96a6acb0405a2caa61f138c46cb29b66e67756eb54f26c3d59f207f1ce02518712aae4ec6266ced4f506b06fbabb4ce70596e
7
- data.tar.gz: 2759e97bb2315a1f7307706524fa3ff87dd265acf498138d3085c22492c84eff062ea440112bd2f6fccd689dc1272434fd84a5170598e28e1d6715a893016061
6
+ metadata.gz: 6b2dc81fcdd2416d16973511e929731556661c6b8e4b4b9c0ef578ed3c500b61ce744e42925caa08709b503915b5c37224cb82841e1bb94468ec5e52ee7f960e
7
+ data.tar.gz: b61a040c8e9c8d3a829a3e1a56b546d1fcc61fa699d2c27dc5b1d2f1eaa6c9415f834ff8b88b627731e956ae2926c6dc6cc57e0f4ee6ef767d0ebb3b5757ad67
data/README.md CHANGED
@@ -31,7 +31,7 @@ To start a consumer
31
31
  bundle exec rake skyrunner:consume
32
32
  ``
33
33
 
34
- To gracefully shut down a consumer, send it SIGINT or SIGTERM. It will finish up processing the messages it has de-queued before terminating.
34
+ To gracefully shut down a consumer, send it SIGINT. It will finish up processing the messages it has de-queued before terminating.
35
35
 
36
36
  See `jobs/example_job.rb` for an example job. To run a job, just call `execute!` on the job, passing any named job arguments you want. The job class should implement the method `run`. This method will get passed the job arguments. For each task you want consumers to run, `run` should yield an array of two elements, the first being the name of the method on the job class to run for the task, and the second a Hash of method arguments.
37
37
 
data/bin/skyrunner CHANGED
@@ -12,11 +12,7 @@ logger.level = Log4r::DEBUG
12
12
  SkyRunner.logger = logger
13
13
 
14
14
  trap("INT") do
15
- SkyRunner.stop_consuming!
16
- end
17
-
18
- trap("TERM") do
19
- SkyRunner.stop_consuming!
15
+ SkyRunner.stop_consuming!(true)
20
16
  end
21
17
 
22
18
  opts = Trollop::options do
@@ -29,6 +25,7 @@ opts = Trollop::options do
29
25
  Valid commands:
30
26
 
31
27
  consume - Starts consuming tasks.
28
+ test - Runs a test job.
32
29
  init - Creates DynamoDB table and SQS queue for SkyRunner.
33
30
  purge - Purges and re-creates DynamoDB table and SQS queue for SkyRunner. (Destructive!)
34
31
  END
@@ -37,14 +34,16 @@ opts = Trollop::options do
37
34
  opt :sqs_queue_name, "SQS queue use for tasks.", default: "skyrunner_tasks", type: :string
38
35
  opt :namespace, "Namespace of jobs to consume.", default: "default", type: :string
39
36
  opt :batch_size, "Number of tasks to consume per batch.", default: 10
37
+ opt :num_threads, "Number of consumer threads.", default: 10
40
38
  end
41
39
 
42
40
  SkyRunner.dynamo_db_table_name = opts[:dynamo_db_table_name]
43
41
  SkyRunner.sqs_queue_name = opts[:sqs_queue_name]
44
42
  SkyRunner.job_namespace = opts[:namespace]
45
43
  SkyRunner.consumer_batch_size = opts[:batch_size].to_i
44
+ SkyRunner.num_threads = opts[:num_threads].to_i
46
45
 
47
- COMMANDS = ["init", "purge", "consume"]
46
+ COMMANDS = ["init", "purge", "consume", "test"]
48
47
 
49
48
  Trollop::die "Must specify command" unless COMMANDS.include?(ARGV[0])
50
49
 
@@ -57,4 +56,9 @@ when "purge"
57
56
  SkyRunner.init!(purge: true)
58
57
  when "consume"
59
58
  SkyRunner.consume!
59
+ when "test"
60
+ $: << "."
61
+ require "#{File.dirname(__FILE__)}/../jobs/example_job"
62
+ ExampleJobModule::ExampleJob.new.execute!(number_of_tasks: 500)
63
+ SkyRunner.consume!
60
64
  end
@@ -7,11 +7,7 @@ namespace :skyrunner do
7
7
  desc "Starts consuming SkyRunner tasks."
8
8
  task consume: :environment do
9
9
  trap("INT") do
10
- SkyRunner.stop_consuming!
11
- end
12
-
13
- trap("TERM") do
14
- SkyRunner.stop_consuming!
10
+ SkyRunner.stop_consuming!(true)
15
11
  end
16
12
 
17
13
  SkyRunner.consume! do |exception|
@@ -16,4 +16,9 @@ SkyRunner.setup do |config|
16
16
  # this should provide sufficient time for a consumer to process 10 tasks, for example. (default 90)
17
17
  #
18
18
  # config.visibility_timeout = 90
19
+
20
+ # Set the number of concurrent threads for the consumer process.
21
+ # (If greater than one, you obviously need to make sure your tasks are thread-safe.)
22
+ #
23
+ # config.num_threads = 10
19
24
  end
data/lib/skyrunner/job.rb CHANGED
@@ -67,6 +67,7 @@ module SkyRunner::Job
67
67
  1.upto(5) do
68
68
  flush.()
69
69
  sleep 5 if pending_args.size > 0
70
+ break if pending_args.size == 0
70
71
  end
71
72
  end
72
73
  end
@@ -74,6 +75,7 @@ module SkyRunner::Job
74
75
  1.upto(5) do
75
76
  flush.() if pending_args.size > 0
76
77
  sleep 5 if pending_args.size > 0
78
+ break if pending_args.size == 0
77
79
  end
78
80
 
79
81
  handle_task_completed!
@@ -1,3 +1,3 @@
1
1
  module Skyrunner
2
- VERSION = "0.0.13"
2
+ VERSION = "0.1.0"
3
3
  end
data/lib/skyrunner.rb CHANGED
@@ -63,14 +63,55 @@ module SkyRunner
63
63
  def self.consume!(&block)
64
64
  queue = sqs_queue
65
65
  table = dynamo_db_table
66
-
67
66
  raise "Queue #{SkyRunner::sqs_queue_name} not found. Try running 'skyrunner init'" unless queue
68
67
  raise "DynamoDB table #{SkyRunner::dynamo_db_table_name} not found. Try running 'skyrunner init'" unless table && table.exists?
69
68
 
69
+ local_queue = Queue.new
70
+ error_queue = Queue.new
71
+
72
+ threads = []
73
+
74
+ 1.upto(SkyRunner::num_threads) do
75
+ threads << Thread.new do
76
+ sqs = AWS::SQS.new
77
+
78
+ loop do
79
+ break if SkyRunner::stop_consuming?
80
+ sleep 1 unless local_queue.size > 0
81
+
82
+ klass, job_id, task_args, message = local_queue.pop
83
+
84
+ SkyRunner::log :info, "Run Task: #{task_args} Job: #{job_id} Message: #{message.id}"
85
+
86
+ job = klass.new
87
+ job.skyrunner_job_id = job_id
88
+
89
+ begin
90
+ job.consume!(task_args)
91
+ message.delete
92
+ rescue Exception => e
93
+ error_queue.push(e)
94
+ SkyRunner::log :error, "Task Failed: #{task_args} Job: #{job_id} #{e.message} #{e.backtrace.join("\n")}"
95
+ end
96
+ end
97
+ end
98
+ end
99
+
70
100
  log :info, "Consumer started."
71
101
 
72
102
  loop do
73
- return true if stop_consuming
103
+ if error_queue.size > 0
104
+ SkyRunner::stop_consuming!
105
+
106
+ while error_queue.size > 0
107
+ error = error_queue.pop
108
+ yield error if block_given?
109
+ end
110
+ end
111
+
112
+ return true if stop_consuming?
113
+
114
+ sleep 1 while local_queue.size >= SkyRunner.num_threads
74
115
 
75
116
  received_messages = []
76
117
 
@@ -80,37 +121,19 @@ module SkyRunner
80
121
 
81
122
  next unless received_messages.size > 0
82
123
 
83
- failed = false
84
-
85
124
  table.batch_get(:all, received_messages.map { |m| m[1]["job_id"] }.uniq, consistent_read: true) do |record|
86
125
  received_messages.select { |m| m[1]["job_id"] == record["job_id"] }.each_with_index do |received_message|
87
126
  message = received_message[1]
88
127
  job_id = message["job_id"]
89
128
 
90
- if record["namespace"] == SkyRunner.job_namespace && record["failed"] == 0 && !failed
129
+ if record["namespace"] == SkyRunner.job_namespace && record["failed"] == 0 && error_queue.size == 0
91
130
  start_time = Time.now
92
131
 
93
132
  begin
94
133
  klass = Kernel.const_get(record["class"])
95
-
96
134
  task_args = message["task_args"]
97
- log :info, "Run Task: #{task_args} Job: #{job_id}"
98
-
99
- job = klass.new
100
- job.skyrunner_job_id = job_id
101
-
102
- begin
103
- job.consume!(task_args)
104
- received_message[0].delete
105
-
106
- yield false if block_given?
107
- rescue Exception => e
108
- failed = true
109
- log :error, "Task Failed: #{task_args} Job: #{job_id} #{e.message} #{e.backtrace.join("\n")}"
110
- yield e if block_given?
111
- end
135
+ local_queue.push([klass, job_id, task_args, received_message[0]])
112
136
  rescue NameError => e
113
- failed = true
114
137
  log :error, "Task Failed: No such class #{record["class"]} #{e.message}"
115
138
  yield e if block_given?
116
139
  end
@@ -118,6 +141,10 @@ module SkyRunner
118
141
  end
119
142
  end
120
143
  end
144
+
145
+ threads.each { |t| t.join }
146
+
147
+ true
121
148
  end
122
149
 
123
150
  def self.dynamo_db_table
@@ -165,10 +192,27 @@ module SkyRunner
165
192
  mattr_accessor :logger
166
193
  @@logger = Log4r::Logger.new("skyrunner")
167
194
 
168
- mattr_accessor :stop_consuming
195
+ mattr_accessor :num_threads
196
+ @@num_threads = 10
197
+
198
+ mattr_accessor :stop_consuming_flag
199
+
200
+ @@stop_consuming_mutex = Mutex.new
201
+
202
+ def self.stop_consuming?
203
+ @@stop_consuming_mutex.synchronize do
204
+ SkyRunner::stop_consuming_flag
205
+ end
206
+ end
169
207
 
170
- def self.stop_consuming!
171
- SkyRunner::stop_consuming = true
208
+ def self.stop_consuming!(its_a_trap=false)
209
+ if its_a_trap
210
+ SkyRunner::stop_consuming_flag = true
211
+ else
212
+ @@stop_consuming_mutex.synchronize do
213
+ SkyRunner::stop_consuming_flag = true
214
+ end
215
+ end
172
216
  end
173
217
 
174
218
  private
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: skyrunner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.13
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Greg Fodor