presto-client 0.5.12 → 0.5.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog +6 -0
- data/README.md +3 -2
- data/lib/presto/client/errors.rb +3 -0
- data/lib/presto/client/statement_client.rb +46 -3
- data/lib/presto/client/version.rb +1 -1
- data/spec/statement_client_spec.rb +155 -0
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 25d825cdb3befbfa69b368f05d2267ed4bc3affd
|
4
|
+
data.tar.gz: abbc72ac27018abef03fbe2c5a122cc96aff68e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5988faa2e414bdb31a1368eb3a829e1a30872195a8bf6aa1a0ece60edb832ca64af70f6e3cfa8b2e85e7b20786b2ab943fdfa8b340158fab33d5d8279b8a440
|
7
|
+
data.tar.gz: 00eb3921405da85361bda22d588982e3e8d706ac118bd694cfab94849812bdb25e27ce8e5c0ba43d437d21a1fdbf03d9a09075722e4569082680ce5fa376c25e
|
data/ChangeLog
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
2018-12-10 version 0.5.13
|
2
|
+
|
3
|
+
* Added `query_timeout` and `plan_timeout` options with default disabled
|
4
|
+
* Changed timer to use CLOCK_MONOTONIC to avoid unexpected behavior when
|
5
|
+
system clock is updated
|
6
|
+
|
1
7
|
2018-08-07 version 0.5.12
|
2
8
|
|
3
9
|
* Upgrade to Presto 0.205 model
|
data/README.md
CHANGED
@@ -94,12 +94,14 @@ $ bundle exec rake modelgen:latest
|
|
94
94
|
* **time_zone** sets time zone of queries. Time zone affects some functions such as `format_datetime`.
|
95
95
|
* **language** sets language of queries. Language affects some functions such as `format_datetime`.
|
96
96
|
* **properties** set session properties. Session properties affect internal behavior such as `hive.force_local_scheduling: true`, `raptor.reader_stream_buffer_size: "32MB"`, etc.
|
97
|
+
* **query_timeout** sets timeout in seconds for the entire query execution (from the first API call until there're no more output data). If timeout happens, client raises PrestoQueryTimeoutError. Default is nil (disabled).
|
98
|
+
* **plan_timeout** sets timeout in seconds for query planning execution (from the first API call until result columns become available). If timeout happens, client raises PrestoQueryTimeoutError. Default is nil (disabled).
|
97
99
|
* **http_headers** sets custom HTTP headers. It must be a Hash of string to string.
|
98
100
|
* **http_proxy** sets host:port of a HTTP proxy server.
|
99
101
|
* **http_debug** enables debug message to STDOUT for each HTTP requests.
|
100
102
|
* **http_open_timeout** sets timeout in seconds to open new HTTP connection.
|
101
103
|
* **http_timeout** sets timeout in seconds to read data from a server.
|
102
|
-
* **model_version** set the presto version to which a job is submitted. Supported versions are 0.153 and 0.149. Default is 0.
|
104
|
+
* **model_version** set the presto version to which a job is submitted. Supported versions are 0.205, 0.178, 0.173, 0.153 and 0.149. Default is 0.205.
|
103
105
|
|
104
106
|
See [RDoc](http://www.rubydoc.info/gems/presto-client/) for the full documentation.
|
105
107
|
|
@@ -112,4 +114,3 @@ See [RDoc](http://www.rubydoc.info/gems/presto-client/) for the full documentati
|
|
112
114
|
3. git commit -am "vX.Y.Z"
|
113
115
|
4. git tag "vX.Y.Z"
|
114
116
|
5. git push --tags
|
115
|
-
|
data/lib/presto/client/errors.rb
CHANGED
@@ -40,6 +40,15 @@ module Presto::Client
|
|
40
40
|
@models = Models
|
41
41
|
end
|
42
42
|
|
43
|
+
@plan_timeout = options[:plan_timeout]
|
44
|
+
@query_timeout = options[:query_timeout]
|
45
|
+
|
46
|
+
if @plan_timeout || @query_timeout
|
47
|
+
# this is set before the first call of faraday_get_with_retry so that
|
48
|
+
# resuming StatementClient with next_uri is also under timeout control.
|
49
|
+
@started_at = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
50
|
+
end
|
51
|
+
|
43
52
|
if next_uri
|
44
53
|
response = faraday_get_with_retry(next_uri)
|
45
54
|
@results = @models::QueryResults.decode(parse_body(response))
|
@@ -110,11 +119,13 @@ module Presto::Client
|
|
110
119
|
if closed? || !has_next?
|
111
120
|
return false
|
112
121
|
end
|
113
|
-
uri = @results.next_uri
|
114
122
|
|
123
|
+
uri = @results.next_uri
|
115
124
|
response = faraday_get_with_retry(uri)
|
116
125
|
@results = decode_model(uri, parse_body(response), @models::QueryResults)
|
117
126
|
|
127
|
+
raise_if_timeout!
|
128
|
+
|
118
129
|
return true
|
119
130
|
end
|
120
131
|
|
@@ -156,7 +167,7 @@ module Presto::Client
|
|
156
167
|
private :parse_body
|
157
168
|
|
158
169
|
def faraday_get_with_retry(uri, &block)
|
159
|
-
start =
|
170
|
+
start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
160
171
|
attempts = 0
|
161
172
|
|
162
173
|
begin
|
@@ -182,14 +193,46 @@ module Presto::Client
|
|
182
193
|
end
|
183
194
|
end
|
184
195
|
|
196
|
+
raise_if_timeout!
|
197
|
+
|
185
198
|
attempts += 1
|
186
199
|
sleep attempts * 0.1
|
187
|
-
end while (
|
200
|
+
end while (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) < @retry_timeout && !@closed
|
188
201
|
|
189
202
|
@exception = PrestoHttpError.new(408, "Presto API error due to timeout")
|
190
203
|
raise @exception
|
191
204
|
end
|
192
205
|
|
206
|
+
def raise_if_timeout!
|
207
|
+
if @started_at
|
208
|
+
if @results && @results.next_uri == nil
|
209
|
+
# query is already done
|
210
|
+
return
|
211
|
+
end
|
212
|
+
|
213
|
+
elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started_at
|
214
|
+
|
215
|
+
if @query_timeout && elapsed > @query_timeout
|
216
|
+
raise_timeout_error!
|
217
|
+
end
|
218
|
+
|
219
|
+
if @plan_timeout && (@results == nil || @results.columns == nil) &&
|
220
|
+
elapsed > @plan_timeout
|
221
|
+
# @results is not set (even first faraday_get_with_retry isn't called yet) or
|
222
|
+
# result from Presto doesn't include result schema. Query planning isn't done yet.
|
223
|
+
raise_timeout_error!
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def raise_timeout_error!
|
229
|
+
if query_id = @results && @results.id
|
230
|
+
raise PrestoQueryTimeoutError, "Query #{query_id} timed out"
|
231
|
+
else
|
232
|
+
raise PrestoQueryTimeoutError, "Query timed out"
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
193
236
|
def cancel_leaf_stage
|
194
237
|
if uri = @results.next_uri
|
195
238
|
response = @faraday.delete do |req|
|
@@ -401,5 +401,160 @@ describe Presto::Client::StatementClient do
|
|
401
401
|
|
402
402
|
StatementClient.new(faraday, query, options)
|
403
403
|
end
|
404
|
+
|
405
|
+
describe "query timeout" do
|
406
|
+
let :headers do
|
407
|
+
{
|
408
|
+
"User-Agent" => "presto-ruby/#{VERSION}",
|
409
|
+
"X-Presto-Catalog" => options[:catalog],
|
410
|
+
"X-Presto-Schema" => options[:schema],
|
411
|
+
"X-Presto-User" => options[:user],
|
412
|
+
"X-Presto-Language" => options[:language],
|
413
|
+
"X-Presto-Time-Zone" => options[:time_zone],
|
414
|
+
}
|
415
|
+
end
|
416
|
+
|
417
|
+
let :planning_response do
|
418
|
+
{
|
419
|
+
id: "queryid",
|
420
|
+
nextUri: 'http://localhost/v1/next_uri',
|
421
|
+
stats: {},
|
422
|
+
}
|
423
|
+
end
|
424
|
+
|
425
|
+
let :early_running_response do
|
426
|
+
{
|
427
|
+
id: "queryid",
|
428
|
+
nextUri: 'http://localhost/v1/next_uri',
|
429
|
+
stats: {},
|
430
|
+
columns: [{name: "_col0", type: "bigint"}],
|
431
|
+
}
|
432
|
+
end
|
433
|
+
|
434
|
+
let :late_running_response do
|
435
|
+
{
|
436
|
+
id: "queryid",
|
437
|
+
nextUri: 'http://localhost/v1/next_uri',
|
438
|
+
stats: {},
|
439
|
+
columns: [{name: "_col0", type: "bigint"}],
|
440
|
+
data: "",
|
441
|
+
}
|
442
|
+
end
|
443
|
+
|
444
|
+
let :done_response do
|
445
|
+
{
|
446
|
+
id: "queryid",
|
447
|
+
stats: {},
|
448
|
+
columns: [{name: "_col0", type: "bigint"}],
|
449
|
+
}
|
450
|
+
end
|
451
|
+
|
452
|
+
before(:each) do
|
453
|
+
end
|
454
|
+
|
455
|
+
[:plan_timeout, :query_timeout].each do |timeout_type|
|
456
|
+
it "raises PrestoQueryTimeoutError if timeout during planning" do
|
457
|
+
stub_request(:post, "localhost/v1/statement").
|
458
|
+
with(body: query, headers: headers).
|
459
|
+
to_return(body: planning_response.to_json)
|
460
|
+
|
461
|
+
client = StatementClient.new(faraday, query, options.merge(timeout_type => 1))
|
462
|
+
|
463
|
+
stub_request(:get, "localhost/v1/next_uri").
|
464
|
+
with(headers: headers).
|
465
|
+
to_return(body: planning_response.to_json)
|
466
|
+
client.advance
|
467
|
+
|
468
|
+
sleep 1
|
469
|
+
stub_request(:get, "localhost/v1/next_uri").
|
470
|
+
with(headers: headers).
|
471
|
+
to_return(body: planning_response.to_json)
|
472
|
+
lambda do
|
473
|
+
client.advance
|
474
|
+
end.should raise_error(Presto::Client::PrestoQueryTimeoutError, "Query queryid timed out")
|
475
|
+
end
|
476
|
+
|
477
|
+
it "raises PrestoQueryTimeoutError if timeout during initial resuming" do
|
478
|
+
stub_request(:get, "localhost/v1/next_uri").
|
479
|
+
with(headers: headers).
|
480
|
+
to_return(body: lambda{|req| raise Timeout::Error.new("execution expired")})
|
481
|
+
|
482
|
+
lambda do
|
483
|
+
StatementClient.new(faraday, query, options.merge(timeout_type => 1), "/v1/next_uri")
|
484
|
+
end.should raise_error(Presto::Client::PrestoQueryTimeoutError, "Query timed out")
|
485
|
+
end
|
486
|
+
|
487
|
+
it "raises PrestoHttpError if timeout during initial resuming and #{timeout_type} < retry_timeout" do
|
488
|
+
stub_request(:get, "localhost/v1/next_uri").
|
489
|
+
with(headers: headers).
|
490
|
+
to_return(body: lambda{|req| raise Timeout::Error.new("execution expired")})
|
491
|
+
|
492
|
+
lambda do
|
493
|
+
StatementClient.new(faraday, query, options.merge(timeout_type => 2, retry_timeout: 1), "/v1/next_uri")
|
494
|
+
end.should raise_error(Presto::Client::PrestoHttpError, "Presto API error due to timeout")
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
it "doesn't raise errors with plan_timeout if query planning is done" do
|
499
|
+
stub_request(:post, "localhost/v1/statement").
|
500
|
+
with(body: query, headers: headers).
|
501
|
+
to_return(body: planning_response.to_json)
|
502
|
+
|
503
|
+
client = StatementClient.new(faraday, query, options.merge(plan_timeout: 1))
|
504
|
+
|
505
|
+
sleep 1
|
506
|
+
|
507
|
+
stub_request(:get, "localhost/v1/next_uri").
|
508
|
+
with(headers: headers).
|
509
|
+
to_return(body: early_running_response.to_json)
|
510
|
+
client.advance
|
511
|
+
|
512
|
+
stub_request(:get, "localhost/v1/next_uri").
|
513
|
+
with(headers: headers).
|
514
|
+
to_return(body: late_running_response.to_json)
|
515
|
+
client.advance
|
516
|
+
end
|
517
|
+
|
518
|
+
it "raises PrestoQueryTimeoutError if timeout during execution" do
|
519
|
+
stub_request(:post, "localhost/v1/statement").
|
520
|
+
with(body: query, headers: headers).
|
521
|
+
to_return(body: planning_response.to_json)
|
522
|
+
|
523
|
+
client = StatementClient.new(faraday, query, options.merge(query_timeout: 1))
|
524
|
+
|
525
|
+
stub_request(:get, "localhost/v1/next_uri").
|
526
|
+
with(headers: headers).
|
527
|
+
to_return(body: early_running_response.to_json)
|
528
|
+
client.advance
|
529
|
+
|
530
|
+
sleep 1
|
531
|
+
stub_request(:get, "localhost/v1/next_uri").
|
532
|
+
with(headers: headers).
|
533
|
+
to_return(body: late_running_response.to_json)
|
534
|
+
lambda do
|
535
|
+
client.advance
|
536
|
+
end.should raise_error(Presto::Client::PrestoQueryTimeoutError, "Query queryid timed out")
|
537
|
+
end
|
538
|
+
|
539
|
+
it "doesn't raise errors if query is done" do
|
540
|
+
stub_request(:post, "localhost/v1/statement").
|
541
|
+
with(body: query, headers: headers).
|
542
|
+
to_return(body: planning_response.to_json)
|
543
|
+
|
544
|
+
client = StatementClient.new(faraday, query, options.merge(query_timeout: 1))
|
545
|
+
|
546
|
+
stub_request(:get, "localhost/v1/next_uri").
|
547
|
+
with(headers: headers).
|
548
|
+
to_return(body: early_running_response.to_json)
|
549
|
+
client.advance
|
550
|
+
|
551
|
+
sleep 1
|
552
|
+
stub_request(:get, "localhost/v1/next_uri").
|
553
|
+
with(headers: headers).
|
554
|
+
to_return(body: done_response.to_json)
|
555
|
+
client.advance
|
556
|
+
end
|
557
|
+
|
558
|
+
end
|
404
559
|
end
|
405
560
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: presto-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sadayuki Furuhashi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-12-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -170,7 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
170
170
|
version: '0'
|
171
171
|
requirements: []
|
172
172
|
rubyforge_project:
|
173
|
-
rubygems_version: 2.
|
173
|
+
rubygems_version: 2.6.13
|
174
174
|
signing_key:
|
175
175
|
specification_version: 4
|
176
176
|
summary: Presto client library
|