tq 0.2.1 → 0.3.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
  SHA1:
3
- metadata.gz: 877e9730d05610f3b211c7a0d69817f60149bde4
4
- data.tar.gz: eb2d73a1f7e5a63659fe53041171bde055e59523
3
+ metadata.gz: 6c715d2a759e261f57e2f4f3a745e8c641187e8e
4
+ data.tar.gz: a996d693740eb9a6846bc510e178e6c935639b41
5
5
  SHA512:
6
- metadata.gz: 9c2539a74728b068c962eab6e1637559664e1a5a74514623893b756166c1246641c5b33dc5892e671ada06a7e2760bba2453137b0ba98f74813c729bbdbaed3b
7
- data.tar.gz: 2981fa8c831cf086873d2d9dfd2fef886533dc01baaa5521b0d4ea2f6f6a701ed37a165299f558a92ba3397d98ddab54415f1658bad433192335a261063b9b45
6
+ metadata.gz: 7c350e6cd8cf00d23926f4bb980af5f8221a6346ba2d3047480dd80ec0052fd81f3441fd0df7b83c26d12bdd6391bfaf8ce39e04a77094acb9c3e689856440c7
7
+ data.tar.gz: 44cbccddca8ed63e62e06e629b70c81598e43078df946f507e796821246d547f34fd92d414c8135db76c840ffcf59550ab82a6e043f0d5e7b1e906027f4b0aa6
data/.gems CHANGED
@@ -1,3 +1,3 @@
1
- google-api-client -v 0.8.4
2
- minitest -v 5.5.1
3
- parallel -v 1.4.1
1
+ google-api-client -v 0.19.3
2
+ minitest -v 5.11.1
3
+ parallel -v 1.12.1
data/lib/tq.rb CHANGED
@@ -1,5 +1,252 @@
1
+ require 'json'
2
+
3
+ require 'googleauth'
4
+ require 'google/apis'
5
+ require 'google/apis/cloudtasks_v2beta2'
6
+ require 'parallel'
7
+
1
8
  require_relative 'version'
2
- require_relative 'tq/app'
3
- require_relative 'tq/queue'
4
- require_relative 'tq/logger'
5
9
 
