active_job_k8s 0.1.0 → 1.0.0.pre.beta.1

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
2
  SHA256:
3
- metadata.gz: 47a17202dbfd72dab2e898ae6097df0d9f9191de31d05119e6ff4190f4038ea9
4
- data.tar.gz: 961f6548436a79621c58b8da0a5d078e14a0db4a2517ec701a43bbed3ea5da87
3
+ metadata.gz: d5b40e92ba26450d0cb797737e03552b8f89fea8dc1f4ae9da53d924b34e23ad
4
+ data.tar.gz: 6d30c4b30a4a1bf180e5617c8ce4582f27862d80a2ed2b1959dc1c57f782d123
5
5
  SHA512:
6
- metadata.gz: aaad5ff2c9f345e177a7b0017d91fe68e6b064392ecdf7d4c174714256d0ba2cacfeae271102845265ecb9979aafb6495859d6831694d4de5f683ead8134dbc9
7
- data.tar.gz: 2e979a40fde5148b72fa00ebe1ab442b570b3ca9ff843a8b77f2f720ef1108423382f72a3c138caf30705f5ae58e149ca9d8543d48a65c4bfb133bdc1cbdc95c
6
+ metadata.gz: a1f159b9d818fc7f1e94f19cd69ffa6288a19e453c444a1fc6ff5470613f46366b0a3a4cef266c488ae7062f0a93ff8872cced39182e0b0feda9f57c3de90318
7
+ data.tar.gz: 3042cee4f989340e528d5f2d153fc954489e43edd0c152fc32255ff717bdeeceb254db5db45c48740df401c0dda1eb5e58a3910ca44f507251bd1bfa3c7e9c51
@@ -21,11 +21,14 @@ jobs:
21
21
 
22
22
  runs-on: ubuntu-latest
23
23
  strategy:
24
+ fail-fast: false
24
25
  matrix:
25
- ruby-version: ['2.6', '2.7']
26
+ ruby-version: [ '2.7','3.0','3.1']
26
27
 
27
28
  steps:
28
29
  - uses: actions/checkout@v3
30
+ - name: Remove Gemfile.lock
31
+ run: rm -fr Gemfile.lock
29
32
  - name: Set up Ruby
30
33
  uses: ruby/setup-ruby@v1
31
34
  with:
data/.gitignore CHANGED
@@ -9,4 +9,5 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
- spec/dummy
12
+ spec/dummy
13
+ *.gem
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # V 0.2.0
2
+ - change position of default manifest
3
+ - implementation of delayed job to be scheduled in a specific moment
4
+
1
5
  # V 0.1.0
2
6
  - first release as POC
3
7
  - base tests
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  gem "rails","~> 6.1"
7
- gem "rake", "~> 12.0"
7
+ gem "rake", "~> 13.0"
8
8
  gem "rspec", "~> 3.0"
9
9
 
10
10
  gem 'simplecov', require: false
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- active_job_k8s (0.1.0)
4
+ active_job_k8s (0.2.0)
5
+ http (>= 5.0)
5
6
  kubeclient (~> 4.0)
6
7
  rails (>= 6.0, < 8)
7
8
 
@@ -72,57 +73,71 @@ GEM
72
73
  builder (3.2.4)
73
74
  concurrent-ruby (1.1.10)
74
75
  crass (1.0.6)
76
+ date (3.3.3)
75
77
  diff-lcs (1.5.0)
76
78
  docile (1.4.0)
77
79
  domain_name (0.5.20190701)
78
80
  unf (>= 0.0.5, < 1.0.0)
79
- erubi (1.11.0)
81
+ erubi (1.12.0)
80
82
  ffi (1.15.5)
81
83
  ffi-compiler (1.0.1)
82
84
  ffi (>= 1.0.0)
83
85
  rake
84
86
  globalid (1.0.0)
85
87
  activesupport (>= 5.0)
86
- http (4.4.1)
87
- addressable (~> 2.3)
88
+ http (5.1.1)
89
+ addressable (~> 2.8)
88
90
  http-cookie (~> 1.0)
