rails-cloud-tasks 0.0.1 → 0.0.2
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/.github/workflows/release.yml +58 -3
- data/README.md +44 -0
- data/Rakefile +4 -0
- data/lib/rails-cloud-tasks.rb +14 -0
- data/lib/rails_cloud_tasks/adapter.rb +1 -1
- data/lib/rails_cloud_tasks/configuration.rb +26 -10
- data/lib/rails_cloud_tasks/credentials.rb +38 -0
- data/lib/rails_cloud_tasks/rack/jobs.rb +1 -1
- data/lib/rails_cloud_tasks/rack/tasks.rb +1 -1
- data/lib/rails_cloud_tasks/scheduler.rb +62 -0
- data/lib/rails_cloud_tasks/version.rb +1 -1
- data/lib/railtie.rb +15 -0
- data/lib/tasks/scheduler.rake +6 -0
- data/rails-cloud-tasks.gemspec +3 -0
- metadata +49 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 924a936920255b90f05426a1a02d8fcb7c0b688f05ecf23f47d5574cfd830100
|
4
|
+
data.tar.gz: dac09c6a8c32a41ce9b8849b57892cac630f54b9592faf88400d248ac32d4661
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4bb22ec37af949357f944d2e5dc5f80c955fd65426aadc35f1ac4d7bc53cfdc8d5703813553f824e2024c137087a3d891f16d2a7859eb6a26fef771da7a894f
|
7
|
+
data.tar.gz: 4ca848172ca6473f08348f0b5ff6d9f9ddad8ff2a9b95ab9b2f8e77d933c5d6a1ebd4c29b1eac6afa43ecd3e665913fb9864d22bc8b451a1ee946b1279be6cb4
|
@@ -1,13 +1,55 @@
|
|
1
|
-
name: Release
|
1
|
+
name: Tag & Release Package
|
2
2
|
|
3
3
|
on:
|
4
4
|
push:
|
5
|
-
|
6
|
-
-
|
5
|
+
branches:
|
6
|
+
- main
|
7
7
|
|
8
8
|
jobs:
|
9
|
+
checks:
|
10
|
+
runs-on: ubuntu-latest
|
11
|
+
outputs:
|
12
|
+
pre_release: ${{ steps.versioning.outputs.pre_release }}
|
13
|
+
upgraded: ${{ steps.versioning.outputs.upgraded }}
|
14
|
+
package_version: ${{ steps.versioning.outputs.package_version }}
|
15
|
+
steps:
|
16
|
+
- uses: actions/checkout@v2
|
17
|
+
|
18
|
+
- name: Set up Ruby 2.7
|
19
|
+
uses: actions/setup-ruby@v1
|
20
|
+
with:
|
21
|
+
ruby-version: 2.7
|
22
|
+
|
23
|
+
- name: Install bundler
|
24
|
+
run: gem install bundler
|
25
|
+
|
26
|
+
- name: Cache dependencies
|
27
|
+
uses: actions/cache@v1
|
28
|
+
with:
|
29
|
+
path: vendor/bundle
|
30
|
+
key: ${{ runner.os }}-gem-${{ hashFiles('**/rails-cloud-tasks.gemspec') }}-2.7
|
31
|
+
|
32
|
+
- name: Install dependencies
|
33
|
+
run: bundle install
|
34
|
+
|
35
|
+
- name: Fetching Tags
|
36
|
+
run: git fetch -t
|
37
|
+
|
38
|
+
- name: Detect version upgrade
|
39
|
+
id: versioning
|
40
|
+
run: |
|
41
|
+
pkg='rails-cloud-tasks'
|
42
|
+
package_version=$(bundle info $pkg | grep -o "$pkg \(.*\)" | sed "s/$pkg (\(.*\))/\1/")
|
43
|
+
echo "::set-output name=package_version::"$package_version
|
44
|
+
upgraded=$(git tag --list | grep -q "${package_version}$" && echo "false" || echo "true")
|
45
|
+
echo "::set-output name=upgraded::"$upgraded
|
46
|
+
pre_release=$([[ $package_version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && echo "false" || echo "true")
|
47
|
+
echo "::set-output name=pre_release::"$pre_release
|
48
|
+
|
9
49
|
release:
|
10
50
|
runs-on: ubuntu-latest
|
51
|
+
needs: checks
|
52
|
+
if: needs.checks.outputs.upgraded == 'true'
|
11
53
|
steps:
|
12
54
|
- uses: actions/checkout@v2
|
13
55
|
|
@@ -28,6 +70,19 @@ jobs:
|
|
28
70
|
- name: Install dependencies
|
29
71
|
run: bundle install
|
30
72
|
|
73
|
+
- name: Create Release
|
74
|
+
uses: actions/create-release@v1
|
75
|
+
env:
|
76
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
77
|
+
with:
|
78
|
+
tag_name: ${{ needs.checks.outputs.package_version }}
|
79
|
+
release_name: Release ${{ needs.checks.outputs.package_version }}
|
80
|
+
body: |
|
81
|
+
Auto-released by bot.
|
82
|
+
See commit changes.
|
83
|
+
draft: false
|
84
|
+
prerelease: ${{ needs.checks.outputs.pre_release }}
|
85
|
+
|
31
86
|
- name: Build package
|
32
87
|
run: bundle exec gem build -o rails-cloud-tasks.gem
|
33
88
|
|
data/README.md
CHANGED
@@ -36,8 +36,11 @@ gem 'rails-cloud-tasks'
|
|
36
36
|
require 'rails-cloud-tasks'
|
37
37
|
|
38
38
|
RailsCloudTasks.configure do |config|
|
39
|
+
config.service_account_email = 'test-account@test-project.iam.gserviceaccount.com'
|
39
40
|
config.project_id = 'my-gcp-project' # This is not needed if running on GCE
|
40
41
|
config.location_id = 'us-central1'
|
42
|
+
config.scheduler_file_path = './custom_path/scheduler_jobs.yml'
|
43
|
+
config.scheduler_prefix_name = 'my-app-name'
|
41
44
|
|
42
45
|
# Base url used by Cloud Tasks to reach your application and run the tasks
|
43
46
|
config.host = 'https://myapplication.host.com'
|
@@ -48,6 +51,19 @@ RailsCloudTasks.configure do |config|
|
|
48
51
|
end
|
49
52
|
```
|
50
53
|
|
54
|
+
Check out the available configs and its usage description:
|
55
|
+
|
56
|
+
| attribute | description | env support | app engine fallback | default value |
|
57
|
+
|----------------------- |------------------------------------------------------------------------------------------------------------- |--------------------- |-------------------- |-------------------------- |
|
58
|
+
| service_account_email | The app service account email. It''s used to impersonate an user on schedule job | GCP_SERVICE_ACCOUNT | ✓ | |
|
59
|
+
| project_id | The Project ID | GCP_PROJECT | ✓ | |
|
60
|
+
| location_id | The region where you app is running (eg: us-central1, us-east1...) | GCP_LOCATION | ✓ | |
|
61
|
+
| host | The app endpoint which the app is running. *Do not use custom domain* Use the generated domain by Cloud Run | GCP_APP_ENDPOINT | | |
|
62
|
+
| scheduler_file_path | Path which the scheduler file is located | 𐄂 | | './config/scheduler.yml' |
|
63
|
+
| scheduler_prefix_name | The prefix to be set into scheduler job name | 𐄂 | | 'rails-cloud' |
|
64
|
+
| tasks_path | The path to run tasks | 𐄂 | | '/tasks' |
|
65
|
+
|
66
|
+
|
51
67
|
- Add a Job class:
|
52
68
|
```ruby
|
53
69
|
# ./app/jobs/application_job.rb
|
@@ -73,6 +89,34 @@ end
|
|
73
89
|
```ruby
|
74
90
|
MyJob.perform_later(attrs)
|
75
91
|
```
|
92
|
+
|
93
|
+
### Scheduled Jobs
|
94
|
+
|
95
|
+
We have support to Google Cloud Schedule. It's based on Cloud tasks, the jobs are scheduled with HTTP Target. We do not support Pub/Sub or App Engine HTTP for now.
|
96
|
+
|
97
|
+
Check out the follow sample of config file:
|
98
|
+
```yaml
|
99
|
+
# config/scheduler.yml
|
100
|
+
- name: Users::SyncJob
|
101
|
+
schedule: 0 8 * * *
|
102
|
+
description: Sync user data
|
103
|
+
time_zone: "America/Los_Angeles"
|
104
|
+
args:
|
105
|
+
arg1: 100
|
106
|
+
arg2: 200
|
107
|
+
```
|
108
|
+
|
109
|
+
| attribute | description | required |
|
110
|
+
|------------- |---------------------------------------------------------------- |---------- |
|
111
|
+
| name | The Job class namespace | ✓ |
|
112
|
+
| schedule | The frequency to run your job. It should be a unix-cron format | ✓ |
|
113
|
+
| description | What this job does | ✓ |
|
114
|
+
| time_zone | Choose which one timezone your job must run | ✓ |
|
115
|
+
| args | What are the job's arguments | ✓ |
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
|
76
120
|
## Tests
|
77
121
|
|
78
122
|
To run tests:
|
data/Rakefile
ADDED
data/lib/rails-cloud-tasks.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
require_relative './railtie'
|
2
|
+
|
1
3
|
require 'active_support'
|
2
4
|
require 'rails_cloud_tasks/rack/errors'
|
3
5
|
|
4
6
|
module RailsCloudTasks
|
5
7
|
extend ActiveSupport::Autoload
|
6
8
|
|
9
|
+
autoload :Scheduler
|
10
|
+
autoload :Credentials
|
7
11
|
autoload :Adapter
|
8
12
|
autoload :AppEngine
|
9
13
|
autoload :Configuration
|
@@ -25,4 +29,14 @@ module RailsCloudTasks
|
|
25
29
|
def self.config
|
26
30
|
@config ||= Configuration.new
|
27
31
|
end
|
32
|
+
|
33
|
+
def self.logger
|
34
|
+
return @logger if @logger
|
35
|
+
|
36
|
+
@logger ||= (Rails.logger || Logger.new($stdout)).tap do |logger|
|
37
|
+
logger.formatter = proc do |severity, datetime, _progname, msg|
|
38
|
+
"[#{datetime}] #{severity} [rails-cloud-tasks]: #{msg}\n"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
28
42
|
end
|
@@ -39,7 +39,7 @@ module RailsCloudTasks
|
|
39
39
|
http_request: {
|
40
40
|
http_method: :POST,
|
41
41
|
url: url,
|
42
|
-
body: { job: job.serialize }.to_json
|
42
|
+
body: { job: job.serialize }.to_json.force_encoding('ASCII-8BIT')
|
43
43
|
}.merge(auth),
|
44
44
|
schedule_time: timestamp && Google::Protobuf::Timestamp.new.tap do |ts|
|
45
45
|
ts.seconds = timestamp
|
@@ -1,12 +1,22 @@
|
|
1
1
|
module RailsCloudTasks
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :location_id, :host, :tasks_path, :service_account_email, :scheduler_file_path,
|
4
|
+
:scheduler_prefix_name
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
attr_writer :project_id
|
7
|
+
attr_reader :app_engine, :google_auth
|
8
|
+
|
9
|
+
def initialize(app_engine = AppEngine, google_auth = Google::Auth)
|
10
|
+
@service_account_email = ENV['GCP_SERVICE_ACCOUNT']
|
11
|
+
@location_id = ENV['GCP_LOCATION']
|
12
|
+
@project_id = ENV['GCP_PROJECT']
|
13
|
+
@host = ENV['GCP_APP_ENDPOINT']
|
8
14
|
@tasks_path = '/tasks'
|
9
|
-
@
|
15
|
+
@scheduler_file_path = './config/scheduler.yml'
|
16
|
+
@scheduler_prefix_name = 'rails-cloud'
|
17
|
+
|
18
|
+
@app_engine = app_engine
|
19
|
+
@google_auth = google_auth
|
10
20
|
end
|
11
21
|
|
12
22
|
def inject_routes
|
@@ -18,20 +28,26 @@ module RailsCloudTasks
|
|
18
28
|
end
|
19
29
|
end
|
20
30
|
|
31
|
+
def project_id
|
32
|
+
@project_id ||= app_engine.project_id
|
33
|
+
end
|
34
|
+
|
35
|
+
def auth
|
36
|
+
@auth ||= authenticate
|
37
|
+
end
|
38
|
+
|
21
39
|
private
|
22
40
|
|
23
41
|
def authenticate
|
24
|
-
email =
|
42
|
+
email = service_account_email ||
|
43
|
+
app_engine.service_account_email ||
|
44
|
+
google_auth.get_application_default.issuer
|
25
45
|
|
26
46
|
{
|
27
47
|
oidc_token: {
|
28
48
|
service_account_email: email
|
29
49
|
}
|
30
50
|
}
|
31
|
-
rescue RuntimeError, Errno::EHOSTDOWN
|
32
|
-
# EHOSTDOWN occurs sporadically when trying to resolve the metadata endpoint
|
33
|
-
# locally. It is unlikely to occur when running on GCE.
|
34
|
-
{}
|
35
51
|
end
|
36
52
|
end
|
37
53
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RailsCloudTasks
|
2
|
+
class Credentials
|
3
|
+
require 'googleauth'
|
4
|
+
require 'google/apis/cloudscheduler_v1'
|
5
|
+
require 'google/apis/iamcredentials_v1'
|
6
|
+
|
7
|
+
DEFAULT_SCOPES = ['https://www.googleapis.com/auth/cloud-platform'].freeze
|
8
|
+
attr_reader :request_options, :iam_credential, :token_request, :auth
|
9
|
+
|
10
|
+
def initialize(
|
11
|
+
request_options: Google::Apis::RequestOptions.new,
|
12
|
+
iam_credential: Google::Apis::IamcredentialsV1::IAMCredentialsService.new,
|
13
|
+
token_request: Google::Apis::IamcredentialsV1::GenerateAccessTokenRequest,
|
14
|
+
auth: Google::Auth
|
15
|
+
)
|
16
|
+
@auth = auth
|
17
|
+
@request_options = request_options
|
18
|
+
@iam_credential = iam_credential
|
19
|
+
@token_request = token_request
|
20
|
+
end
|
21
|
+
|
22
|
+
def generate(impersonate_account = nil, scopes = [])
|
23
|
+
current_scopes = DEFAULT_SCOPES + scopes
|
24
|
+
authorization = auth.get_application_default(current_scopes).dup
|
25
|
+
request_options.authorization = authorization
|
26
|
+
|
27
|
+
if impersonate_account
|
28
|
+
iam_credential.generate_service_account_access_token(
|
29
|
+
"projects/-/serviceAccounts/#{impersonate_account}",
|
30
|
+
token_request.new(scope: current_scopes, lifetime: '3600s'),
|
31
|
+
options: request_options
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
request_options.authorization
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module RailsCloudTasks
|
2
|
+
class Scheduler
|
3
|
+
delegate :project_id, :location_id, :host, :auth, :tasks_path,
|
4
|
+
:scheduler_file_path, :scheduler_prefix_name,
|
5
|
+
:service_account_email, to: 'RailsCloudTasks.config'
|
6
|
+
|
7
|
+
attr_reader :client, :credentials
|
8
|
+
|
9
|
+
def initialize(
|
10
|
+
client: Google::Cloud::Scheduler.cloud_scheduler,
|
11
|
+
credentials: RailsCloudTasks::Credentials.new
|
12
|
+
)
|
13
|
+
client.configure do |config|
|
14
|
+
config.credentials = credentials.generate(service_account_email)
|
15
|
+
end
|
16
|
+
@client = client
|
17
|
+
end
|
18
|
+
|
19
|
+
# Create & Update scheduler job on Google Cloud
|
20
|
+
# TODO: Support to delete scheduled jobs
|
21
|
+
def upsert
|
22
|
+
scheduler_jobs.each do |job|
|
23
|
+
begin
|
24
|
+
client.create_job parent: location_path, job: job
|
25
|
+
rescue Google::Cloud::AlreadyExistsError
|
26
|
+
client.update_job job: job
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def location_path
|
34
|
+
@location_path ||= client.location_path project: project_id, location: location_id
|
35
|
+
end
|
36
|
+
|
37
|
+
def scheduler_jobs
|
38
|
+
parse_jobs_from_file.map(&method(:build_job))
|
39
|
+
end
|
40
|
+
|
41
|
+
def build_job(job)
|
42
|
+
{
|
43
|
+
name: "#{location_path}/jobs/#{scheduler_prefix_name}--#{job[:name]}",
|
44
|
+
schedule: job[:schedule],
|
45
|
+
description: job[:description],
|
46
|
+
time_zone: job[:time_zone],
|
47
|
+
http_target: {
|
48
|
+
uri: "#{host}#{tasks_path}/#{job[:name]}",
|
49
|
+
http_method: 'POST',
|
50
|
+
body: job[:args].to_json
|
51
|
+
}.merge(auth)
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_jobs_from_file
|
56
|
+
settings = File.read(File.expand_path(scheduler_file_path))
|
57
|
+
YAML.safe_load(ERB.new(settings).result).map(&:deep_symbolize_keys)
|
58
|
+
rescue Errno::ENOENT
|
59
|
+
[]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/lib/railtie.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails-cloud-tasks'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module RailsCloudTasks
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
railtie_name :rails_cloud_tasks
|
7
|
+
|
8
|
+
rake_tasks do
|
9
|
+
namespace :rails_cloud_tasks do
|
10
|
+
path = File.expand_path(__dir__)
|
11
|
+
Dir.glob("#{path}/tasks/**/*.rake").each { |f| load f }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/rails-cloud-tasks.gemspec
CHANGED
@@ -23,6 +23,9 @@ Gem::Specification.new do |spec|
|
|
23
23
|
end
|
24
24
|
|
25
25
|
spec.add_dependency 'activesupport', '>= 4'
|
26
|
+
spec.add_dependency 'google-apis-cloudscheduler_v1'
|
27
|
+
spec.add_dependency 'google-apis-iamcredentials_v1'
|
28
|
+
spec.add_dependency 'google-cloud-scheduler', '>= 2'
|
26
29
|
spec.add_dependency 'google-cloud-tasks', '>= 2'
|
27
30
|
spec.add_development_dependency 'rails', '>= 4'
|
28
31
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-cloud-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Guilherme Araújo
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -24,6 +24,48 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '4'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: google-apis-cloudscheduler_v1
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: google-apis-iamcredentials_v1
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: google-cloud-scheduler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2'
|
27
69
|
- !ruby/object:Gem::Dependency
|
28
70
|
name: google-cloud-tasks
|
29
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -236,14 +278,19 @@ files:
|
|
236
278
|
- Gemfile
|
237
279
|
- LICENSE
|
238
280
|
- README.md
|
281
|
+
- Rakefile
|
239
282
|
- lib/rails-cloud-tasks.rb
|
240
283
|
- lib/rails_cloud_tasks/adapter.rb
|
241
284
|
- lib/rails_cloud_tasks/app_engine.rb
|
242
285
|
- lib/rails_cloud_tasks/configuration.rb
|
286
|
+
- lib/rails_cloud_tasks/credentials.rb
|
243
287
|
- lib/rails_cloud_tasks/rack/errors.rb
|
244
288
|
- lib/rails_cloud_tasks/rack/jobs.rb
|
245
289
|
- lib/rails_cloud_tasks/rack/tasks.rb
|
290
|
+
- lib/rails_cloud_tasks/scheduler.rb
|
246
291
|
- lib/rails_cloud_tasks/version.rb
|
292
|
+
- lib/railtie.rb
|
293
|
+
- lib/tasks/scheduler.rake
|
247
294
|
- rails-cloud-tasks.gemspec
|
248
295
|
homepage: http://github.com/flamingo-run/rails-cloud-tasks
|
249
296
|
licenses:
|