10
+ module TQ
11
+
12
+ CloudTasks = Google::Apis::CloudtasksV2beta2
13
+
14
+ API_SCOPES = ['https://www.googleapis.com/auth/cloud-tasks' ]
15
+
16
+ module Utils
17
+
18
+ def options_including(keys, options)
19
+ options.select { |k,_| keys.include?(k) }
20
+ end
21
+
22
+ end
23
+
24
+ class App
25
+
26
+ attr_reader :worker, :queue_in, :queue_out, :queue_err, :logger, :concurrency, :env
27
+ def initialize( worker, queue_in, queue_out: nil, queue_err: nil,
28
+ logger: nil, concurrency: 1, env: {} )
29
+ @worker = worker
30
+ @queue_in = queue_in
31
+ @queue_out = queue_out
32
+ @queue_err = queue_err
33
+ @logger = logger
34
+ @concurrency = concurrency
35
+ @env = env
36
+ end
37
+
38
+ def call(auth_file=nil)
39
+ if auth_file
40
+ run!( service_account_client(auth_file) )
41
+ else
42
+ run!( default_client )
43
+ end
44
+ end
45
+
46
+ def run!(client)
47
+ setup_api_logger!
48
+ qin = TQ::Queue.new(client, queue_in)
49
+ qout = queue_out.nil? ? nil : TQ::Queue.new(client, queue_out)
50
+ qerr = queue_err.nil? ? nil : TQ::Queue.new(client, queue_err)
51
+
52
+ tasks = qin.lease!
53
+
54
+ Parallel.each(tasks, :in_threads => concurrency) do |task|
55
+ worker.new(qin, qout, qerr, env_with_logger).call(task)
56
+ end
57
+ end
58
+
59
+ def default_client
60
+ CloudTasks::CloudTasksService.new
61
+ end
62
+
63
+ def service_account_client(file)
64
+ return TQ::ServiceAccount.client(file)
65
+ end
66
+
67
+ def setup_api_logger!
68
+ Google::Apis.logger = logger
69
+ end
70
+
71
+ def env_with_logger
72
+ env.merge({ 'logger' => logger })
73
+ end
74
+
75
+ end
76
+
77
+ module ServiceAccount
78
+ extend self
79
+
80
+ def client(file)
81
+ creds = Google::Auth::ServiceAccountCredentials.make_creds(
82
+ :json_key_io => File.open(file, 'r'),
83
+ :scope => TQ::API_SCOPES
84
+ )
85
+ creds.fetch_access_token!
86
+
87
+ client = CloudTasks::CloudTasksService.new
88
+ client.authorization = creds
89
+ client
90
+ end
91
+
92
+ end
93
+
94
+ class QueueSpec
95
+ extend TQ::Utils
96
+
97
+ def self.from_hash(data)
98
+ return new(
99
+ data['project'],
100
+ data['location'],
101
+ data['name'],
102
+ **options_including(['lease_duration','max_tasks'], data)
103
+ )
104
+ end
105
+
106
+ attr_reader :project, :location, :name, :lease_duration, :max_tasks
107
+ def initialize(project, location, name,
108
+ lease_duration: '60s', max_tasks: 1)
109
+ @project = project
110
+ @location = location
111
+ @name = name
112
+ @lease_duration = lease_duration
113
+ @max_tasks = max_tasks
114
+ end
115
+
116
+ def queue_name
117
+ "projects/#{project}/locations/#{location}/queues/#{name}"
118
+ end
119
+
120
+ end
121
+
122
+
123
+ class Queue
124
+
125
+ attr_reader :client, :queue
126
+ def initialize(client, spec)
127
+ @client = client
128
+ @queue = spec
129
+ end
130
+
131
+ def queue_name
132
+ queue.queue_name
133
+ end
134
+
135
+ def lease!
136
+ msg = { :lease_duration => queue.lease_duration,
137
+ :max_tasks => queue.max_tasks,
138
+ :response_view => 'FULL'
139
+ }
140
+ results = client.lease_tasks( queue_name,
141
+ CloudTasks::LeaseTasksRequest.new( **msg )
142
+ )
143
+ items = results.tasks || []
144
+ items.map {|t| new_task(t)}
145
+ end
146
+
147
+
148
+ # Note: does not actually extend the time, but sets the total duration
149
+ # to the given amount (minus any already elapsed time).
150
+ #
151
+ def extend!(task, dur)
152
+ msg = { :lease_duration => dur,
153
+ :schedule_time => task.schedule_time,
154
+ :response_view => 'FULL'
155
+ }
156
+ results = client.renew_task_lease( task.name,
157
+ CloudTasks::RenewLeaseRequest.new( **msg )
158
+ )
159
+ return new_task(results)
160
+ end
161
+
162
+ def push!(payload, tag=nil)
163
+ msg = { :payload => encode(payload), :tag => tag }.reject {|k,v| v.nil?}
164
+ results = client.create_task( queue_name,
165
+ CloudTasks::CreateTaskRequest.new(
166
+ :task => CloudTasks::Task.new(
167
+ :pull_message => CloudTasks::PullMessage.new( **msg )
168
+ )
169
+ )
170
+ )
171
+ new_task(results)
172
+ end
173
+
174
+ def finish!(task)
175
+ results = client.acknowledge_task( task.name,
176
+ CloudTasks::AcknowledgeTaskRequest.new( :schedule_time => task.schedule_time )
177
+ )
178
+ return
179
+ end
180
+
181
+
182
+ private
183
+
184
+ def new_task(t)
185
+ TQ::Task.new self, t
186
+ end
187
+
188
+ def encode(obj)
189
+ JSON.dump(obj)
190
+ end
191
+
192
+ end
193
+
194
+ class Task
195
+
196
+ attr_reader :task
197
+ def initialize(queue, task)
198
+ @queue = queue
199
+ @task = task
200
+ @clock = Time
201
+ end
202
+
203
+ def name
204
+ self.task.name
205
+ end
206
+
207
+ def expires
208
+ DateTime.rfc3339(self.task.schedule_time).to_time
209
+ end
210
+
211
+ def tag
212
+ self.task.tag
213
+ end
214
+
215
+ def payload
216
+ decode self.task.pull_message.payload
217
+ end
218
+
219
+ def finish!
220
+ @queue.finish!(self.task)
221
+ end
222
+
223
+ def extend!(dur)
224
+ @queue.extend!(self.task, dur)
225
+ end
226
+
227
+ def clock!(_)
228
+ @clock = _; return self
229
+ end
230
+
231
+ def reset_clock!
232
+ @clock = Time; return self
233
+ end
234
+
235
+ def lease_remaining
236
+ self.expires - @clock.now
237
+ end
238
+
239
+ def lease_expired?
240
+ self.expires < @clock.now
241
+ end
242
+
243
+ private
244
+
245
+ def decode(str)
246
+ JSON.load(str)
247
+ end
248
+
249
+ end
250
+
251
+
252
+ end
@@ -1,4 +1,4 @@
1
1
 
2
2
  module TQ
3
- VERSION = '0.2.1'
3
+ VERSION = '0.3.1'
4
4
  end
@@ -4,7 +4,9 @@ require 'logger'
4
4
  gem 'minitest'
5
5
  require 'minitest/autorun'
6
6
 
7
- require 'google/api_client'
7
+ require 'googleauth'
8
+ require 'google/apis'
9
+ require 'google/apis/cloudtasks_v2beta2'
8
10
 
9
11
  module TestUtils
10
12
  extend self
@@ -14,122 +16,64 @@ module TestUtils
14
16
  FileUtils.mkdir_p( File.dirname(file) )
15
17
  logger = Logger.new( File.open(file, 'w' ) )
16
18
  logger.level = ENV['DEBUG'] ? Logger::DEBUG : Logger::INFO
