asyncapi-client 0.6.0 → 0.11.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 +5 -5
- data/README.md +15 -3
- data/app/controllers/asyncapi/client/v1/jobs_controller.rb +2 -1
- data/app/models/asyncapi/client/job.rb +15 -7
- data/app/services/asyncapi/client/update_job.rb +3 -1
- data/app/workers/asyncapi/client/cleaner_worker.rb +1 -3
- data/app/workers/asyncapi/client/job_cleaner_worker.rb +39 -5
- data/app/workers/asyncapi/client/job_post_worker.rb +7 -2
- data/app/workers/asyncapi/client/job_time_out_worker.rb +4 -2
- data/db/migrate/20141104030959_create_asyncapi_client_jobs.rb +1 -1
- data/db/migrate/20141119011011_add_callback_params_to_asyncapi_client_jobs.rb +1 -1
- data/db/migrate/20141212064041_add_secret_to_asyncapi_client_job.rb +1 -1
- data/db/migrate/20150202062211_add_expired_at_to_asyncapi_client_job.rb +1 -1
- data/db/migrate/20150202062320_populate_asyncapi_client_job_expired_at.rb +1 -1
- data/db/migrate/20150610053320_add_on_time_out_to_asyncapi_client_job.rb +1 -1
- data/db/migrate/20150612082965_add_time_out_index_to_asyncapi_client_job.rb +1 -1
- data/db/migrate/20150630004215_add_response_code_to_asyncapi_client_jobs.rb +1 -1
- data/db/migrate/20150703001225_add_on_queue_error_to_asyncapi_client_jobs.rb +1 -1
- data/db/migrate/20190218200630_add_expired_at_index_to_asyncapi_client_jobs.rb +11 -0
- data/db/migrate/20190304200630_remove_expired_at_index_on_asyncapi_client_jobs.rb +5 -0
- data/lib/asyncapi/client.rb +4 -2
- data/lib/asyncapi/client/version.rb +1 -1
- metadata +42 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5fd1ef047e069d51524a6d6fa1a935dd21291f9287314f9c0cecedd06a4443be
|
4
|
+
data.tar.gz: 2103154fa8afb427645b952aa63e1503819ea961d38d0899e5efe5c01ed4b972
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a012d3e92b0955d0d35e520441eb2d17798740366c410e319a33f595826ab1368ceb197a4ae27995d7610b2aceb5a644820b96488b0551203506e1f535a36d65
|
7
|
+
data.tar.gz: 41a1a7a745dc6e67fb9097dedb1f97c4f3cf03e3ab97378567f0bbc7023bf7283cc83fd36fef2c0a6f6ebc08a556f9bee1eaf48200d13123038faa6de90c2bf2
|
data/README.md
CHANGED
@@ -73,9 +73,11 @@ There is a feed of all jobs that can be accessed via `/asyncapi/client/v1/jobs.j
|
|
73
73
|
|
74
74
|
## Expiry
|
75
75
|
|
76
|
-
To make space in the database, old jobs must be deleted. By default, jobs older than
|
76
|
+
To make space in the database, old jobs must be deleted. By default, jobs older than 4 days will be deleted in both the Asyncapi Client and Asyncapi Server. Asyncapi Client is responsible for deleting the jobs it no longer needs a response from on the server.
|
77
77
|
|
78
|
-
|
78
|
+
**Important:** keep in mind that this setting may conflict with the `successful_jobs_deletion_after` setting with jobs in `success` state, which normally are deleted after they reach this state (see [Successful jobs automatic deletion](#successful-jobs-automatic-deletion) for more information).
|
79
|
+
|
80
|
+
By default, jobs 4 days old and older will be deleted. You can change this setting by putting this in an initializer:
|
79
81
|
|
80
82
|
```ruby
|
81
83
|
Asyncapi::Client.expiry_threshold = 5.days
|
@@ -89,6 +91,16 @@ The cleaner job is run every day at "0 0 * * *". If you want to change the frequ
|
|
89
91
|
Asyncapi::Client.clean_job_cron = "30 2 * * *"
|
90
92
|
```
|
91
93
|
|
94
|
+
## Successful jobs automatic deletion
|
95
|
+
|
96
|
+
After a job completes successfully, we schedule another job to delete it after a brief period of time to avoid having a lot of records on the table. By default, a successful job is deleted from the table after 2 minutes, ignoring the `expiry_threshold` configuration option. You can change this setting using the `successful_jobs_deletion_after` configuration option in an initializer if you want to extend or shorten the wait time for deletion:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
Asyncapi::Client.successful_jobs_deletion_after = 3.days
|
100
|
+
```
|
101
|
+
|
102
|
+
**Important:** if you want to ignore `successful_jobs_deletion_after` setting in favor of `expiry_threshold`, set `successful_jobs_deletion_after` to a value greater than `expiry_threshold`.
|
103
|
+
|
92
104
|
# Installation
|
93
105
|
|
94
106
|
**Note**: if you're using the `protected_attributes`, also see the "Optional" section below.
|
@@ -156,7 +168,7 @@ require "asyncapi/client/factories"
|
|
156
168
|
# Development
|
157
169
|
|
158
170
|
```
|
159
|
-
rake
|
171
|
+
rake db:migrate && rake db:migrate RAILS_ENV=test
|
160
172
|
rspec spec
|
161
173
|
```
|
162
174
|
|
@@ -1,6 +1,7 @@
|
|
1
1
|
module Asyncapi::Client
|
2
2
|
module V1
|
3
3
|
class JobsController < Asyncapi::Client.parent_controller
|
4
|
+
include Rails::Pagination
|
4
5
|
|
5
6
|
def index
|
6
7
|
jobs = Job.all
|
@@ -12,7 +13,7 @@ module Asyncapi::Client
|
|
12
13
|
UpdateJob.execute(job: job, params: job_params)
|
13
14
|
render json: job
|
14
15
|
else
|
15
|
-
|
16
|
+
head :forbidden
|
16
17
|
end
|
17
18
|
end
|
18
19
|
|
@@ -21,7 +21,7 @@ module Asyncapi::Client
|
|
21
21
|
transitions from: :fresh, to: :queued
|
22
22
|
end
|
23
23
|
|
24
|
-
event :succeed do
|
24
|
+
event :succeed, after: :schedule_for_deletion do
|
25
25
|
transitions from: :queued, to: :success
|
26
26
|
end
|
27
27
|
|
@@ -40,6 +40,10 @@ module Asyncapi::Client
|
|
40
40
|
|
41
41
|
scope :expired, -> { where(arel_table[:expired_at].lt(Time.now)) }
|
42
42
|
scope :with_time_out, -> { where(arel_table[:time_out_at].not_eq(nil)) }
|
43
|
+
scope :stale, -> (stale_duration = 5) do
|
44
|
+
where(arel_table[:updated_at].lteq(stale_duration.minutes.ago)).
|
45
|
+
where(status: statuses[:queued])
|
46
|
+
end
|
43
47
|
scope :for_time_out, -> do
|
44
48
|
where(arel_table[:time_out_at].lt(Time.now)).
|
45
49
|
where(status: [statuses[:queued], statuses[:fresh]])
|
@@ -70,18 +74,15 @@ module Asyncapi::Client
|
|
70
74
|
}
|
71
75
|
args[:time_out_at] = time_out.from_now if time_out
|
72
76
|
job = create(args)
|
73
|
-
|
77
|
+
ActiveRecord::Base.after_transaction do
|
78
|
+
JobPostWorker.perform_async(job.id, url)
|
79
|
+
end
|
74
80
|
end
|
75
81
|
|
76
82
|
def url
|
77
83
|
Asyncapi::Client::Engine.routes.url_helpers.v1_job_url(self)
|
78
84
|
end
|
79
85
|
|
80
|
-
def body=(body)
|
81
|
-
json = body.is_a?(Hash) ? body.to_json : body
|
82
|
-
write_attribute :body, json
|
83
|
-
end
|
84
|
-
|
85
86
|
[:on_success, :on_error, :on_queue, :on_time_out, :on_queue_error].each do |attr|
|
86
87
|
define_method("#{attr}=") do |klass|
|
87
88
|
write_attribute attr, klass.to_s
|
@@ -90,6 +91,13 @@ module Asyncapi::Client
|
|
90
91
|
|
91
92
|
private
|
92
93
|
|
94
|
+
def schedule_for_deletion
|
95
|
+
if success?
|
96
|
+
# delete in a couple of minutes, giving time for the success to be broadcasted
|
97
|
+
JobCleanerWorker.perform_in(Asyncapi::Client.successful_jobs_deletion_after, self.id)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
93
101
|
def set_expired_at
|
94
102
|
self.expired_at ||= Asyncapi::Client.expiry_threshold.from_now
|
95
103
|
end
|
@@ -9,7 +9,9 @@ module Asyncapi::Client
|
|
9
9
|
if may_transition?(job, to: status)
|
10
10
|
transition(job, to: status)
|
11
11
|
if job.status_changed? && job.save
|
12
|
-
|
12
|
+
ActiveRecord::Base.after_transaction do
|
13
|
+
JobStatusWorker.perform_async(job.id)
|
14
|
+
end
|
13
15
|
else
|
14
16
|
job.save
|
15
17
|
end
|
@@ -7,7 +7,7 @@ module Asyncapi
|
|
7
7
|
|
8
8
|
def perform(job_id)
|
9
9
|
if job = Job.find_by(id: job_id)
|
10
|
-
destroy_remote
|
10
|
+
destroy_remote(job)
|
11
11
|
job.destroy
|
12
12
|
end
|
13
13
|
end
|
@@ -15,12 +15,46 @@ module Asyncapi
|
|
15
15
|
private
|
16
16
|
|
17
17
|
def destroy_remote(job)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
18
|
+
errors = validate_remote_job_info(job)
|
19
|
+
if errors.empty?
|
20
|
+
Typhoeus.delete(job.server_job_url, {
|
21
|
+
params: { secret: job.secret },
|
22
|
+
headers: job.headers,
|
23
|
+
})
|
24
|
+
else
|
25
|
+
log_remote_error_for(job, errors)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def validate_remote_job_info(job)
|
30
|
+
errors = []
|
31
|
+
errors << "server_job_url is invalid" unless url_ok_for?(job)
|
32
|
+
errors << "authorization headers are not present" unless headers_ok_for?(job)
|
33
|
+
errors << "secret is not present" unless job.secret.present?
|
34
|
+
errors
|
35
|
+
end
|
36
|
+
|
37
|
+
def url_ok_for?(job)
|
38
|
+
uri = URI.parse(job.server_job_url)
|
39
|
+
uri.is_a?(URI::HTTP) && !uri.host.nil?
|
40
|
+
rescue URI::InvalidURIError
|
41
|
+
false
|
22
42
|
end
|
23
43
|
|
44
|
+
def headers_ok_for?(job)
|
45
|
+
job.headers.is_a?(Hash) && job.headers[:AUTHORIZATION]
|
46
|
+
end
|
47
|
+
|
48
|
+
def log_remote_error_for(job, errors)
|
49
|
+
if defined?(G5::Logger::Log)
|
50
|
+
G5::Logger::Log.send(:warn, {
|
51
|
+
origin: "#{self.class.name}#destroy_remote",
|
52
|
+
external_parent_id: "#{job.id}",
|
53
|
+
message: "Not enough info to delete expired remote job: #{errors.join(", ")}",
|
54
|
+
error: "Unable to delete remote job",
|
55
|
+
})
|
56
|
+
end
|
57
|
+
end
|
24
58
|
end
|
25
59
|
end
|
26
60
|
end
|
@@ -21,12 +21,16 @@ module Asyncapi::Client
|
|
21
21
|
job.assign_attributes(job_params_from(response))
|
22
22
|
job.enqueue
|
23
23
|
if job.save!
|
24
|
-
|
24
|
+
ActiveRecord::Base.after_transaction do
|
25
|
+
JobStatusWorker.perform_async(job.id)
|
26
|
+
end
|
25
27
|
end
|
26
28
|
else
|
27
29
|
job.fail_queue
|
28
30
|
if job.update_attributes!(message: response.body, response_code: response.response_code)
|
29
|
-
|
31
|
+
ActiveRecord::Base.after_transaction do
|
32
|
+
JobStatusWorker.perform_async(job.id)
|
33
|
+
end
|
30
34
|
end
|
31
35
|
end
|
32
36
|
end
|
@@ -38,6 +42,7 @@ module Asyncapi::Client
|
|
38
42
|
end
|
39
43
|
|
40
44
|
def server_params_from(job, params)
|
45
|
+
params = params.to_json if params.is_a? Hash
|
41
46
|
{
|
42
47
|
job: {
|
43
48
|
callback_url: job.url,
|
@@ -12,8 +12,10 @@ module Asyncapi::Client
|
|
12
12
|
private
|
13
13
|
|
14
14
|
def time_out_job(job)
|
15
|
-
job.
|
16
|
-
|
15
|
+
job.update(status: :timed_out)
|
16
|
+
ActiveRecord::Base.after_transaction do
|
17
|
+
JobStatusWorker.perform_async(job.id)
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
21
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class PopulateAsyncapiClientJobExpiredAt < ActiveRecord::Migration
|
1
|
+
class PopulateAsyncapiClientJobExpiredAt < ActiveRecord::Migration[4.2]
|
2
2
|
def change
|
3
3
|
Asyncapi::Client::Job.find_each do |job|
|
4
4
|
job.update_attributes(expired_at: Asyncapi::Client.expiry_threshold.from_now)
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class AddExpiredAtIndexToAsyncapiClientJobs < ActiveRecord::Migration[5.0]
|
2
|
+
disable_ddl_transaction!
|
3
|
+
|
4
|
+
def change
|
5
|
+
opts = {}
|
6
|
+
if !!(ActiveRecord::Base.connection_config[:adapter] =~ /postgresql/i)
|
7
|
+
opts[:algorithm] = :concurrently
|
8
|
+
end
|
9
|
+
add_index :asyncapi_client_jobs, :expired_at, opts
|
10
|
+
end
|
11
|
+
end
|
data/lib/asyncapi/client.rb
CHANGED
@@ -3,15 +3,17 @@ require "sidekiq-cron"
|
|
3
3
|
require "api-pagination"
|
4
4
|
require "typhoeus"
|
5
5
|
require 'aasm'
|
6
|
+
require 'ar_after_transaction'
|
6
7
|
require "asyncapi/client/engine"
|
7
8
|
require "securerandom"
|
8
9
|
|
9
10
|
module Asyncapi
|
10
11
|
module Client
|
11
12
|
|
12
|
-
CONFIG_ATTRS = %i[parent_controller expiry_threshold clean_job_cron]
|
13
|
+
CONFIG_ATTRS = %i[parent_controller expiry_threshold clean_job_cron successful_jobs_deletion_after]
|
13
14
|
mattr_accessor(*CONFIG_ATTRS)
|
14
|
-
self.expiry_threshold =
|
15
|
+
self.expiry_threshold = 4.days
|
16
|
+
self.successful_jobs_deletion_after = 2.minutes
|
15
17
|
self.clean_job_cron = "0 0 * * *"
|
16
18
|
|
17
19
|
def self.configure
|
metadata
CHANGED
@@ -1,31 +1,31 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asyncapi-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- G5
|
8
8
|
- Marc Ignacio
|
9
9
|
- Ramon Tayag
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date:
|
13
|
+
date: 2021-06-09 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
requirements:
|
19
|
-
- - "
|
19
|
+
- - "~>"
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
21
|
+
version: '6.0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
25
25
|
requirements:
|
26
|
-
- - "
|
26
|
+
- - "~>"
|
27
27
|
- !ruby/object:Gem::Version
|
28
|
-
version: '
|
28
|
+
version: '6.0'
|
29
29
|
- !ruby/object:Gem::Dependency
|
30
30
|
name: sidekiq
|
31
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -111,19 +111,47 @@ dependencies:
|
|
111
111
|
- !ruby/object:Gem::Version
|
112
112
|
version: '4.0'
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
|
-
name:
|
114
|
+
name: ar_after_transaction
|
115
115
|
requirement: !ruby/object:Gem::Requirement
|
116
116
|
requirements:
|
117
117
|
- - ">="
|
118
118
|
- !ruby/object:Gem::Version
|
119
119
|
version: '0'
|
120
|
-
type: :
|
120
|
+
type: :runtime
|
121
121
|
prerelease: false
|
122
122
|
version_requirements: !ruby/object:Gem::Requirement
|
123
123
|
requirements:
|
124
124
|
- - ">="
|
125
125
|
- !ruby/object:Gem::Version
|
126
126
|
version: '0'
|
127
|
+
- !ruby/object:Gem::Dependency
|
128
|
+
name: sprockets
|
129
|
+
requirement: !ruby/object:Gem::Requirement
|
130
|
+
requirements:
|
131
|
+
- - "<"
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '4'
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - "<"
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '4'
|
141
|
+
- !ruby/object:Gem::Dependency
|
142
|
+
name: sqlite3
|
143
|
+
requirement: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - "~>"
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: 1.4.2
|
148
|
+
type: :development
|
149
|
+
prerelease: false
|
150
|
+
version_requirements: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - "~>"
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: 1.4.2
|
127
155
|
- !ruby/object:Gem::Dependency
|
128
156
|
name: rspec-rails
|
129
157
|
requirement: !ruby/object:Gem::Requirement
|
@@ -253,6 +281,8 @@ files:
|
|
253
281
|
- db/migrate/20150612082965_add_time_out_index_to_asyncapi_client_job.rb
|
254
282
|
- db/migrate/20150630004215_add_response_code_to_asyncapi_client_jobs.rb
|
255
283
|
- db/migrate/20150703001225_add_on_queue_error_to_asyncapi_client_jobs.rb
|
284
|
+
- db/migrate/20190218200630_add_expired_at_index_to_asyncapi_client_jobs.rb
|
285
|
+
- db/migrate/20190304200630_remove_expired_at_index_on_asyncapi_client_jobs.rb
|
256
286
|
- lib/asyncapi-client.rb
|
257
287
|
- lib/asyncapi/client.rb
|
258
288
|
- lib/asyncapi/client/engine.rb
|
@@ -264,7 +294,7 @@ homepage: https://github.com/G5/asyncapi-client
|
|
264
294
|
licenses:
|
265
295
|
- MIT
|
266
296
|
metadata: {}
|
267
|
-
post_install_message:
|
297
|
+
post_install_message:
|
268
298
|
rdoc_options: []
|
269
299
|
require_paths:
|
270
300
|
- lib
|
@@ -279,9 +309,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
279
309
|
- !ruby/object:Gem::Version
|
280
310
|
version: '0'
|
281
311
|
requirements: []
|
282
|
-
|
283
|
-
|
284
|
-
signing_key:
|
312
|
+
rubygems_version: 3.0.9
|
313
|
+
signing_key:
|
285
314
|
specification_version: 4
|
286
315
|
summary: Asynchronous API communication
|
287
316
|
test_files: []
|