td-querier 0.0.5 → 0.0.6
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/Gemfile.lock +14 -9
- data/README.md +47 -3
- data/VERSION +1 -1
- data/lib/td/querier.rb +7 -7
- data/spec/querier_spec.rb +87 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 478227b02106d0610c2662f2507c894bf32bd393
|
4
|
+
data.tar.gz: ead6a5f69c35e4c6d0e167ea7a93c90889e12aca
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 013197d771d0710df0c51823d2975b4b2e262ff039e926120c0e6cb40d559b0818060f862b5837914143e13738189f44ae83e1c57448f3c7430deddfaca5bf45
|
7
|
+
data.tar.gz: 735e9f9635ec2cb22651d4effe909cdbd5ce40e817a4ad4bbe6da34781012d761fef867cf0a8703b2faccf9cee12615ba923180b64604af4e5554650e059553b
|
data/Gemfile.lock
CHANGED
@@ -1,24 +1,28 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
td-querier (0.0.
|
5
|
-
sidekiq (
|
6
|
-
td (
|
4
|
+
td-querier (0.0.5)
|
5
|
+
sidekiq (~> 2.7.2)
|
6
|
+
td (~> 0.10.73)
|
7
7
|
|
8
8
|
GEM
|
9
9
|
remote: http://rubygems.org/
|
10
10
|
specs:
|
11
|
-
celluloid (0.
|
11
|
+
celluloid (0.12.4)
|
12
|
+
facter (>= 1.6.12)
|
12
13
|
timers (>= 1.0.0)
|
13
14
|
connection_pool (1.0.0)
|
14
15
|
diff-lcs (1.2.4)
|
16
|
+
facter (1.6.17)
|
15
17
|
fluent-logger (0.4.5)
|
16
18
|
msgpack (= 0.4.7)
|
17
19
|
yajl-ruby (~> 1.0)
|
18
20
|
hirb (0.7.1)
|
19
21
|
json (1.7.7)
|
20
22
|
msgpack (0.4.7)
|
23
|
+
multi_json (1.7.3)
|
21
24
|
parallel (0.5.21)
|
25
|
+
rake (10.0.4)
|
22
26
|
redis (3.0.4)
|
23
27
|
redis-namespace (1.3.0)
|
24
28
|
redis (~> 3.0.0)
|
@@ -31,11 +35,11 @@ GEM
|
|
31
35
|
diff-lcs (>= 1.1.3, < 2.0)
|
32
36
|
rspec-mocks (2.13.1)
|
33
37
|
rubyzip (0.9.9)
|
34
|
-
sidekiq (2.
|
35
|
-
celluloid (
|
36
|
-
connection_pool (
|
37
|
-
|
38
|
-
redis (
|
38
|
+
sidekiq (2.7.2)
|
39
|
+
celluloid (~> 0.12.0)
|
40
|
+
connection_pool (~> 1.0)
|
41
|
+
multi_json (~> 1)
|
42
|
+
redis (~> 3)
|
39
43
|
redis-namespace
|
40
44
|
td (0.10.77)
|
41
45
|
hirb (>= 0.4.5)
|
@@ -59,5 +63,6 @@ PLATFORMS
|
|
59
63
|
ruby
|
60
64
|
|
61
65
|
DEPENDENCIES
|
66
|
+
rake
|
62
67
|
rspec
|
63
68
|
td-querier!
|
data/README.md
CHANGED
@@ -1,7 +1,51 @@
|
|
1
|
-
|
1
|
+
## Treasure Data and Sidekiq awesomeness
|
2
2
|
|
3
|
-
|
3
|
+
###Concept
|
4
|
+
Treasure data jobs take sometime to finish, and in most scenarios waiting is not really an option.
|
4
5
|
|
6
|
+
Td-querier will create a Sidekiq job with the job_id of your Treasure Data Queries and will check if the job has finished.
|
7
|
+
|
8
|
+
If it is finished, it will send a callback to continue your data process.
|
9
|
+
|
10
|
+
If not it will reschedule itself until the job is done.
|
11
|
+
|
12
|
+
###Installation
|
5
13
|
$ gem install td-querier
|
6
14
|
|
7
|
-
|
15
|
+
###Usage
|
16
|
+
```
|
17
|
+
querier = Querier.new("TREASURE_DATA_API_KEY")
|
18
|
+
database_name = 'my_td_database_name'
|
19
|
+
query_text = 'select count(*) from my_table'
|
20
|
+
options = {:klass=>"MyClass", :method=>"my_method", :results => "true"} #See Options section for this one
|
21
|
+
|
22
|
+
#Optional
|
23
|
+
on_demand_path = 'mysql://user:password@host/database/table' #will insert the result of your query into another table
|
24
|
+
priority = 1 #default 1
|
25
|
+
reschedule_time #Time interval for checking if the job is finished
|
26
|
+
|
27
|
+
querier.query(database_name, query_text, on_demand_path, options, priority, reschedule_time)
|
28
|
+
```
|
29
|
+
|
30
|
+
###Options
|
31
|
+
Once the job has finished sidekiq will stop retriying and will send a callback to a class method specified on the options.
|
32
|
+
|
33
|
+
* klass: The name of the class you want to use, i.e. "MyClass"
|
34
|
+
* method: The name of the class method you want to use, i.e. "my_method"
|
35
|
+
* results: if is "true" will fetch the results from treasure data and it will pass those results to your method as a parameter. Be aware that exceptionally large results might impact your performance.
|
36
|
+
|
37
|
+
###Internals
|
38
|
+
Querier objects are designed to query treasure data api asynchronously.
|
39
|
+
|
40
|
+
This gem uses [Sidekiq] (https://github.com/mperham/sidekiq) so make sure your app plays nice with that.
|
41
|
+
|
42
|
+
Also it uses [td gem](https://rubygems.org/gems/td)
|
43
|
+
|
44
|
+
### Contributing
|
45
|
+
|
46
|
+
1. Fork it
|
47
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
48
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
49
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
50
|
+
5. Create new Pull Request
|
51
|
+
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0.
|
1
|
+
0.0.6
|
data/lib/td/querier.rb
CHANGED
@@ -10,24 +10,24 @@ class Querier
|
|
10
10
|
@api_key = api_key
|
11
11
|
end
|
12
12
|
|
13
|
-
def query(database, query,
|
13
|
+
def query(database, query, opts, on_demand_path='', priority=1, reschedule_time=300)
|
14
14
|
client = TreasureData::Client.new(@api_key)
|
15
|
-
job = client.query(database, query,
|
15
|
+
job = client.query(database, query, on_demand_path, priority)
|
16
16
|
Querier.perform_async(@api_key, job.job_id, opts, reschedule_time)
|
17
17
|
end
|
18
18
|
|
19
|
-
def perform(api_key, job_id, opts, reschedule_time=
|
19
|
+
def perform(api_key, job_id, opts, reschedule_time=300)
|
20
20
|
client = TreasureData::Client.new(api_key)
|
21
21
|
job = client.job(job_id)
|
22
22
|
#reschedule if the job is not finished
|
23
23
|
return Querier.perform_in(reschedule_time, api_key, job_id, opts, reschedule_time) unless job.finished?
|
24
24
|
|
25
25
|
if opts
|
26
|
-
klass = opts[
|
27
|
-
meth = opts[
|
28
|
-
send_results = opts[
|
26
|
+
klass = opts[:klass]
|
27
|
+
meth = opts[:method]
|
28
|
+
send_results = opts[:results]
|
29
29
|
results = (send_results.to_s == "true" ? job.results : nil)
|
30
|
-
|
30
|
+
eval(klass).send(meth.to_s, results)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
data/spec/querier_spec.rb
CHANGED
@@ -1,6 +1,91 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'debugger'
|
3
2
|
|
4
3
|
describe Querier do
|
5
|
-
|
4
|
+
describe "Send the query to treasaure data" do
|
5
|
+
context "Wrong parameters" do
|
6
|
+
|
7
|
+
it "will raise an error if the api key is not valid" do
|
8
|
+
fake_client = Object.new
|
9
|
+
fake_client.should_receive(:query).and_raise(TreasureData::APIError.new("apikey authentication failed"))
|
10
|
+
TreasureData::Client.should_receive(:new).and_return(fake_client)
|
11
|
+
Querier.should_not_receive(:perform_async)
|
12
|
+
|
13
|
+
querier = Querier.new("bad_key")
|
14
|
+
lambda{querier.query("database", "my_query", {})}.should raise_error(TreasureData::APIError)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "will raise an error if the database name is not valid" do
|
18
|
+
fake_client = Object.new
|
19
|
+
fake_client.should_receive(:query).and_raise(TreasureData::NotFoundError.new("Couldn't find UserDatabase with name = bad_name"))
|
20
|
+
TreasureData::Client.should_receive(:new).and_return(fake_client)
|
21
|
+
Querier.should_not_receive(:perform_async)
|
22
|
+
|
23
|
+
querier = Querier.new("good_key")
|
24
|
+
lambda{querier.query("bad_name", "my_query", {})}.should raise_error(TreasureData::NotFoundError)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context "Right parameters" do
|
29
|
+
it "will send a query to treasure data and instance a sidekiq job with the job id of the new job" do
|
30
|
+
fake_job = Object.new
|
31
|
+
fake_job.should_receive(:job_id).and_return(1)
|
32
|
+
|
33
|
+
fake_client = Object.new
|
34
|
+
fake_client.should_receive(:query).and_return(fake_job)
|
35
|
+
|
36
|
+
TreasureData::Client.should_receive(:new).and_return(fake_client)
|
37
|
+
|
38
|
+
Querier.should_receive(:perform_async).and_return(true)
|
39
|
+
|
40
|
+
querier = Querier.new("good_key")
|
41
|
+
querier.query("database", "my_query", {})
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "Sidekiq processing" do
|
47
|
+
context "Standar processing" do
|
48
|
+
before(:each) do
|
49
|
+
@opts = {:klass => "Object", :method => "fake_method", :results => "false"}
|
50
|
+
@fake_job = Object.new
|
51
|
+
@fake_client = Object.new
|
52
|
+
@fake_client.should_receive(:job).and_return(@fake_job)
|
53
|
+
TreasureData::Client.should_receive(:new).and_return(@fake_client)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "will reschedule the sidekiq job if the treasure data job is not yet finished" do
|
57
|
+
@fake_job.should_receive(:finished?).and_return(false)
|
58
|
+
Querier.should_receive(:perform_in).with(300, "apikey", 1, @opts, 300).and_return(true)
|
59
|
+
Querier.new.perform("apikey", 1, @opts)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "will make a call to a given class method if que job is finished" do
|
63
|
+
@fake_job.should_receive(:finished?).and_return(true)
|
64
|
+
Object.should_receive(:fake_method).and_return(true)
|
65
|
+
Querier.new.perform("apikey", 1, @opts)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "will request the query results if the options for result are set to true" do
|
69
|
+
new_opts = {:klass => "Object", :method => "fake_method", :results => "true"}
|
70
|
+
results = [[1]]
|
71
|
+
@fake_job.should_receive(:finished?).and_return(true)
|
72
|
+
@fake_job.should_receive(:results).and_return(results)
|
73
|
+
Object.should_receive(:fake_method).and_return(true)
|
74
|
+
Querier.new.perform("apikey", 1, new_opts)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "Error case" do
|
79
|
+
it "will raise an exception if something explodes within sidekiq" do
|
80
|
+
@opts = {:klass => "Object", :method => "fake_method", :results => "false"}
|
81
|
+
@fake_job = Object.new
|
82
|
+
@fake_client = Object.new
|
83
|
+
@fake_client.should_receive(:job).and_return(@fake_job)
|
84
|
+
TreasureData::Client.should_receive(:new).and_return(@fake_client)
|
85
|
+
|
86
|
+
@fake_job.should_receive(:finished?).and_raise(RuntimeError.new("unexpected error"))
|
87
|
+
lambda{Querier.new.perform("apikey", 1, @opts)}.should raise_error(RuntimeError)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
6
91
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: td-querier
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Carlos Donderis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-05-
|
11
|
+
date: 2013-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sidekiq
|