web_task_runner 0.0.4 → 0.0.5
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 +4 -4
- data/README.md +76 -8
- data/lib/web_task_runner.rb +33 -11
- data/lib/web_task_runner/redis_module.rb +9 -1
- data/lib/web_task_runner/version.rb +1 -1
- data/web_task_runner.gemspec +1 -0
- metadata +15 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa3d96c91c52ee015b141cdfd3a166f9ab0ae680
|
|
4
|
+
data.tar.gz: 21bd106643b4e50183b9fa5232cff82f2902fc1b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2118e07ec979f23255dcb1ab83ec17a58d131a0fcdf3033bd1ffcb0bd1e7f95ec4f7175939e5195f4863d3fb905389c67f058ef0f3e21c469cb0f3529270318d
|
|
7
|
+
data.tar.gz: a9c40f240304c6543d0d8bc6f38c14c9b3274c89223caf510c64b5514282ebb78dabcf2a4af9e0a181c0a2d6f537fdb1c823a7f6f1418d80346f1121059bf317
|
data/README.md
CHANGED
|
@@ -26,6 +26,78 @@ And then execute:
|
|
|
26
26
|
Redis is required to run the background jobs. Make sure you have one, and set
|
|
27
27
|
the `REDIS_URL` environment variable to the Redis URL.
|
|
28
28
|
|
|
29
|
+
## Usage
|
|
30
|
+
|
|
31
|
+
Just `require 'web_task_runner'` and append jobs to it
|
|
32
|
+
(`WebTaskRunner.jobs << SomeWork`). Then you'll have a Rack app `WebTaskRunner`
|
|
33
|
+
providing web APIs ready to be mounted. Configurations `REDIS_URL`, `API_KEY`
|
|
34
|
+
and `REDIS_NAMESPACE` can be set through environment variables.
|
|
35
|
+
|
|
36
|
+
Please refer the [Getting Start](#getting-start) section for more details.
|
|
37
|
+
|
|
38
|
+
### API Endpoints
|
|
39
|
+
|
|
40
|
+
Note that all APIs has been secured with the `API_KEY`. Each request should
|
|
41
|
+
pass the matching `API_KEY` with the `key` parameter
|
|
42
|
+
(e.g.: `https://example.app/?key=secreat_key`), otherwise an `401 Unauthorized`
|
|
43
|
+
error will be returned.
|
|
44
|
+
|
|
45
|
+
#### `GET /`
|
|
46
|
+
|
|
47
|
+
Returns the information of the task runner.
|
|
48
|
+
|
|
49
|
+
#### `GET /status`
|
|
50
|
+
|
|
51
|
+
Returns the current (or last) status of running task.
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
HTTP/1.1 200 OK
|
|
55
|
+
|
|
56
|
+
{
|
|
57
|
+
"status": "processing",
|
|
58
|
+
"progress": 0.52,
|
|
59
|
+
"started_at": "2015-05-29 22:36:35 +0000"
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- status: can be `processing`, `ok` or `error`
|
|
64
|
+
- progress: an float representing the current working progress, presented only
|
|
65
|
+
if the task is currently in progress
|
|
66
|
+
- started_at: time of when the task has been started
|
|
67
|
+
- finished_at: time of when the task has finished, presented only
|
|
68
|
+
if the last task is finished
|
|
69
|
+
|
|
70
|
+
#### `GET /start`
|
|
71
|
+
|
|
72
|
+
Start to run the task (if the task is not currently running).
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
HTTP/1.1 202 Accepted
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
"status": "processing",
|
|
79
|
+
"link": "https://example.app/status?key=secreat_key"
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- status: must be `processing`, since the task will be run asynchronously
|
|
84
|
+
- link: URL for monitoring the started task
|
|
85
|
+
|
|
86
|
+
#### `GET /stop`
|
|
87
|
+
|
|
88
|
+
Force stop the current running task.
|
|
89
|
+
|
|
90
|
+
```json
|
|
91
|
+
HTTP/1.1 200 OK
|
|
92
|
+
|
|
93
|
+
{
|
|
94
|
+
"status": "error",
|
|
95
|
+
"link": "https://example.app/status?key=secreat_key",
|
|
96
|
+
"started_at": "2015-05-29 22:36:35 +0000",
|
|
97
|
+
"finished_at": "2015-05-29 23:12:48 +0000"
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
29
101
|
## Getting Start
|
|
30
102
|
|
|
31
103
|
Create and `cd` into a new folder to place the task runner app. After adding
|
|
@@ -41,6 +113,7 @@ app to run, you can set it using `$ export` or save them into a file called
|
|
|
41
113
|
|
|
42
114
|
- `REDIS_URL`: specify the Redis to connect to
|
|
43
115
|
- `API_KEY`: chose a secret key for accessing the web API
|
|
116
|
+
- `REDIS_NAMESPACE`: _(optional)_ namespacing Redis keys
|
|
44
117
|
|
|
45
118
|
### Create The App
|
|
46
119
|
|
|
@@ -106,7 +179,7 @@ class MyWorkOne < WebTaskRunner::TaskWorker
|
|
|
106
179
|
sleep(1)
|
|
107
180
|
raise if Random.rand(100) < 2 # simulate errors
|
|
108
181
|
# report the current progress
|
|
109
|
-
WebTaskRunner.job_1_progress = (i + 1) / 10
|
|
182
|
+
WebTaskRunner.job_1_progress = (i + 1) / 10.0
|
|
110
183
|
end
|
|
111
184
|
end
|
|
112
185
|
end
|
|
@@ -121,16 +194,11 @@ require 'web_task_runner'
|
|
|
121
194
|
|
|
122
195
|
class MyWorkOne < WebTaskRunner::TaskWorker
|
|
123
196
|
def exec
|
|
124
|
-
#
|
|
125
|
-
10.times do |i|
|
|
126
|
-
sleep(1)
|
|
127
|
-
raise if Random.rand(100) < 2 # simulate errors
|
|
128
|
-
# report the current progress
|
|
129
|
-
WebTaskRunner.job_1_progress = (i + 1) / 10
|
|
130
|
-
end
|
|
197
|
+
# ...
|
|
131
198
|
end
|
|
132
199
|
end
|
|
133
200
|
|
|
201
|
+
# append the job to task runner
|
|
134
202
|
WebTaskRunner.jobs << MyWorkOne
|
|
135
203
|
```
|
|
136
204
|
|
data/lib/web_task_runner.rb
CHANGED
|
@@ -17,7 +17,7 @@ class WebTaskRunner < Sinatra::Application
|
|
|
17
17
|
@@jobs
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
-
# GET /?key=<api_key> - retrieve current state of the
|
|
20
|
+
# GET /?key=<api_key> - retrieve current state of the task runner
|
|
21
21
|
get '/' do
|
|
22
22
|
# Authorize the request
|
|
23
23
|
error 401, JSON.pretty_generate(error: 'Unauthorized') and \
|
|
@@ -26,7 +26,16 @@ class WebTaskRunner < Sinatra::Application
|
|
|
26
26
|
return JSON.pretty_generate(current_info)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
# GET
|
|
29
|
+
# GET /?key=<api_key> - retrieve current status of the task
|
|
30
|
+
get '/status' do
|
|
31
|
+
# Authorize the request
|
|
32
|
+
error 401, JSON.pretty_generate(error: 'Unauthorized') and \
|
|
33
|
+
return if ENV['API_KEY'] != params[:key]
|
|
34
|
+
|
|
35
|
+
return JSON.pretty_generate(current_status)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# GET /start?key=<api_key> - start the task if idle
|
|
30
39
|
get '/start' do
|
|
31
40
|
# Authorize the request
|
|
32
41
|
error 401, JSON.pretty_generate(error: 'Unauthorized') and \
|
|
@@ -34,18 +43,21 @@ class WebTaskRunner < Sinatra::Application
|
|
|
34
43
|
|
|
35
44
|
start_task_if_idle
|
|
36
45
|
|
|
37
|
-
|
|
46
|
+
link = "#{request.env['rack.url_scheme']}://#{request.env['HTTP_HOST']}/status?key=#{params[:key]}"
|
|
47
|
+
|
|
48
|
+
status 202
|
|
49
|
+
return JSON.pretty_generate({ status: 'processing', link: link })
|
|
38
50
|
end
|
|
39
51
|
|
|
40
|
-
# GET /
|
|
41
|
-
get '/
|
|
52
|
+
# GET /stop?key=<api_key> - kill the working task
|
|
53
|
+
get '/stop' do
|
|
42
54
|
# Authorize the request
|
|
43
55
|
error 401, JSON.pretty_generate(error: 'Unauthorized') and \
|
|
44
56
|
return if ENV['API_KEY'] != params[:key]
|
|
45
57
|
|
|
46
58
|
kill_task
|
|
47
59
|
|
|
48
|
-
return
|
|
60
|
+
return JSON.pretty_generate(current_status)
|
|
49
61
|
end
|
|
50
62
|
|
|
51
63
|
# Report that a job has been done, call this in each job after
|
|
@@ -61,6 +73,7 @@ class WebTaskRunner < Sinatra::Application
|
|
|
61
73
|
# set the state to idle if all the works has been done
|
|
62
74
|
if WebTaskRunner::RedisModule.redis.get('task:working_jobs').to_i < 1
|
|
63
75
|
WebTaskRunner::RedisModule.redis.set('task:state', 'idle')
|
|
76
|
+
WebTaskRunner::RedisModule.redis.set('task:status', 'ok')
|
|
64
77
|
WebTaskRunner::RedisModule.redis.set('task:finished_at', Time.now)
|
|
65
78
|
end
|
|
66
79
|
end
|
|
@@ -78,6 +91,7 @@ class WebTaskRunner < Sinatra::Application
|
|
|
78
91
|
def self.start_task
|
|
79
92
|
kill_task
|
|
80
93
|
WebTaskRunner::RedisModule.redis.set('task:state', 'working')
|
|
94
|
+
WebTaskRunner::RedisModule.redis.set('task:status', 'processing')
|
|
81
95
|
WebTaskRunner::RedisModule.redis.set('task:started_at', Time.now)
|
|
82
96
|
|
|
83
97
|
# Set the count of jobs that should be started
|
|
@@ -113,14 +127,16 @@ class WebTaskRunner < Sinatra::Application
|
|
|
113
127
|
# Kills the running task
|
|
114
128
|
def self.kill_task
|
|
115
129
|
ps = Sidekiq::ProcessSet.new
|
|
130
|
+
killed_count = 0
|
|
116
131
|
ps.each do |p|
|
|
117
|
-
p.stop! if p['busy'] > 0
|
|
132
|
+
p.stop! and killed_count += 1 if p['busy'] > 0
|
|
118
133
|
end
|
|
119
134
|
sleep(0.5)
|
|
120
135
|
Sidekiq::Queue.new.clear
|
|
121
136
|
Sidekiq::ScheduledSet.new.clear
|
|
122
137
|
Sidekiq::RetrySet.new.clear
|
|
123
138
|
WebTaskRunner.job_ended(all: true)
|
|
139
|
+
WebTaskRunner::RedisModule.redis.set('task:status', 'error') if killed_count > 0
|
|
124
140
|
end
|
|
125
141
|
|
|
126
142
|
def kill_task # :nodoc:
|
|
@@ -174,7 +190,7 @@ class WebTaskRunner < Sinatra::Application
|
|
|
174
190
|
WebTaskRunner.task_finished_at
|
|
175
191
|
end
|
|
176
192
|
|
|
177
|
-
# Get the info of the task
|
|
193
|
+
# Get the info of the task runner
|
|
178
194
|
def self.current_info
|
|
179
195
|
info = { state: current_state }
|
|
180
196
|
info[:task_progress] = task_progress if task_progress
|
|
@@ -188,11 +204,17 @@ class WebTaskRunner < Sinatra::Application
|
|
|
188
204
|
WebTaskRunner.current_info
|
|
189
205
|
end
|
|
190
206
|
|
|
191
|
-
# Get the status of the task
|
|
207
|
+
# Get the status of the task
|
|
192
208
|
def self.current_status
|
|
193
|
-
|
|
209
|
+
task_status = WebTaskRunner::RedisModule.redis.get('task:status')
|
|
210
|
+
return {} unless task_status
|
|
194
211
|
|
|
195
|
-
|
|
212
|
+
status = { status: task_status }
|
|
213
|
+
status[:progress] = task_progress if task_progress && task_status == 'processing'
|
|
214
|
+
status[:started_at] = task_started_at if task_started_at
|
|
215
|
+
status[:finished_at] = task_finished_at if task_finished_at
|
|
216
|
+
|
|
217
|
+
status
|
|
196
218
|
end
|
|
197
219
|
|
|
198
220
|
def current_status # :nodoc:
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
require 'sinatra'
|
|
2
2
|
require 'sidekiq'
|
|
3
|
+
require 'redis-namespace'
|
|
3
4
|
|
|
4
5
|
class WebTaskRunner < Sinatra::Application
|
|
5
6
|
module RedisModule
|
|
6
7
|
def self.connection
|
|
7
|
-
|
|
8
|
+
if ENV['REDIS_NAMESPACE']
|
|
9
|
+
proc do
|
|
10
|
+
redis_c = Redis.new(url: ENV['REDIS_URL'])
|
|
11
|
+
Redis::Namespace.new(ENV['REDIS_NAMESPACE'], redis: redis_c)
|
|
12
|
+
end
|
|
13
|
+
else
|
|
14
|
+
proc { Redis.new(url: ENV['REDIS_URL']) }
|
|
15
|
+
end
|
|
8
16
|
end
|
|
9
17
|
|
|
10
18
|
def self.redis
|
data/web_task_runner.gemspec
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: web_task_runner
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Neson
|
|
@@ -66,6 +66,20 @@ dependencies:
|
|
|
66
66
|
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
68
|
version: '0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: redis-namespace
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - ">="
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '0'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - ">="
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '0'
|
|
69
83
|
- !ruby/object:Gem::Dependency
|
|
70
84
|
name: dotenv
|
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|