89
91
  http-form_data (~> 2.2)
90
- http-parser (~> 1.2.0)
92
+ llhttp-ffi (~> 0.4.0)
91
93
  http-accept (1.7.0)
92
94
  http-cookie (1.0.5)
93
95
  domain_name (~> 0.5)
94
96
  http-form_data (2.3.0)
95
- http-parser (1.2.3)
96
- ffi-compiler (>= 1.0, < 2.0)
97
97
  i18n (1.12.0)
98
98
  concurrent-ruby (~> 1.0)
99
99
  jsonpath (1.1.2)
100
100
  multi_json
101
- kubeclient (4.10.1)
102
- http (>= 3.0, < 5.0)
101
+ kubeclient (4.11.0)
102
+ http (>= 3.0, < 6.0)
103
103
  jsonpath (~> 1.0)
104
104
  recursive-open-struct (~> 1.1, >= 1.1.1)
105
105
  rest-client (~> 2.0)
106
- loofah (2.19.0)
106
+ llhttp-ffi (0.4.0)
107
+ ffi-compiler (~> 1.0)
108
+ rake (~> 13.0)
109
+ loofah (2.19.1)
107
110
  crass (~> 1.0.2)
108
111
  nokogiri (>= 1.5.9)
109
- mail (2.7.1)
112
+ mail (2.8.0)
110
113
  mini_mime (>= 0.1.1)
114
+ net-imap
115
+ net-pop
116
+ net-smtp
111
117
  marcel (1.0.2)
112
118
  method_source (1.0.0)
113
119
  mime-types (3.4.1)
114
120
  mime-types-data (~> 3.2015)
115
121
  mime-types-data (3.2022.0105)
116
122
  mini_mime (1.1.2)
117
- minitest (5.16.3)
123
+ minitest (5.17.0)
118
124
  multi_json (1.15.0)
125
+ net-imap (0.3.4)
126
+ date
127
+ net-protocol
128
+ net-pop (0.1.2)
129
+ net-protocol
130
+ net-protocol (0.2.1)
131
+ timeout
132
+ net-smtp (0.3.3)
133
+ net-protocol
119
134
  netrc (0.11.0)
120
135
  nio4r (2.5.8)
121
- nokogiri (1.13.9-x86_64-linux)
136
+ nokogiri (1.13.10-x86_64-linux)
122
137
  racc (~> 1.4)
123
- public_suffix (5.0.0)
124
- racc (1.6.0)
125
- rack (2.2.4)
138
+ public_suffix (5.0.1)
139
+ racc (1.6.2)
140
+ rack (2.2.5)
126
141
  rack-test (2.0.2)
127
142
  rack (>= 1.3)
128
143
  rails (6.1.7)
@@ -143,15 +158,15 @@ GEM
143
158
  rails-dom-testing (2.0.3)
144
159
  activesupport (>= 4.2.0)
145
160
  nokogiri (>= 1.6)
146
- rails-html-sanitizer (1.4.3)
147
- loofah (~> 2.3)
161
+ rails-html-sanitizer (1.4.4)
162
+ loofah (~> 2.19, >= 2.19.1)
148
163
  railties (6.1.7)
149
164
  actionpack (= 6.1.7)
150
165
  activesupport (= 6.1.7)
151
166
  method_source
152
167
  rake (>= 12.2)
153
168
  thor (~> 1.0)
154
- rake (12.3.3)
169
+ rake (13.0.6)
155
170
  recursive-open-struct (1.1.3)
156
171
  rest-client (2.1.0)
157
172
  http-accept (>= 1.7.0, < 2.0)
@@ -159,20 +174,20 @@ GEM
159
174
  mime-types (>= 1.16, < 4.0)
160
175
  netrc (~> 0.8)
161
176
  rexml (3.2.5)