17
- Google::APIClient.logger = logger
19
+ Google::Apis.logger = logger
18
20
  end
19
21
 
20
22
  def current_logger
21
- Google::APIClient.logger
23
+ Google::Apis.logger
22
24
  end
23
25
 
24
26
  class QueueHelper
25
27
 
26
- attr_reader :project, :queue
27
- def initialize(project,queue)
28
- @project, @queue = project, queue
29
- @service_auth = false
30
- end
31
-
32
- def auth_files(secrets,creds)
33
- @secrets_file, @creds_file = secrets, creds
34
- @service_auth = false
35
- return self
36
- end
37
-
38
- def service_auth_files(issuer,p12)
39
- @secrets_issuer, @secrets_p12 = issuer, p12
40
- @service_auth = true
41
- return self
42
- end
43
-
44
- def authorized_client
45
- @authorized_client ||= (
46
- if @service_auth
47
- TQ::App.new('test_app',nil).service_auth!(
48
- File.read(@secrets_issuer).chomp, @secrets_p12
49
- )
50
- else
51
- TQ::App.new('test_app',nil).auth!(@secrets_file, @creds_file)
52
- end
53
- )
54
- end
28
+ CloudTasks = Google::Apis::CloudtasksV2beta2
55
29
 
56
- # Note: inaccurate, don't use
57
- def peek()
58
- client, api = authorized_client
59
- results = client.execute!( :api_method => api.tasks.list,
60
- :parameters => { :project => project, :taskqueue => queue }
61
- )
62
- items = results.data['items'] || []
30
+ def initialize(spec, authfile)
31
+ @queue = spec
32
+ @authfile = authfile
63
33
  end
64
34
 
65
- def push!(payload)
66
- client, api = authorized_client
67
- client.execute!( :api_method => api.tasks.insert,
68
- :parameters => { :project => project, :taskqueue => queue },
69
- :body_object => {
70
- 'queueName' => queue,
71
- 'payloadBase64' => encode(payload)
72
- }
35
+ def purge!
36
+ client = service_account_client
37
+ client.purge_queue(@queue.queue_name,
38
+ CloudTasks::PurgeQueueRequest.new
73
39
  )
40
+ return
74
41
  end
75
42
 
76
- def pop!(n=1)
77
- client, api = authorized_client
78
- results = client.execute!( :api_method => api.tasks.lease,
79
- :parameters => { :project => project, :taskqueue => queue,
80
- :leaseSecs => 60, :numTasks => n
81
- }
82
- )
83
- items = results.data['items'] || []
84
- items.each do |item|
85
- client.execute!( :api_method => api.tasks.delete,
86
- :parameters => { :project => project, :taskqueue => queue, :task => item['id'] }
87
- )
43
+ # Note: longer way to do it, but gets the count
44
+ def clear!
45
+ client = service_account_client
46
+ results = client.list_project_location_queue_tasks(@queue.queue_name)
47
+ tasks = (results.tasks || [])
48
+ tasks.each do |t|
49
+ client.delete_project_location_queue_task( t.name )
88
50
  end
89
- return items
90
- end
91
-
92
- def all_payloads!
93
- map! { |t| decode(t['payloadBase64']) }
51
+ return tasks
94
52
  end
95
53
 
96
- def all_tags!
97
- map! { |t| t['tag'] }
54
+ def push!(data)
55
+ client = service_account_client
56
+ q = TQ::Queue.new(client, @queue)
57
+ return q.push!(data)
98
58
  end
99
59
 
100
- def all_payloads_and_tags!
101
- map! { |t| {:payload => decode(t['payloadBase64']),
102
- :tag => t['tag']
103
- }
104
- }
105
- end
106
-
107
- def map!(&b)
108
- clear!.map(&b)
109
- end
110
-
111
- def clear!
112
- client, api = authorized_client
113
- done = false
114
- all = []
115
- while !done do
116
- batch = pop!(10)
117
- done = batch.empty? || batch.length < 10
118
- all = all + batch
119
- end
120
- all
121
- end
60
+ def service_account_client
61
+ creds = Google::Auth::ServiceAccountCredentials.make_creds(
62
+ :json_key_io => File.open(@authfile, 'r'),
63
+ :scope => TQ::API_SCOPES
64
+ )
65
+ creds.fetch_access_token!
122
66
 
123
- def encode(obj)
124
- Base64.urlsafe_encode64(JSON.dump(obj))
67
+ client = CloudTasks::CloudTasksService.new
68
+ client.authorization = creds
69
+ client
125
70
  end
126
71
 
127
- def decode(str)
128
- JSON.load(Base64.urlsafe_decode64(str))
72
+ def messages!
73
+ clear!.map {|t| t.pull_message }
129
74
  end
130
75
 
131
76
  end
132
77
 
133
-
134
78
  end
135
79
 
@@ -1,4 +1,4 @@
1
1
 
2
- %w[ test_shell test_run test_logger ].each do |rb|
2
+ %w[ test_auth test_run test_logger ].each do |rb|
3
3
  require_relative rb
4
4
  end