deferred_request 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 8a9e96cf574be720de97ae91ae7f06d09b082d56ffc2aef3eae449653dbce7b9
4
+ data.tar.gz: f604991997404bf38fad4cae5fd40b5b00088d952f0f3d15bd1a64b4f9d4a078
5
+ SHA512:
6
+ metadata.gz: ffa3d29e8e24b1c6dc48200cb6463f4facef2ded394cd820b0a5083dee8948f779b2f0e439779a8276a786dffbfc6790b20679a98d1481861a2b8bd9410677a3
7
+ data.tar.gz: 5bffe0fe31acd967710261f6a23925ccf48db5b9e1b573df520eec7d6d42c97df13cf92ac1d7853007d945fd3ac4ae2fb2ecee0cff8bef62eaf70dc380d08673
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Austin Miller
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # Deferred Request
2
+ A simple plugin to defer an http request until you can actually process it. This is good in situtations where work performed is not needed immidiately (think status callbacks from services like Twilio or Stripe). This pattern can help prevent you from getting DDoS'd by services you might interact with.
3
+
4
+ ## Installation
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem "deferred_request"
9
+ ```
10
+
11
+ And then execute:
12
+ ```bash
13
+ $ bundle
14
+ ```
15
+
16
+ Or install it yourself as:
17
+ ```bash
18
+ $ gem install deferred_request
19
+ ```
20
+
21
+ ### Migrations
22
+ Copy the Deferred Request migrations to your app:
23
+
24
+ ```bash
25
+ bin/rails deferred_request:install:migrations
26
+ ```
27
+
28
+ Then, run the migrations:
29
+
30
+ ```bash
31
+ bin/rails db:migrate
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ### Controllers
37
+ In your controllers you can use the library like so. **Make sure you add a method with a `_deferred` suffix so that it can be processed later**
38
+
39
+ ```ruby
40
+ # app/controllers/twilio.rb
41
+
42
+ # ... (snipped for brevity)
43
+ def status_callback
44
+ # We can go ahead and give a :ok response (fast and snappy)
45
+ head :ok
46
+
47
+ # Then queue the request to run later
48
+ deferred_request = DeferredRequest::DeferredRequest.from_request(request, params)
49
+ deferred_request.save!
50
+
51
+ deferred_request.peform_later
52
+ end
53
+
54
+ # Your deferred request method will be called later (via a job)
55
+ # deferred_request will be of type DeferredRequest::DeferredRequest
56
+ def status_callback_deferred(deferred_request)
57
+ # do some actual processing
58
+ if deferred_request.params["SmsStatus"] == "delivered"
59
+ # mark message as delivered
60
+ end
61
+
62
+ # return a status and it will be saved to the database
63
+ true
64
+ end
65
+ # ...
66
+ ```
67
+
68
+ ## 🙏 Contributing
69
+
70
+ If you have an issue you'd like to submit, please do so using the issue tracker in GitHub. In order for us to help you in the best way possible, please be as detailed as you can.
71
+
72
+ If you'd like to open a PR please make sure the following things pass:
73
+
74
+ ```ruby
75
+ bin/rails db:test:prepare
76
+ bin/rails test
77
+ bundle exec standardrb
78
+ ```
79
+
80
+ ## 📝 License
81
+
82
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/deferred_request .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ module DeferredRequest
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -0,0 +1,26 @@
1
+ module DeferredRequest
2
+ class TestController < ApplicationController
3
+ skip_before_action :verify_authenticity_token
4
+
5
+ def status_callback
6
+ # We can go ahead and give a :ok response (fast and snappy)
7
+ head :ok
8
+
9
+ # Then queue the request to run later
10
+ deferred_request = DeferredRequest::DeferredRequest.from_request(request, params)
11
+ deferred_request.save!
12
+
13
+ deferred_request.peform_later
14
+ end
15
+
16
+ def status_callback_deferred(deferred_request)
17
+ # do some actual processing
18
+ if deferred_request.params["SmsStatus"] == "delivered"
19
+ # mark message as delivered
20
+ end
21
+
22
+ # return a status and it will be saved to the database
23
+ true
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,4 @@
1
+ module DeferredRequest
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DeferredRequest
2
+ module TestHelper
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module DeferredRequest
2
+ class ApplicationJob < ActiveJob::Base
3
+ end
4
+ end
@@ -0,0 +1,13 @@
1
+ module DeferredRequest
2
+ class DeferredRequestJob < ApplicationJob
3
+ queue_as :default
4
+
5
+ def perform(*args)
6
+ id = args[0]
7
+ request = DeferredRequest.find(id)
8
+ request.perform!
9
+ rescue ActiveRecord::RecordNotFound
10
+ Rails.logger.error("DeferredRequest::DeferredRequestJob: Could not find DeferredRequest with id: #{id}")
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,6 @@
1
+ module DeferredRequest
2
+ class ApplicationMailer < ActionMailer::Base
3
+ default from: "from@example.com"
4
+ layout "mailer"
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module DeferredRequest
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -0,0 +1,62 @@
1
+ module DeferredRequest
2
+ class DeferredRequest < ApplicationRecord
3
+ serialize :routing, JSON, default: {}
4
+ serialize :request, JSON, default: {}
5
+
6
+ store_accessor :routing, "controller", "action"
7
+ store_accessor :request, "url", "method", "headers", "params", "remote_ip"
8
+
9
+ enum status: {queued: 0, processing: 1, complete: 2, error: 99}
10
+
11
+ # request: ActionDispatch::Request
12
+ # create a deferred request from a ActionDispatch::Request
13
+ def self.from_request(request)
14
+ deferred_request = DeferredRequest.new
15
+
16
+ debugger
17
+ deferred_request.controller = request.controller_class
18
+ deferred_request.action = request.params["action"]
19
+
20
+ deferred_request.url = request.url
21
+ deferred_request.method = request.method
22
+ deferred_request.headers = get_headers(request)
23
+ deferred_request.params = request.params.except(:controller, :action)
24
+ deferred_request.remote_ip = request.remote_ip
25
+
26
+ deferred_request
27
+ end
28
+
29
+ def perform_later
30
+ DeferredRequestJob.perform_later(self.id)
31
+ end
32
+
33
+ def perform!
34
+ begin
35
+ self.status = :processing
36
+ self.save!
37
+
38
+ klass = self.controller.constantize.new
39
+
40
+ self.result = klass.try("#{self.action}_deferred".to_sym, self)
41
+ self.status = :complete
42
+ rescue => e
43
+ Rails.logger.error("DeferredRequest::DeferredRequestJob: #{e.message}")
44
+ self.result = e.message
45
+ self.status = :error
46
+ end
47
+
48
+ self.save!
49
+ end
50
+
51
+ private
52
+
53
+ def self.get_headers(request)
54
+ # Get the request headers from the request
55
+ {}.tap do |t|
56
+ request.headers.each do |key, value|
57
+ t[key] = value if key.downcase.starts_with?("http")
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Deferred request</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "deferred_request/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,3 @@
1
+ DeferredRequest::Engine.routes.draw do
2
+ post 'status_callback' => 'deferred_request/test#status_callback'
3
+ end
@@ -0,0 +1,12 @@
1
+ class CreateDeferredRequestDeferredRequests < ActiveRecord::Migration[7.0]
2
+ def change
3
+ create_table :deferred_request_deferred_requests do |t|
4
+ t.text :request
5
+ t.text :routing
6
+ t.text :result
7
+ t.integer :status, default: 0, null: false
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module DeferredRequest
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace DeferredRequest
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module DeferredRequest
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,6 @@
1
+ require "deferred_request/version"
2
+ require "deferred_request/engine"
3
+
4
+ module DeferredRequest
5
+ # Your code goes here...
6
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :deferred_request do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: deferred_request
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Austin Miller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-02-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '6.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '6.1'
27
+ description: A simple library to defer http requests until you can actually process
28
+ them. (Think webhooks. Stripe webhooks, Twilio status callbacks, ect.)
29
+ email:
30
+ - austinrmiller1991@gmail.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - MIT-LICENSE
36
+ - README.md
37
+ - Rakefile
38
+ - app/assets/config/deferred_request_manifest.js
39
+ - app/assets/stylesheets/deferred_request/application.css
40
+ - app/controllers/deferred_request/application_controller.rb
41
+ - app/controllers/deferred_request/test_controller.rb
42
+ - app/helpers/deferred_request/application_helper.rb
43
+ - app/helpers/deferred_request/test_helper.rb
44
+ - app/jobs/deferred_request/application_job.rb
45
+ - app/jobs/deferred_request/deferred_request_job.rb
46
+ - app/mailers/deferred_request/application_mailer.rb
47
+ - app/models/deferred_request/application_record.rb
48
+ - app/models/deferred_request/deferred_request.rb
49
+ - app/views/layouts/deferred_request/application.html.erb
50
+ - config/routes.rb
51
+ - db/migrate/20220204152629_create_deferred_request_deferred_requests.rb
52
+ - lib/deferred_request.rb
53
+ - lib/deferred_request/engine.rb
54
+ - lib/deferred_request/version.rb
55
+ - lib/tasks/deferred_request_tasks.rake
56
+ homepage: https://github.com/armiiller/deferred_request
57
+ licenses:
58
+ - MIT
59
+ metadata:
60
+ homepage_uri: https://github.com/armiiller/deferred_request
61
+ source_code_uri: https://github.com/armiiller/deferred_request
62
+ changelog_uri: https://github.com/armiiller/deferred_request/blob/master/CHANGELOG.md
63
+ post_install_message:
64
+ rdoc_options: []
65
+ require_paths:
66
+ - lib
67
+ required_ruby_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ required_rubygems_version: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ requirements: []
78
+ rubygems_version: 3.2.15
79
+ signing_key:
80
+ specification_version: 4
81
+ summary: Deferred Request
82
+ test_files: []