162
- rspec (3.11.0)
163
- rspec-core (~> 3.11.0)
164
- rspec-expectations (~> 3.11.0)
165
- rspec-mocks (~> 3.11.0)
166
- rspec-core (3.11.0)
167
- rspec-support (~> 3.11.0)
168
- rspec-expectations (3.11.1)
177
+ rspec (3.12.0)
178
+ rspec-core (~> 3.12.0)
179
+ rspec-expectations (~> 3.12.0)
180
+ rspec-mocks (~> 3.12.0)
181
+ rspec-core (3.12.0)
182
+ rspec-support (~> 3.12.0)
183
+ rspec-expectations (3.12.1)
169
184
  diff-lcs (>= 1.2.0, < 2.0)
170
- rspec-support (~> 3.11.0)
171
- rspec-mocks (3.11.1)
185
+ rspec-support (~> 3.12.0)
186
+ rspec-mocks (3.12.1)
172
187
  diff-lcs (>= 1.2.0, < 2.0)
173
- rspec-support (~> 3.11.0)
174
- rspec-support (3.11.1)
175
- simplecov (0.21.2)
188
+ rspec-support (~> 3.12.0)
189
+ rspec-support (3.12.0)
190
+ simplecov (0.22.0)
176
191
  docile (~> 1.1)
177
192
  simplecov-html (~> 0.11)
178
193
  simplecov_json_formatter (~> 0.1)
@@ -181,14 +196,15 @@ GEM
181
196
  simplecov (~> 0.19)
182
197
  simplecov-html (0.12.3)
183
198
  simplecov_json_formatter (0.1.4)
184
- sprockets (4.1.1)
199
+ sprockets (4.2.0)
185
200
  concurrent-ruby (~> 1.0)
186
- rack (> 1, < 3)
201
+ rack (>= 2.2.4, < 4)
187
202
  sprockets-rails (3.4.2)
188
203
  actionpack (>= 5.2)
189
204
  activesupport (>= 5.2)
190
205
  sprockets (>= 3.0.0)
191
206
  thor (1.2.1)
207
+ timeout (0.3.1)
192
208
  tzinfo (2.0.5)
193
209
  concurrent-ruby (~> 1.0)
194
210
  unf (0.1.4)
@@ -197,7 +213,7 @@ GEM
197
213
  websocket-driver (0.7.5)
198
214
  websocket-extensions (>= 0.1.0)
199
215
  websocket-extensions (0.1.5)
200
- zeitwerk (2.6.1)
216
+ zeitwerk (2.6.6)
201
217
 
202
218
  PLATFORMS
203
219
  x86_64-linux
@@ -205,7 +221,7 @@ PLATFORMS
205
221
  DEPENDENCIES
206
222
  active_job_k8s!
207
223
  rails (~> 6.1)
208
- rake (~> 12.0)
224
+ rake (~> 13.0)
209
225
  rspec (~> 3.0)
210
226
  simplecov
211
227
  simplecov-cobertura (~> 2.1.0)
data/README.md CHANGED
@@ -1,12 +1,12 @@
1
- # ActiveJobK8s
1
+ # ActiveJobK8s [![Gem Version](https://badge.fury.io/rb/active_job_k8s.svg)](https://badge.fury.io/rb/active_job_k8s)
2
2
 
3
3
  WIP gem to make active job work with kubernetes jobs.
4
4
 
5
5
  Roadmap for V1.0:
6
6
  - [x] ActiveJob.perform_later create a Job in k8s that will execute the job
7
- - [ ] ActiveJob.perform_later with delay create a Job in k8s in suspended mode,
7
+ - [x] ActiveJob.perform_later with delay create a Job in k8s in suspended mode,
8
8
  a task will enable it as soon as the time is reached
9
- - [ ] Limiting the number of concurrent jobs (if there are more jobs they will be created in suspended mode)
9
+ - [x] Limiting the number of concurrent jobs (if there are more jobs they will be created in suspended mode)
10
10
 
11
11
  Future:
12
12
  - [ ] Metrics (because everyone like metrics)
@@ -66,8 +66,33 @@ Rails.application.configure do
66
66
  namespace
67
67
  )
68
68
 
