qyu 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +56 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +5 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +6 -0
  7. data/LICENSE +21 -0
  8. data/README.md +90 -0
  9. data/Rakefile +6 -0
  10. data/bin/console +14 -0
  11. data/bin/server +17 -0
  12. data/bin/setup +8 -0
  13. data/examples/bin/simple +7 -0
  14. data/examples/config.rb +22 -0
  15. data/examples/simple/create_workflow.rb +18 -0
  16. data/examples/simple/enqueue_job.rb +8 -0
  17. data/examples/simple/worker.rb +32 -0
  18. data/lib/qyu.rb +74 -0
  19. data/lib/qyu/config.rb +35 -0
  20. data/lib/qyu/errors.rb +4 -0
  21. data/lib/qyu/errors/base.rb +8 -0
  22. data/lib/qyu/errors/could_not_fetch_task.rb +18 -0
  23. data/lib/qyu/errors/invalid_queue_name.rb +12 -0
  24. data/lib/qyu/errors/invalid_task_attributes.rb +12 -0
  25. data/lib/qyu/errors/job_not_found.rb +14 -0
  26. data/lib/qyu/errors/lock_already_acquired.rb +12 -0
  27. data/lib/qyu/errors/lock_not_acquired.rb +12 -0
  28. data/lib/qyu/errors/message_not_received.rb +12 -0
  29. data/lib/qyu/errors/not_implemented_error.rb +12 -0
  30. data/lib/qyu/errors/payload_validation_error.rb +12 -0
  31. data/lib/qyu/errors/task_not_found.rb +15 -0
  32. data/lib/qyu/errors/task_status_update_failed.rb +15 -0
  33. data/lib/qyu/errors/unknown_validation_option.rb +12 -0
  34. data/lib/qyu/errors/unsync_error.rb +12 -0
  35. data/lib/qyu/errors/workflow_descriptor_validation_error.rb +14 -0
  36. data/lib/qyu/errors/workflow_not_found.rb +15 -0
  37. data/lib/qyu/factory.rb +26 -0
  38. data/lib/qyu/models.rb +9 -0
  39. data/lib/qyu/models/concerns/workflow_descriptor_validator.rb +117 -0
  40. data/lib/qyu/models/enums/status.rb +44 -0
  41. data/lib/qyu/models/job.rb +174 -0
  42. data/lib/qyu/models/task.rb +218 -0
  43. data/lib/qyu/models/workflow.rb +85 -0
  44. data/lib/qyu/queue.rb +5 -0
  45. data/lib/qyu/queue/base.rb +46 -0
  46. data/lib/qyu/queue/memory/adapter.rb +90 -0
  47. data/lib/qyu/store.rb +5 -0
  48. data/lib/qyu/store/base.rb +106 -0
  49. data/lib/qyu/store/memory/adapter.rb +187 -0
  50. data/lib/qyu/ui.rb +56 -0
  51. data/lib/qyu/ui/helpers/pagination.rb +35 -0
  52. data/lib/qyu/ui/public/bootstrap.min.css +5 -0
  53. data/lib/qyu/ui/public/paper-dashboard.css +3315 -0
  54. data/lib/qyu/ui/public/script.js +28 -0
  55. data/lib/qyu/ui/public/style.css +6 -0
  56. data/lib/qyu/ui/views/footer.erb +18 -0
  57. data/lib/qyu/ui/views/helpers/pagination.erb +49 -0
  58. data/lib/qyu/ui/views/jobs.erb +58 -0
  59. data/lib/qyu/ui/views/kaminari/_first_page.html.erb +3 -0
  60. data/lib/qyu/ui/views/kaminari/_gap.html.erb +3 -0
  61. data/lib/qyu/ui/views/kaminari/_last_page.html.erb +3 -0
  62. data/lib/qyu/ui/views/kaminari/_next_page.html.erb +3 -0
  63. data/lib/qyu/ui/views/kaminari/_page.html.erb +9 -0
  64. data/lib/qyu/ui/views/kaminari/_paginator.html.erb +15 -0
  65. data/lib/qyu/ui/views/kaminari/_prev_page.html.erb +3 -0
  66. data/lib/qyu/ui/views/layout.erb +33 -0
  67. data/lib/qyu/ui/views/navbar.erb +29 -0
  68. data/lib/qyu/ui/views/pagination.erb +19 -0
  69. data/lib/qyu/ui/views/show_job.erb +55 -0
  70. data/lib/qyu/ui/views/sidebar.erb +17 -0
  71. data/lib/qyu/ui/views/task_row.erb +26 -0
  72. data/lib/qyu/utils.rb +17 -0
  73. data/lib/qyu/version.rb +3 -0
  74. data/lib/qyu/workers.rb +10 -0
  75. data/lib/qyu/workers/base.rb +126 -0
  76. data/lib/qyu/workers/concerns/callback.rb +38 -0
  77. data/lib/qyu/workers/concerns/failure_queue.rb +23 -0
  78. data/lib/qyu/workers/concerns/payload_validator.rb +124 -0
  79. data/lib/qyu/workers/sync.rb +63 -0
  80. data/qyu.gemspec +36 -0
  81. metadata +278 -0
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Qyu
4
+ module Workers
5
+ module Concerns
6
+ module Callback
7
+ # Meant to add callbacks to Qyu::Worker
8
+ #
9
+ # Usage:
10
+ #
11
+ # Qyu::Worker.new do
12
+ # callback :execute, :after do
13
+ # # Do something after execution
14
+ # end
15
+ # end
16
+ #
17
+
18
+ def callback(method, type, &block)
19
+ @_callbacks ||= {}
20
+ @_callbacks[method] ||= {}
21
+ @_callbacks[method][type] = block
22
+ end
23
+
24
+ def run_callbacks(method, &block)
25
+ find_callback(method, :before)&.call
26
+ find_callback(method, :around) ? find_callback(method, :around).call(block) : yield
27
+ find_callback(method, :after)&.call
28
+ end
29
+
30
+ private
31
+
32
+ def find_callback(method, type)
33
+ @_callbacks.dig(method, type) if @_callbacks.is_a?(Hash)
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Qyu
4
+ module Workers
5
+ module Concerns
6
+ # Qyu::Concerns::FailureQueue
7
+ module FailureQueue
8
+ # Adds ability to workers enqueue failed task to another queue
9
+ #
10
+ # Qyu::Worker.new do
11
+ # failure_queue true
12
+ # # or
13
+ # failure_queue false
14
+ # end
15
+ #
16
+
17
+ def failure_queue(fq)
18
+ @failure_queue = fq
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Qyu
4
+ module Workers
5
+ module Concerns
6
+ # Qyu::Concerns::PayloadValidator
7
+ module PayloadValidator
8
+ # Adds ability to workers to perform validations on
9
+ # params for the task to be processed
10
+ #
11
+ # Usage:
12
+ #
13
+ # Qyu::Worker.new do
14
+ # validates :user_id, presence: true, type: :integer, unless: :no_user
15
+ # validates :name, presence: true, type: :string
16
+ # validates :account_id, absence: true, if: :customer_id
17
+ # validates :account_id, presence: true, unless: :customer_id
18
+ # end
19
+ #
20
+
21
+ def validates(parameter, opts = {})
22
+ @_validations ||= {}
23
+ @_validations[parameter.to_s] = Qyu::Utils.stringify_hash_keys(opts)
24
+ end
25
+
26
+ def validate_payload!(model)
27
+ return unless @_validations
28
+ payload = Qyu::Utils.stringify_hash_keys(model.payload || {})
29
+ validation_errors = {}
30
+ @_validations.each do |attribute, opts|
31
+ # example: attribute :name
32
+ # example opts { presence: true, type: integer }
33
+ next unless if_validation(payload, opts['if'])
34
+ next unless unless_validation(payload, opts['unless'])
35
+ opts.map do |option, value|
36
+ error = run_validation(option, payload[attribute.to_s], value)
37
+ # next if error is nil
38
+ next unless error
39
+ validation_errors["#{attribute}.#{option}"] = error
40
+ end
41
+ end
42
+
43
+ if validation_errors.size.positive?
44
+ fail Qyu::Errors::PayloadValidationError, validation_errors
45
+ end
46
+ nil
47
+ end
48
+
49
+ private
50
+
51
+ def run_validation(option, param, value)
52
+ # Skip if and unless conditionals (return nil)
53
+ return if option.eql?('if')
54
+ return if option.eql?('unless')
55
+ # supported options are presence, absence and type
56
+ __send__(option, param, value)
57
+ rescue NoMethodError
58
+ raise Qyu::Errors::UnknownValidationOption, option
59
+ end
60
+
61
+ def presence(param, value)
62
+ return unless value
63
+ return unless param.nil?
64
+ { expected: 'present' }
65
+ end
66
+
67
+ def absence(param, value)
68
+ return unless value
69
+ return if param.nil?
70
+ { expected: 'absent' }
71
+ end
72
+
73
+ def type(param, data_type)
74
+ __send__("#{data_type}_type_validator", param)
75
+ end
76
+
77
+ # DataType validators
78
+ def integer_type_validator(param)
79
+ type_validator('integer', [Integer], param.class)
80
+ end
81
+
82
+ def string_type_validator(param)
83
+ type_validator('string', [String, Symbol], param.class)
84
+ end
85
+
86
+ def number_type_validator(param)
87
+ type_validator('number', [Integer, Float], param.class)
88
+ end
89
+
90
+ def boolean_type_validator(param)
91
+ type_validator('boolean', [TrueClass, FalseClass], param.class)
92
+ end
93
+
94
+ def hash_type_validator(param)
95
+ type_validator('hash', [Hash], param.class)
96
+ end
97
+
98
+ def array_type_validator(param)
99
+ type_validator('array', [Array], param.class)
100
+ end
101
+
102
+ def type_validator(type_name, data_types, param_class)
103
+ return if data_types.include?(param_class)
104
+ { expected: type_name, got: param_class.name.downcase }
105
+ end
106
+
107
+ # Conditonal validation
108
+ def if_validation(payload, key)
109
+ # TODO: support block passing "return yield if block_given?"
110
+ return true if key.nil?
111
+ return true if payload[key.to_s]
112
+ false
113
+ end
114
+
115
+ def unless_validation(payload, key)
116
+ # TODO: support block passing "return yield if block_given?"
117
+ return true if key.nil?
118
+ return true unless payload[key.to_s]
119
+ false
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Qyu
4
+ module Workers
5
+ class Sync < Base
6
+ def work(queue_name)
7
+ super do |task|
8
+ job = task.job
9
+ task_names_to_wait_for = job.tasks_to_wait_for(task)
10
+ log(:debug, "Task names to wait for: #{task_names_to_wait_for}")
11
+ task_names_to_wait_for.each do |task_name|
12
+ sync_condition = job.sync_condition(task, task_name)
13
+ log(:debug, "Task: #{task_name}, Sync condition: #{sync_condition}")
14
+ if respond_to?(sync_condition['function'], true)
15
+ __send__(sync_condition['function'], job, task, task_name, sync_condition['param'])
16
+ else
17
+ fail Qyu::Errors::NotImplementedError
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def eq_completed(job, task, task_name_to_wait_for, sync_param_name)
26
+ sync_param_value = task.payload[sync_param_name]
27
+ log(:debug, "Task: #{task_name_to_wait_for}, Sync param value: #{sync_param_value}")
28
+ parent_task_id = task.parent_task_id
29
+ log(:debug, "Task: #{task_name_to_wait_for}, Parent task ID: #{parent_task_id}")
30
+ task_ids = job.find_task_ids_by_name_and_ancestor_task_id(task_name_to_wait_for, parent_task_id)
31
+ log(:debug, "Task: #{task_name_to_wait_for}, Task IDs: #{task_ids}")
32
+
33
+ if task_ids.size < sync_param_value
34
+ log(:debug, 'Re-enqueuing sync task')
35
+ fail Qyu::Errors::UnsyncError
36
+ end
37
+
38
+ check_completion!(task_ids)
39
+ end
40
+
41
+ def completed(job, task, task_name_to_wait_for, _sync_param_name)
42
+ parent_task_id = task.parent_task_id
43
+ log(:debug, "Task: #{task_name_to_wait_for}, Parent task ID: #{parent_task_id}")
44
+ task_ids = job.find_task_ids_by_name_and_ancestor_task_id(task_name_to_wait_for, parent_task_id)
45
+ log(:debug, "Task: #{task_name_to_wait_for}, Task IDs: #{task_ids}")
46
+ if task_ids.empty?
47
+ log(:debug, 'Re-enqueuing sync task')
48
+ fail Qyu::Errors::UnsyncError
49
+ end
50
+ check_completion!(task_ids)
51
+ end
52
+
53
+ def check_completion!(task_ids)
54
+ task_ids.each do |task_id|
55
+ state = Qyu::Status.find(task_id)
56
+ log(:debug, "[CHECK_COMPLETION] Task ID: #{task_id}, Status: #{state.status}")
57
+ next if state.completed?
58
+ fail Qyu::Errors::UnsyncError
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,36 @@
1
+
2
+ lib = File.expand_path("../lib", __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require "qyu/version"
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "qyu"
8
+ spec.version = Qyu::VERSION
9
+ spec.authors = ['Elod Peter', 'Mohamed Osama']
10
+ spec.email = ['bejmuller@gmail.com', 'mohamed.o.alnagdy@gmail.com']
11
+
12
+ spec.summary = 'Distributed task execution system for complex workflows'
13
+ spec.description = 'Distributed task execution system for complex workflows'
14
+ spec.homepage = 'https://github.com/FindHotel/qyu'
15
+ spec.required_ruby_version = '>= 2.4'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
18
+ f.match(%r{^(test|spec|features)/})
19
+ end
20
+ spec.bindir = "exe"
21
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
+ spec.require_paths = ["lib"]
23
+
24
+ spec.add_runtime_dependency 'activesupport', '~> 5.1'
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.16'
27
+ spec.add_development_dependency 'dotenv'
28
+ spec.add_development_dependency 'rack-test'
29
+ spec.add_development_dependency 'pry'
30
+ spec.add_development_dependency 'pry-byebug'
31
+ spec.add_development_dependency 'rake', '~> 10.0'
32
+ spec.add_development_dependency 'rspec', '~> 3.5'
33
+ spec.add_development_dependency 'simplecov'
34
+ spec.add_development_dependency 'sinatra'
35
+ spec.add_development_dependency 'timecop', '~> 0.8'
36
+ end
metadata ADDED
@@ -0,0 +1,278 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: qyu
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Elod Peter
8
+ - Mohamed Osama
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2018-02-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '5.1'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '5.1'
28
+ - !ruby/object:Gem::Dependency
29
+ name: bundler
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.16'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.16'
42
+ - !ruby/object:Gem::Dependency
43
+ name: dotenv
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: rack-test
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ type: :development
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ - !ruby/object:Gem::Dependency
71
+ name: pry
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: pry-byebug
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rake
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '10.0'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '10.0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: rspec
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '3.5'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '3.5'
126
+ - !ruby/object:Gem::Dependency
127
+ name: simplecov
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: '0'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ version: '0'
140
+ - !ruby/object:Gem::Dependency
141
+ name: sinatra
142
+ requirement: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ type: :development
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: '0'
154
+ - !ruby/object:Gem::Dependency
155
+ name: timecop
156
+ requirement: !ruby/object:Gem::Requirement
157
+ requirements:
158
+ - - "~>"
159
+ - !ruby/object:Gem::Version
160
+ version: '0.8'
161
+ type: :development
162
+ prerelease: false
163
+ version_requirements: !ruby/object:Gem::Requirement
164
+ requirements:
165
+ - - "~>"
166
+ - !ruby/object:Gem::Version
167
+ version: '0.8'
168
+ description: Distributed task execution system for complex workflows
169
+ email:
170
+ - bejmuller@gmail.com
171
+ - mohamed.o.alnagdy@gmail.com
172
+ executables: []
173
+ extensions: []
174
+ extra_rdoc_files: []
175
+ files:
176
+ - ".gitignore"
177
+ - ".rspec"
178
+ - ".travis.yml"
179
+ - CODE_OF_CONDUCT.md
180
+ - Gemfile
181
+ - LICENSE
182
+ - README.md
183
+ - Rakefile
184
+ - bin/console
185
+ - bin/server
186
+ - bin/setup
187
+ - examples/bin/simple
188
+ - examples/config.rb
189
+ - examples/simple/create_workflow.rb
190
+ - examples/simple/enqueue_job.rb
191
+ - examples/simple/worker.rb
192
+ - lib/qyu.rb
193
+ - lib/qyu/config.rb
194
+ - lib/qyu/errors.rb
195
+ - lib/qyu/errors/base.rb
196
+ - lib/qyu/errors/could_not_fetch_task.rb
197
+ - lib/qyu/errors/invalid_queue_name.rb
198
+ - lib/qyu/errors/invalid_task_attributes.rb
199
+ - lib/qyu/errors/job_not_found.rb
200
+ - lib/qyu/errors/lock_already_acquired.rb
201
+ - lib/qyu/errors/lock_not_acquired.rb
202
+ - lib/qyu/errors/message_not_received.rb
203
+ - lib/qyu/errors/not_implemented_error.rb
204
+ - lib/qyu/errors/payload_validation_error.rb
205
+ - lib/qyu/errors/task_not_found.rb
206
+ - lib/qyu/errors/task_status_update_failed.rb
207
+ - lib/qyu/errors/unknown_validation_option.rb
208
+ - lib/qyu/errors/unsync_error.rb
209
+ - lib/qyu/errors/workflow_descriptor_validation_error.rb
210
+ - lib/qyu/errors/workflow_not_found.rb
211
+ - lib/qyu/factory.rb
212
+ - lib/qyu/models.rb
213
+ - lib/qyu/models/concerns/workflow_descriptor_validator.rb
214
+ - lib/qyu/models/enums/status.rb
215
+ - lib/qyu/models/job.rb
216
+ - lib/qyu/models/task.rb
217
+ - lib/qyu/models/workflow.rb
218
+ - lib/qyu/queue.rb
219
+ - lib/qyu/queue/base.rb
220
+ - lib/qyu/queue/memory/adapter.rb
221
+ - lib/qyu/store.rb
222
+ - lib/qyu/store/base.rb
223
+ - lib/qyu/store/memory/adapter.rb
224
+ - lib/qyu/ui.rb
225
+ - lib/qyu/ui/helpers/pagination.rb
226
+ - lib/qyu/ui/public/bootstrap.min.css
227
+ - lib/qyu/ui/public/paper-dashboard.css
228
+ - lib/qyu/ui/public/script.js
229
+ - lib/qyu/ui/public/style.css
230
+ - lib/qyu/ui/views/footer.erb
231
+ - lib/qyu/ui/views/helpers/pagination.erb
232
+ - lib/qyu/ui/views/jobs.erb
233
+ - lib/qyu/ui/views/kaminari/_first_page.html.erb
234
+ - lib/qyu/ui/views/kaminari/_gap.html.erb
235
+ - lib/qyu/ui/views/kaminari/_last_page.html.erb
236
+ - lib/qyu/ui/views/kaminari/_next_page.html.erb
237
+ - lib/qyu/ui/views/kaminari/_page.html.erb
238
+ - lib/qyu/ui/views/kaminari/_paginator.html.erb
239
+ - lib/qyu/ui/views/kaminari/_prev_page.html.erb
240
+ - lib/qyu/ui/views/layout.erb
241
+ - lib/qyu/ui/views/navbar.erb
242
+ - lib/qyu/ui/views/pagination.erb
243
+ - lib/qyu/ui/views/show_job.erb
244
+ - lib/qyu/ui/views/sidebar.erb
245
+ - lib/qyu/ui/views/task_row.erb
246
+ - lib/qyu/utils.rb
247
+ - lib/qyu/version.rb
248
+ - lib/qyu/workers.rb
249
+ - lib/qyu/workers/base.rb
250
+ - lib/qyu/workers/concerns/callback.rb
251
+ - lib/qyu/workers/concerns/failure_queue.rb
252
+ - lib/qyu/workers/concerns/payload_validator.rb
253
+ - lib/qyu/workers/sync.rb
254
+ - qyu.gemspec
255
+ homepage: https://github.com/FindHotel/qyu
256
+ licenses: []
257
+ metadata: {}
258
+ post_install_message:
259
+ rdoc_options: []
260
+ require_paths:
261
+ - lib
262
+ required_ruby_version: !ruby/object:Gem::Requirement
263
+ requirements:
264
+ - - ">="
265
+ - !ruby/object:Gem::Version
266
+ version: '2.4'
267
+ required_rubygems_version: !ruby/object:Gem::Requirement
268
+ requirements:
269
+ - - ">="
270
+ - !ruby/object:Gem::Version
271
+ version: '0'
272
+ requirements: []
273
+ rubyforge_project:
274
+ rubygems_version: 2.7.4
275
+ signing_key:
276
+ specification_version: 4
277
+ summary: Distributed task execution system for complex workflows
278
+ test_files: []