reqless 0.0.1
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 +7 -0
- data/Gemfile +8 -0
- data/README.md +648 -0
- data/Rakefile +117 -0
- data/bin/docker-build-and-test +22 -0
- data/exe/reqless-web +11 -0
- data/lib/reqless/config.rb +31 -0
- data/lib/reqless/failure_formatter.rb +43 -0
- data/lib/reqless/job.rb +496 -0
- data/lib/reqless/job_reservers/ordered.rb +29 -0
- data/lib/reqless/job_reservers/round_robin.rb +46 -0
- data/lib/reqless/job_reservers/shuffled_round_robin.rb +21 -0
- data/lib/reqless/lua/reqless-lib.lua +2965 -0
- data/lib/reqless/lua/reqless.lua +2545 -0
- data/lib/reqless/lua_script.rb +90 -0
- data/lib/reqless/middleware/requeue_exceptions.rb +94 -0
- data/lib/reqless/middleware/retry_exceptions.rb +72 -0
- data/lib/reqless/middleware/sentry.rb +66 -0
- data/lib/reqless/middleware/timeout.rb +63 -0
- data/lib/reqless/queue.rb +189 -0
- data/lib/reqless/queue_priority_pattern.rb +16 -0
- data/lib/reqless/server/static/css/bootstrap-responsive.css +686 -0
- data/lib/reqless/server/static/css/bootstrap-responsive.min.css +12 -0
- data/lib/reqless/server/static/css/bootstrap.css +3991 -0
- data/lib/reqless/server/static/css/bootstrap.min.css +689 -0
- data/lib/reqless/server/static/css/codemirror.css +112 -0
- data/lib/reqless/server/static/css/docs.css +839 -0
- data/lib/reqless/server/static/css/jquery.noty.css +105 -0
- data/lib/reqless/server/static/css/noty_theme_twitter.css +137 -0
- data/lib/reqless/server/static/css/style.css +200 -0
- data/lib/reqless/server/static/favicon.ico +0 -0
- data/lib/reqless/server/static/img/glyphicons-halflings-white.png +0 -0
- data/lib/reqless/server/static/img/glyphicons-halflings.png +0 -0
- data/lib/reqless/server/static/js/bootstrap-alert.js +94 -0
- data/lib/reqless/server/static/js/bootstrap-scrollspy.js +125 -0
- data/lib/reqless/server/static/js/bootstrap-tab.js +130 -0
- data/lib/reqless/server/static/js/bootstrap-tooltip.js +270 -0
- data/lib/reqless/server/static/js/bootstrap-typeahead.js +285 -0
- data/lib/reqless/server/static/js/bootstrap.js +1726 -0
- data/lib/reqless/server/static/js/bootstrap.min.js +6 -0
- data/lib/reqless/server/static/js/codemirror.js +2972 -0
- data/lib/reqless/server/static/js/jquery.noty.js +220 -0
- data/lib/reqless/server/static/js/mode/javascript.js +360 -0
- data/lib/reqless/server/static/js/theme/cobalt.css +18 -0
- data/lib/reqless/server/static/js/theme/eclipse.css +25 -0
- data/lib/reqless/server/static/js/theme/elegant.css +10 -0
- data/lib/reqless/server/static/js/theme/lesser-dark.css +45 -0
- data/lib/reqless/server/static/js/theme/monokai.css +28 -0
- data/lib/reqless/server/static/js/theme/neat.css +9 -0
- data/lib/reqless/server/static/js/theme/night.css +21 -0
- data/lib/reqless/server/static/js/theme/rubyblue.css +21 -0
- data/lib/reqless/server/static/js/theme/xq-dark.css +46 -0
- data/lib/reqless/server/views/_job.erb +259 -0
- data/lib/reqless/server/views/_job_list.erb +8 -0
- data/lib/reqless/server/views/_pagination.erb +7 -0
- data/lib/reqless/server/views/about.erb +130 -0
- data/lib/reqless/server/views/completed.erb +11 -0
- data/lib/reqless/server/views/config.erb +14 -0
- data/lib/reqless/server/views/failed.erb +48 -0
- data/lib/reqless/server/views/failed_type.erb +18 -0
- data/lib/reqless/server/views/job.erb +17 -0
- data/lib/reqless/server/views/layout.erb +451 -0
- data/lib/reqless/server/views/overview.erb +137 -0
- data/lib/reqless/server/views/queue.erb +125 -0
- data/lib/reqless/server/views/queues.erb +45 -0
- data/lib/reqless/server/views/tag.erb +6 -0
- data/lib/reqless/server/views/throttles.erb +38 -0
- data/lib/reqless/server/views/track.erb +75 -0
- data/lib/reqless/server/views/worker.erb +34 -0
- data/lib/reqless/server/views/workers.erb +14 -0
- data/lib/reqless/server.rb +549 -0
- data/lib/reqless/subscriber.rb +74 -0
- data/lib/reqless/test_helpers/worker_helpers.rb +55 -0
- data/lib/reqless/throttle.rb +57 -0
- data/lib/reqless/version.rb +5 -0
- data/lib/reqless/worker/base.rb +237 -0
- data/lib/reqless/worker/forking.rb +215 -0
- data/lib/reqless/worker/serial.rb +41 -0
- data/lib/reqless/worker.rb +5 -0
- data/lib/reqless.rb +309 -0
- metadata +399 -0
data/Rakefile
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
require 'bundler/gem_helper'
|
3
|
+
Bundler::GemHelper.install_tasks
|
4
|
+
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
7
|
+
t.rspec_opts = %w[--profile]
|
8
|
+
t.ruby_opts = "-Ispec -rsimplecov_setup"
|
9
|
+
end
|
10
|
+
|
11
|
+
min_coverage_threshold = 85.0
|
12
|
+
desc "Checks the spec coverage and fails if it is less than #{min_coverage_threshold}%"
|
13
|
+
task :check_coverage do
|
14
|
+
percent = File.read("./coverage/coverage_percent.txt").to_f
|
15
|
+
if percent < min_coverage_threshold
|
16
|
+
raise "Spec coverage was not high enough: #{percent.round(2)}%"
|
17
|
+
else
|
18
|
+
puts "Nice job! Spec coverage is still at least #{min_coverage_threshold}%"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
task default: [:spec, :check_coverage]
|
23
|
+
|
24
|
+
namespace :core do
|
25
|
+
reqless_core_dir = "./lib/reqless/reqless-core"
|
26
|
+
|
27
|
+
desc "Builds the reqless-core lua scripts"
|
28
|
+
task :build do
|
29
|
+
Dir.chdir(reqless_core_dir) do
|
30
|
+
sh "make clean && make"
|
31
|
+
sh "cp reqless.lua ../lua"
|
32
|
+
sh "cp reqless-lib.lua ../lua"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
task :update_submodule do
|
37
|
+
Dir.chdir(reqless_core_dir) do
|
38
|
+
sh "git checkout main"
|
39
|
+
sh "git pull --rebase"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
desc "Updates reqless-core and rebuilds it"
|
44
|
+
task update: [:update_submodule, :build]
|
45
|
+
|
46
|
+
namespace :verify do
|
47
|
+
script_files = %w[ lib/reqless/lua/reqless.lua lib/reqless/lua/reqless-lib.lua ]
|
48
|
+
|
49
|
+
desc "Verifies the script has no uncommitted changes"
|
50
|
+
task :clean do
|
51
|
+
script_files.each do |file|
|
52
|
+
git_status = `git status -- #{file}`
|
53
|
+
unless /working directory clean/.match(git_status)
|
54
|
+
raise "#{file} is dirty: \n\n#{git_status}\n\n"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
desc "Verifies the script is current"
|
60
|
+
task :current do
|
61
|
+
require 'digest/md5'
|
62
|
+
our_md5s = script_files.map do |file|
|
63
|
+
Digest::MD5.hexdigest(File.read file)
|
64
|
+
end
|
65
|
+
|
66
|
+
canonical_md5s = Dir.chdir(reqless_core_dir) do
|
67
|
+
sh "make clean && make"
|
68
|
+
script_files.map do |file|
|
69
|
+
Digest::MD5.hexdigest(File.read(File.basename file))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
unless our_md5s == canonical_md5s
|
74
|
+
raise "The current scripts are out of date with reqless-core"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
desc "Verifies the committed script is current"
|
80
|
+
task verify: %w[ verify:clean verify:current ]
|
81
|
+
end
|
82
|
+
|
83
|
+
desc "Starts a reqless console"
|
84
|
+
task :console do
|
85
|
+
ENV['PUBLIC_SEQUEL_API'] = 'true'
|
86
|
+
ENV['NO_NEW_RELIC'] = 'true'
|
87
|
+
exec "bundle exec pry -r./conf/console"
|
88
|
+
end
|
89
|
+
|
90
|
+
namespace :reqless do
|
91
|
+
desc "Runs a test worker so you can send signals to it for testing"
|
92
|
+
task :run_test_worker do
|
93
|
+
require 'reqless'
|
94
|
+
require 'reqless/job_reservers/ordered'
|
95
|
+
require 'reqless/worker'
|
96
|
+
queue = Reqless::Client.new.queues["example"]
|
97
|
+
queue.client.redis.flushdb
|
98
|
+
|
99
|
+
ENV['VVERBOSE'] = '1'
|
100
|
+
|
101
|
+
class ExampleJob
|
102
|
+
def self.perform(job)
|
103
|
+
sleep_time = job.data.fetch("sleep")
|
104
|
+
print "Sleeping for #{sleep_time}..."
|
105
|
+
sleep sleep_time
|
106
|
+
puts "done"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
20.times do |i|
|
111
|
+
queue.put(ExampleJob, sleep: i)
|
112
|
+
end
|
113
|
+
|
114
|
+
reserver = Reqless::JobReservers::Ordered.new([queue])
|
115
|
+
Reqless::Workers::ForkingWorker.new(reserver, log_level: Logger::INFO).run
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e -o pipefail
|
4
|
+
|
5
|
+
# From https://stackoverflow.com/a/4774063
|
6
|
+
REPO_DIR="$( cd -- "$(dirname "$0")/.." >/dev/null 2>&1 ; pwd -P )"
|
7
|
+
|
8
|
+
COMMAND="$@"
|
9
|
+
if [ -z "$COMMAND" ]; then
|
10
|
+
COMMAND="bundle exec rspec"
|
11
|
+
fi
|
12
|
+
|
13
|
+
test -f "$REPO_DIR/Gemfile.lock" && rm -f "$REPO_DIR/Gemfile.lock"
|
14
|
+
redis-cli flushdb
|
15
|
+
docker build -t reqless-rb "$REPO_DIR"
|
16
|
+
docker run \
|
17
|
+
-it \
|
18
|
+
--publish 4000:4000 \
|
19
|
+
--rm \
|
20
|
+
--volume $REPO_DIR:/app \
|
21
|
+
reqless-rb \
|
22
|
+
$COMMAND
|
data/exe/reqless-web
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
|
5
|
+
require "rackup"
|
6
|
+
|
7
|
+
rackup_file = File.realpath(File.dirname(__FILE__) + '/../config.ru')
|
8
|
+
|
9
|
+
ARGV << rackup_file
|
10
|
+
server = Rackup::Server.new
|
11
|
+
server.start
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# Encoding: utf-8
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Reqless
|
6
|
+
# A configuration class associated with a reqless client
|
7
|
+
class Config
|
8
|
+
def initialize(client)
|
9
|
+
@client = client
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](key)
|
13
|
+
@client.call('config.get', key)
|
14
|
+
end
|
15
|
+
|
16
|
+
def []=(key, value)
|
17
|
+
@client.call('config.set', key, value)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Get the specified `reqless` configuration option, or if
|
21
|
+
# none is provided, get the complete current configuration
|
22
|
+
def all
|
23
|
+
JSON.parse(@client.call('config.getAll'))
|
24
|
+
end
|
25
|
+
|
26
|
+
# Restore this option to the default (remove this option)
|
27
|
+
def clear(option)
|
28
|
+
@client.call('config.unset', option)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Encoding: utf-8
|
2
|
+
|
3
|
+
module Reqless
|
4
|
+
# A helper for formatting failure messages
|
5
|
+
class FailureFormatter
|
6
|
+
Failure = Struct.new(:group, :message) do
|
7
|
+
# allow de-structring assignment
|
8
|
+
def to_ary
|
9
|
+
[group, message]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@replacements = { Dir.pwd => '.' }
|
15
|
+
@replacements[ENV['GEM_HOME']] = '<GEM_HOME>' if ENV.key?('GEM_HOME')
|
16
|
+
end
|
17
|
+
|
18
|
+
def format(job, error, lines_to_remove = caller(2))
|
19
|
+
group = "#{job.klass_name}:#{error.class}"
|
20
|
+
message = "#{truncated_message(error)}\n\n" +
|
21
|
+
"#{format_failure_backtrace(error.backtrace, lines_to_remove)}"
|
22
|
+
Failure.new(group, message)
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
# TODO: pull this out into a config option.
|
28
|
+
MAX_ERROR_MESSAGE_SIZE = 10_000
|
29
|
+
def truncated_message(error)
|
30
|
+
return error.message if error.message.length <= MAX_ERROR_MESSAGE_SIZE
|
31
|
+
error.message.slice(0, MAX_ERROR_MESSAGE_SIZE) +
|
32
|
+
"\n... (truncated due to length)"
|
33
|
+
end
|
34
|
+
|
35
|
+
def format_failure_backtrace(error_backtrace, lines_to_remove)
|
36
|
+
(error_backtrace - lines_to_remove).map do |line|
|
37
|
+
@replacements.reduce(line) do |formatted, (original, new)|
|
38
|
+
formatted.sub(original, new)
|
39
|
+
end
|
40
|
+
end.join("\n")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|