69
+ default_manifest = YAML.safe_load(
70
+ <<~MANIFEST
71
+ apiVersion: batch/v1
72
+ kind: Job
73
+ metadata:
74
+ name: scheduled-job-name
75
+ namespace: default
76
+ spec:
77
+ template:
78
+ spec:
79
+ restartPolicy: Never
80
+ containers:
81
+ - name: app-job
82
+ image: image_of_the_rails_application
83
+ imagePullPolicy: IfNotPresent
84
+ command:
85
+ - /bin/bash
86
+ args:
87
+ - '-c'
88
+ - bundle exec rails active_job_k8s:run_job
89
+
90
+ MANIFEST
91
+ )
92
+
69
93
  config.active_job.queue_adapter = ActiveJob::QueueAdapters::K8sAdapter.new(
70
- kubeclient_context: context
94
+ kubeclient_context: context,
95
+ default_manifest: default_manifest
71
96
  )
72
97
 
73
98
  end
@@ -92,9 +117,8 @@ rules:
92
117
  verbs:
93
118
  - get
94
119
  - list
95
- - watch
96
120
  - create
97
- - delete
121
+ - patch
98
122
  ---
99
123
  kind: RoleBinding
100
124
  apiVersion: rbac.authorization.k8s.io/v1
@@ -123,27 +147,12 @@ class HelloWorldJob < ApplicationJob
123
147
  def perform(*args)
124
148
  Rails.logger.debug "Hello World"
125
149
  end
126
-
127
- def manifest
128
- YAML.safe_load(
129
- <<~MANIFEST
130
- apiVersion: batch/v1
131
- kind: Job
132
- metadata:
133
- name: scheduled-job-name
134
- namespace: default
135
- spec:
136
- template:
137
- spec:
138
- restartPolicy: Never
139
- containers:
140
- - name: app-job
141
- image: image_of_the_rails_application
142
- imagePullPolicy: IfNotPresent
143
-
144
- MANIFEST
145
- )
146
- end
150
+
151
+ #[Optional] if not present it will be taken from scheduler configuration
152
+ # def manifest
153
+ # .....
154
+ # end
155
+
147
156
  end
