skyrunner 0.0.13 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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