asyncapi-client 0.6.0 → 0.11.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
- SHA1:
3
- metadata.gz: 2c4aa942b90ab8794c0eaeb572810d4277581df5
4
- data.tar.gz: 186bd9cf4144c883d8f532e18caa8bd5143c2755
2
+ SHA256:
3
+ metadata.gz: 5fd1ef047e069d51524a6d6fa1a935dd21291f9287314f9c0cecedd06a4443be
4
+ data.tar.gz: 2103154fa8afb427645b952aa63e1503819ea961d38d0899e5efe5c01ed4b972
5
5
  SHA512:
6
- metadata.gz: 6553230b72635076b4fee02bb0a47fd04b50821c6ddae57f3819bc353f33289c151eadbfe5fbcd8be0a58cb8e36f07d28209e7684ffee3aef7c6c82876c5e1a1
7
- data.tar.gz: a4358536d0282459c8830a2009b761d60d008ea5dfdfa6c7be598edd75c5effa8629b18ccfd583c18f323b24974c2beedbeab90caf94c4a6c28f065e0e66ed0a
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 10 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.
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
- By default, jobs 10 days old and older will be deleted. You can change this setting by putting this in an initializer:
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 app:db:schema:load
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
- render nothing: true, status: 403
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
- JobPostWorker.perform_async(job.id, url)
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
- JobStatusWorker.perform_async(job.id)
12
+ ActiveRecord::Base.after_transaction do
13
+ JobStatusWorker.perform_async(job.id)
14
+ end
13
15
  else
14
16
  job.save
15
17
  end
@@ -6,9 +6,7 @@ module Asyncapi
6
6
  sidekiq_options retry: false
7
7
 
8
8
  def perform
9
- Job.expired.find_each do |job|
10
- JobCleanerWorker.perform_async(job.id)
11
- end
9
+ Job.expired.pluck(:id).each{ |job_id| JobCleanerWorker.perform_async(job_id) }
12
10
  end
13
11
 
14
12
  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 job
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
- Typhoeus.delete(job.server_job_url, {
19
- params: { secret: job.secret },
20
- headers: job.headers,
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
- JobStatusWorker.perform_async(job.id)
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
- JobStatusWorker.perform_async(job.id)
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.update_attributes(status: :timed_out)
16
- JobStatusWorker.perform_async(job.id)
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 CreateAsyncapiClientJobs < ActiveRecord::Migration
1
+ class CreateAsyncapiClientJobs < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  create_table :asyncapi_client_jobs do |t|
4
4
  t.string "server_job_url"
@@ -1,4 +1,4 @@
1
- class AddCallbackParamsToAsyncapiClientJobs < ActiveRecord::Migration
1
+ class AddCallbackParamsToAsyncapiClientJobs < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_column :asyncapi_client_jobs, :callback_params, :text
4
4
  end
@@ -1,4 +1,4 @@
1
- class AddSecretToAsyncapiClientJob < ActiveRecord::Migration
1
+ class AddSecretToAsyncapiClientJob < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_column :asyncapi_client_jobs, :secret, :string
4
4
  end
@@ -1,4 +1,4 @@
1
- class AddExpiredAtToAsyncapiClientJob < ActiveRecord::Migration
1
+ class AddExpiredAtToAsyncapiClientJob < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_column :asyncapi_client_jobs, :expired_at, :datetime
4
4
  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)
@@ -1,4 +1,4 @@
1
- class AddOnTimeOutToAsyncapiClientJob < ActiveRecord::Migration
1
+ class AddOnTimeOutToAsyncapiClientJob < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_column :asyncapi_client_jobs, :on_time_out, :string
4
4
  end
@@ -1,4 +1,4 @@
1
- class AddTimeOutIndexToAsyncapiClientJob < ActiveRecord::Migration
1
+ class AddTimeOutIndexToAsyncapiClientJob < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_index :asyncapi_client_jobs, :time_out_at
4
4
  end
@@ -1,4 +1,4 @@
1
- class AddResponseCodeToAsyncapiClientJobs < ActiveRecord::Migration
1
+ class AddResponseCodeToAsyncapiClientJobs < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_column :asyncapi_client_jobs, :response_code, :integer
4
4
  end
@@ -1,4 +1,4 @@
1
- class AddOnQueueErrorToAsyncapiClientJobs < ActiveRecord::Migration
1
+ class AddOnQueueErrorToAsyncapiClientJobs < ActiveRecord::Migration[4.2]
2
2
  def change
3
3
  add_column :asyncapi_client_jobs, :on_queue_error, :string
4
4
  end
@@ -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
@@ -0,0 +1,5 @@
1
+ class RemoveExpiredAtIndexOnAsyncapiClientJobs < ActiveRecord::Migration[5.0]
2
+ def change
3
+ remove_index :asyncapi_client_jobs, :expired_at
4
+ end
5
+ end
@@ -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 = 10.days
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
@@ -1,5 +1,5 @@
1
1
  module Asyncapi
2
2
  module Client
3
- VERSION = "0.6.0"
3
+ VERSION = "0.11.0".freeze
4
4
  end
5
5
  end
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.6.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: 2016-05-26 00:00:00.000000000 Z
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: '4.0'
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: '4.0'
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: sqlite3
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: :development
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
- rubyforge_project:
283
- rubygems_version: 2.5.1
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: []