148
157
  ```
149
158
 
@@ -9,13 +9,13 @@ Gem::Specification.new do |spec|
9
9
  spec.summary = "ActiveJob adapter for kubernetes job"
10
10
  spec.homepage = "https://github.com/oniram88/active_job_k8s"
11
11
  spec.license = "MIT"
12
- spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
12
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
13
13
 
14
14
  spec.metadata["allowed_push_host"] = "https://rubygems.org"
15
15
 
16
16
  spec.metadata["homepage_uri"] = spec.homepage
17
17
  spec.metadata["source_code_uri"] = spec.homepage
18
- spec.metadata["changelog_uri"] = "#{spec.homepage}/CHANGELOG.md"
18
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/master/CHANGELOG.md"
19
19
 
20
20
  # Specify which files should be added to the gem when it is released.
21
21
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
27
27
  spec.require_paths = ["lib"]
28
28
 
29
29
  spec.add_dependency 'kubeclient', '~> 4.0' #https://github.com/ManageIQ/kubeclient
30
+ spec.add_dependency 'http', '>= 5.0' # dipendenza di kubeclient, ma non si compila correttamente con versione di ruby > di 2.7
30
31
  spec.add_dependency 'rails', '>= 6.0', '<8'
31
32
 
32
33
  end
data/bin/setup CHANGED
@@ -5,27 +5,46 @@ set -vx
5
5
 
6
6
  bundle install
7
7
 
8
- # Prepariamo l'applicazione esempio
8
+ # Create dummy application
9
9
  rm -fr spec/dummy
10
10
  bundle exec rails new spec/dummy --skip-git --skip-javascript --skip-hotwire --skip-jbuilder --skip-test --skip-bootsnap --force
11
11
 
12
12
  echo "Changes to application"
13
13
 
14
- sed -i 's/"2.7.4"/">= 2.7.4"/' spec/dummy/Gemfile
14
+ sed -i 's/2.7.4/>= 2.7.4/' spec/dummy/Gemfile
15
15
  sed -i '/end/i root "main#index"' spec/dummy/config/routes.rb
16
16
  sed -i '/root "main#index"/i get "create_job", to: "main#create_job", as: "create_job"' spec/dummy/config/routes.rb
17
+ sed -i '/root "main#index"/i get "send_email", to: "main#send_email", as: "send_email"' spec/dummy/config/routes.rb
18
+ sed -i '/root "main#index"/i get "health", to: "main#health"' spec/dummy/config/routes.rb
17
19
 
18
20
  echo '
19
21
  class MainController < ApplicationController
20
22
  include ActionView::Helpers::UrlHelper
21
- def index
22
- render inline: "#{link_to HelloWorldJob.name,create_job_path}"
23
- end
24
23
 
25
- def create_job
26
- HelloWorldJob.perform_later
27
- redirect_to root_path
28
- end
24
+ def index
25
+ render inline: "#{link_to HelloWorldJob.name, create_job_path}<br>
26
+ #{link_to HelloWorldJob.name, create_job_path(wait: 1)}<br>
27
+ #{link_to SubscriptionMailer, send_email_path}"
28
+ end
29
+
30
+ def create_job
31
+ j = HelloWorldJob
32
+ if params[:wait]
33
+ j = j.set(wait: params[:wait].to_i.minutes)
34
+ end
35
+ j.perform_later
36
+
37
+ redirect_to root_path
38
+ end
39
+
40
+ def health
41
+ head :ok
42
+ end
43
+
44
+ def send_email
45
+ SubscriptionMailer.notify.deliver_later
46
+ redirect_to root_path
47
+ end
29
48
 
30
49
  end
31
50
  ' > spec/dummy/app/controllers/main_controller.rb
@@ -52,8 +71,46 @@ Rails.application.configure do
52
71
  namespace
53
72
  )
54
73
 
74
+ default_manifest = YAML.safe_load(
75
+ <<~MANIFEST
76
+ apiVersion: batch/v1
77
+ kind: Job
78
+ metadata:
79
+ name: scheduled-job-name
80
+ namespace: default
81
+ spec:
82
+ template:
83
+ spec:
84
+ restartPolicy: Never
85
+ containers:
86
+ - name: app-job
87
+ image: activejobk8s:0.1.0
88
+ imagePullPolicy: IfNotPresent
89
+ env:
90
+ - name: RAILS_SERVE_STATIC_FILES
91
+ value: "1"
92
+ - name: RAILS_LOG_TO_STDOUT
93
+ value: "1"
94
+ - name: RAILS_ENV
95
+ value: "development"
96
+ command: ["/bin/sh"]
97
+ args:
98
+ - "-ec"
99
+ - "bundle install && bundle exec rails active_job_k8s:run_job"
100
+ volumeMounts:
101
+ - mountPath: /usr/src/app
102
+ name: application-volume
103
+ volumes:
104
+ - name: application-volume
105
+ hostPath:
106
+ # directory location on host
107
+ path: /application
108
+ MANIFEST
109
+ )
110
+
55
111
  config.active_job.queue_adapter = ActiveJob::QueueAdapters::K8sAdapter.new(
56
- kubeclient_context: context
112
+ kubeclient_context: context,
113
+ default_manifest: default_manifest
57
114
  )
58
115
 
59
116
  end
@@ -65,50 +122,19 @@ class HelloWorldJob < ApplicationJob
65
122
 
66
123
  def perform(*args)
67
124
  Rails.logger.debug "Hello World"
125
+ sleep (SecureRandom.random_number * 50).to_i # simulate operations
68
126
  FileUtils.touch(Rails.root.join("tmp","#{SecureRandom.hex}.test"))
69
127
  end
128
+ end
129
+ ' > spec/dummy/app/jobs/hello_world_job.rb
70
130
 
71
- def manifest
72
- YAML.safe_load(
73
- <<~MANIFEST
74
- apiVersion: batch/v1
75
- kind: Job
76
- metadata:
77
- name: scheduled-job-name
78
- namespace: default
79
- spec:
80
- template:
81
- spec:
82
- restartPolicy: Never
83
- containers:
84
- - name: app-job
85
- image: activejobk8s:0.1.0
86
- imagePullPolicy: IfNotPresent
87
- env:
88
- - name: RAILS_SERVE_STATIC_FILES
89
- value: "1"
90
- - name: RAILS_LOG_TO_STDOUT
91
- value: "1"
92
- - name: RAILS_ENV
93
- value: "development"
94
- command: ["/bin/sh"]
95
- args:
96
- - "-ec"
97
- - "bundle install && bundle exec rails active_job_k8s:run_job"
98
- volumeMounts:
99
- - mountPath: /usr/src/app
100
- name: application-volume
101
- volumes:
102
- - name: application-volume
103
- hostPath:
104
- # directory location on host
105
- path: /application
106
-
107
- MANIFEST
108
- )
131
+ echo '
132
+ class SubscriptionMailer < ApplicationMailer
133
+ def notify
134
+ mail(to: "test@domain.tld", subject: "test", body: "message")
109
135
  end
110
136
  end
111
- ' > spec/dummy/app/jobs/hello_world_job.rb
137
+ ' > spec/dummy/app/mailers/subscription_mailer.rb
112
138
 
113
139
  echo 'FROM ruby:3.0.4-alpine3.16
114
140
 
@@ -126,7 +152,7 @@ RUN bundle install
126
152
 
127
153
  COPY . .
128
154
 
129
- CMD ["/bin/sh", "-ec", "bundle install && bundle exec rails s -b 0.0.0.0 -p 3000"]' > spec/dummy/Dockerfile
155
+ CMD ["/bin/sh", "-ec", "rm -fr /usr/src/app/spec/dummy/tmp/pids/* && bundle install && bundle exec rails s -b 0.0.0.0 -p 3000"]' > spec/dummy/Dockerfile
130
156
 
131
157
  docker build -t activejobk8s:0.1.0 spec/dummy/.
132
158
 
@@ -171,6 +197,12 @@ spec:
171
197
  volumeMounts:
172
198
  - mountPath: /usr/src/app
173
199
  name: application-volume
200
+ livenessProbe:
201
+ httpGet:
202
+ path: /health
203
+ port: 3000
204
+ initialDelaySeconds: 120
205
+ periodSeconds: 3
174
206
  volumes:
175
207
  - name: application-volume
176
208
  hostPath:
@@ -190,9 +222,8 @@ rules:
190
222
  verbs:
191
223
  - get
192
224
  - list
193
- - watch
194
225
  - create
195
- - delete
226
+ - patch
196
227
  ---
197
228
  kind: RoleBinding
198
229
  apiVersion: rbac.authorization.k8s.io/v1
data/bin/teardown ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ rm -fr spec/dummy
7
+ kind delete cluster -n active-job-cluster
@@ -16,12 +16,10 @@ module ActiveJob
16
16
  scheduler.create_job(job)
17
17
  end
18
18
 
19
- def enqueue_at(*)
20
- # :nodoc:
21
- raise NotImplementedError, "It will be implemented in the future. Read the roadmap"
19
+ def enqueue_at(job,scheduled_at)
20
+ scheduler.create_job(job,scheduled_at:scheduled_at)
22
21
  end
23
22
 
24
-
25
23
  end
26
24
  end
27
25
  end
@@ -5,5 +5,17 @@ module ActiveJobK8s
5
5
  rake_tasks do
6
6
  require 'active_job_k8s/tasks'
7
7
  end
8
+
9
+ server do
10
+ puts "=> START ActiveJobK8s - ControlLoop sleep [5]"
11
+ Thread.new do
12
+ Rails.application.reloader.wrap do
13
+ loop do
14
+ Rails.application.config.active_job.queue_adapter.scheduler.un_suspend_jobs
15
+ sleep 5
16
+ end
17
+ end
18
+ end
19
+ end
8
20
  end
9
21
  end
@@ -5,26 +5,90 @@ require "json"
5
5
  module ActiveJobK8s
6
6
  class Scheduler
7
7
 
8
+ #@return [Kubeclient::Config::Context]
8
9
  attr_reader :kubeclient_context
9
10
 
10
- # @param [Hash{ kubeclient_context: [Kubeclient::Config::Context] }] opts
11
- def initialize(**opts)
12
- raise "No KubeClientContext given" if opts[:kubeclient_context].nil?
11
+ #@return [Hash]
12
+ attr_reader :default_manifest
13
+
14
+ # @param [Kubeclient::Config::Context] kubeclient_context
15
+ # @param [Hash] default_manifest
16
+ # @param [Integer] max_concurrent_jobs default 5
17
+ def initialize(kubeclient_context:, default_manifest: {}, max_concurrent_jobs: 5)
13
18
  # or to use a specific context, by name:
14
- @kubeclient_context = opts[:kubeclient_context]
19
+ @kubeclient_context = kubeclient_context
20
+ @default_manifest = default_manifest
21
+ @max_concurrent_jobs = max_concurrent_jobs
22
+ end
23
+
24
+ def create_job(job, scheduled_at: nil)
25
+
26
+ ##
27
+ # Make the job scheduled_at if there are not enought slot available
28
+ if scheduled_at.nil? and active_jobs.length>=@max_concurrent_jobs
29
+ scheduled_at = Time.now
30
+ end
31
+ _create_job(job, scheduled_at: scheduled_at)
32
+ end
33
+
34
+ def self.execute_job
35
+ ActiveJob::Base.execute(JSON.parse(ENV['SERIALIZED_JOB']))
36
+ end
37
+
38
+ ##
39
+ # Un-suspend jobs if the `scheduled at` is outdated, limited to max allowed concurrent
40
+ def un_suspend_jobs
41
+
42
+ to_activate_jobs = @max_concurrent_jobs - active_jobs.size
43
+ to_activate_jobs = 0 if to_activate_jobs < 0
44
+ # ::Rails.logger.debug { "Slot liberi: #{to_activate_jobs} - Job attivi: #{active_jobs.size} - Job in attesa: #{suspended_jobs.length}" }
45
+ suspended_jobs.select { |sj|
46
+ scheduled_at = Time.at(sj.metadata.annotations.scheduled_at.to_f)
47
+ Time.now > scheduled_at and sj.spec.suspend
48
+ }.take(to_activate_jobs).each do |sj|
49
+ client.patch_job(sj.metadata.name, { spec: { suspend: false } }, sj.metadata.namespace).inspect
50
+ end
51
+ end
52
+
53
+ protected
54
+
55
+ def client
56
+ @client ||= Kubeclient::Client.new(@kubeclient_context.api_endpoint + '/apis/batch',
57
+ @kubeclient_context.api_version || 'v1',
58
+ ssl_options: @kubeclient_context.ssl_options,
59
+ auth_options: @kubeclient_context.auth_options)
60
+ end
61
+
62
+ private
63
+
64
+ ##
65
+ # Internal list of all suspended jobs
66
+ def suspended_jobs
67
+ client.get_jobs(namespace: kubeclient_context.namespace,
68
+ label_selector: "activeJobK8s=scheduled",
69
+ field_selector: 'status.successful!=1')
70
+ end
15
71
 
72
+ # @return [Array<Kubeclient::Resource>]
73
+ def active_jobs
74
+ client.get_jobs(namespace: kubeclient_context.namespace,
75
+ label_selector: "activeJobK8s",
76
+ field_selector: 'status.successful!=1').select do |j|
77
+ j.status.active.to_i == 1 and j.spec.suspend != "true"
78
+ end
16
79
  end
17
80
 
18
- def create_job(job)
81
+ def _create_job(job, scheduled_at: nil)
19
82
 
20
83
  serialized_job = JSON.dump(job.serialize)
21
84
 
22
- kube_job = Kubeclient::Resource.new(job.manifest)
85
+ manifest = (job.respond_to?(:manifest) and job.manifest.is_a?(Hash) and !job.manifest.empty?) ? job.manifest : default_manifest
86
+ kube_job = Kubeclient::Resource.new(manifest)
23
87
 
24
- # kube_job.spec.suspend = false FIXME complete for delayed jobs
25
88
  kube_job.metadata.name = "#{kube_job.metadata.name}-#{job.job_id}"
26
- kube_job.metadata.job_id = job.job_id
27
- kube_job.metadata.queue_name = job.queue_name
89
+ kube_job.metadata.annotations ||= {}
90
+ kube_job.metadata.annotations.job_id = job.job_id
91
+ kube_job.metadata.annotations.queue_name = job.queue_name
28
92
  kube_job.metadata.namespace = kube_job.metadata.namespace || kubeclient_context.namespace
29
93
  kube_job.spec.template.spec.containers.map do |container|
30
94
  container.env ||= []
@@ -38,23 +102,19 @@ module ActiveJobK8s
38
102
  container.args = ["active_job_k8s:run_job"]
39
103
  end
40
104
  end
41
- kube_job.spec.ttlSecondsAfterFinished = 300 #number of seconds the job will be erased
105
+ kube_job.spec.ttlSecondsAfterFinished = 300 # number of seconds the job will be erased
42
106
 
107
+ kube_job.metadata.labels ||= {}
108
+ if scheduled_at
109
+ kube_job.spec.suspend = true
110
+ kube_job.metadata.annotations.scheduled_at = scheduled_at.to_s
111
+ kube_job.metadata.labels.activeJobK8s = "scheduled" # job to be execute when time comes
112
+ else
113
+ kube_job.metadata.labels.activeJobK8s = "delayed" # job to be execute when possible
114
+ end
43
115
  client.create_job(kube_job)
44
116
  end
45
117
 
46
- def self.execute_job
47
- ActiveJob::Base.execute(JSON.parse(ENV['SERIALIZED_JOB']))
48
- end
49
-
50
- protected
51
-
52
- def client
53
- @client ||= Kubeclient::Client.new(@kubeclient_context.api_endpoint + '/apis/batch',
54
- @kubeclient_context.api_version || 'v1',
55
- ssl_options: @kubeclient_context.ssl_options,
56
- auth_options: @kubeclient_context.auth_options)
57
- end
58
118
  end
59
119
 
60
120
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveJobK8s
2
- VERSION = "0.1.0"
2
+ VERSION = "1.0.0-beta.1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_job_k8s
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0.pre.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marino Bonetti
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-30 00:00:00.000000000 Z
11
+ date: 2023-01-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kubeclient
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: http
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '5.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '5.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rails
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -66,6 +80,7 @@ files:
66
80
  - bin/cluster.yaml
67
81
  - bin/console
68
82
  - bin/setup
83
+ - bin/teardown
69
84
  - lib/active_job/queue_adapters/k8s_adapter.rb
70
85
  - lib/active_job_k8s.rb
71
86
  - lib/active_job_k8s/railtie.rb
@@ -79,7 +94,7 @@ metadata:
79
94
  allowed_push_host: https://rubygems.org
80
95
  homepage_uri: https://github.com/oniram88/active_job_k8s
81
96
  source_code_uri: https://github.com/oniram88/active_job_k8s
82
- changelog_uri: https://github.com/oniram88/active_job_k8s/CHANGELOG.md
97
+ changelog_uri: https://github.com/oniram88/active_job_k8s/blob/master/CHANGELOG.md
83
98
  post_install_message:
84
99
  rdoc_options: []
85
100
  require_paths:
@@ -88,14 +103,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
88
103
  requirements:
89
104
  - - ">="
90
105
  - !ruby/object:Gem::Version
91
- version: 2.3.0
106
+ version: 2.7.0
92
107
  required_rubygems_version: !ruby/object:Gem::Requirement
93
108
  requirements:
94
- - - ">="
109
+ - - ">"
95
110
  - !ruby/object:Gem::Version
96
- version: '0'
111
+ version: 1.3.1
97
112
  requirements: []
98
- rubygems_version: 3.2.33
113
+ rubygems_version: 3.1.4
99
114
  signing_key:
100
115
  specification_version: 4
101
116
  summary: ActiveJob adapter for kubernetes job