presto-client 0.5.12 → 0.5.13
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/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
|