embulk-input-mixpanel 0.3.4 → 0.4.0

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: 4f7e9eb914b30c6a19d3afe35b5b5314497c0c83
4
- data.tar.gz: 1b3d12b83c9c06d66657b6e370ad2c28446b1754
3
+ metadata.gz: 0dedffafe59dd4e3dcbe23d13d3d2ae8f1a4046f
4
+ data.tar.gz: dad21a163d3dfe678e3b4d49531c476fe48af594
5
5
  SHA512:
6
- metadata.gz: 20a77df82f23049667d97de1a245a46844733983c5fece681dd53857507ec7eae6b1ee5a6ccefe325c48038c215584bf5590c93f710af44a64bfa1c206c4712b
7
- data.tar.gz: d9536d638c52cac6af9936bea589b408a8f1106509ed6a60d929c3cec06d2bb96d29444a7666194b50ed581d210df599914f8d979d37a23a7ac0e8cf30b2bfe7
6
+ metadata.gz: 0ac29f80faece33812fb85d48aed368398ea1fb2ee779cab01b7489ea1f171cfa7ea6aa9d017527d6ab8ca80b6966f29c22164ca0534f3878c1f94e2cd92b56c
7
+ data.tar.gz: c4a4382fd745a91c483ae5eff4b11e2aca0949a157ddcfb127d2430d273d4158c8087b350d0da5844e957a487a1c08e7bd0b1c07cef30900c23db883e870b566
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- jruby-9.0.1.0
1
+ jruby-9.0.5.0
data/.travis.yml CHANGED
@@ -1,84 +1,35 @@
1
1
  language: ruby
2
2
 
3
3
  jdk: oraclejdk8
4
+ sudo: false
4
5
 
5
6
  addons:
6
7
  code_climate:
7
8
  repo_token:
8
9
  secure: "opE/ZhRzsEU2Fn6YEnItMD/rMs3O2OHVYQQ7Ly0dAkIc9ZrVMa//ogt4k7h0QGZUettRVV7kawCtRzde+QbOmezTRwWqQJ7Mi6D6qfwlYMz+D9FcufHaCJyLy+dYeBuQqr1d6n/3gVqVGh8MAMGHipYodudCub38DQ1sVWcCMDNNo4PMRFLS0pS839SC80HAS7tutOeaeohRc+Ct5yoY2ZDoTuGtNeJhwqmDAo13RwvVu9aZw97EZPvt8UcaW5oYDnx47kDpKi4XGrTPaWpSm/IitwW11FF+Kevt0RpUS0uVWqg4/6xTjDg++ETG+94ePYrOZGF4ne/CPtC0AtaWF1jgSlL9iu4IR/Awt+2BqawKzCnoSRgCGIHRZApErC3KacadJBaPCrKwf4xxxqRXex4lXcptKRygkG4ic2r+MblyPPwIsc1Wb1QYCeVjIEGWzOgKVEUpT8qN0DAj6KQe/HuyuXKE/FiPIRfkJkRY5oGCNZtzeCzXlC+IqhZYCg6HwcZuk3CbcxRrg5VFKDlL0VWacD/FQoGgfTp3SUmaL6NMcCKSrL0vjEgx98/yM9rsGZlZOU9ioN93PQVgqpI5dl+nm9vKkFyuzW07nNM+/6PNdHbbZBY1OLNd3RSpWVC9TDtZ3Q2gAx25+31TDzD2/3yjJjfdtwIH3bdyrO44MK8="
9
- notifications:
10
- slack:
11
- secure: "cAAHcb/HdJK6elr6gfxlotUJdZys8nA/BUb1rKVt7T7EShOjqNOwHo0vZBG5fXQEbUJjHCFAl8tH1N8wz+KLoVErlMmD2OgBKGgvgm3fddkIgGRRvxe8yB0yEFy5yuvfgqJDlwPHZxbwj2Ddb8uTaLd8yzmRzGWNwLyRQTDaQbaKBaB+emP2t/1AilQHyItN02NuW3qcEGr7Hzg+IsKabDRzhMi89RV0xk2eP5iWTYW76ULbbfP3NqBpcVLskAqVQd1YOFUSEb2fdzRj7UuLUUp3C0Kb5gKfXPHb97XuMqwyviakTr02omdaM82NvB8GKn7QKBbcwA1Iz1euinxQQ7MTzJe8wLMH8q205lTpl96CANKwIxrk/HestgEboq97xSp5Wc1Qn1ynnrLOvBYW7EG/e6exguojQmkLkV9P6LW9g4nYsR8UEjyuRd252xch4+b4M3lxtlAXtpWguPfm5ZKhICBsJMlYm6//q1cBlNUOzR0cufCHDTNdlB/YLynvdg1ykFISYARP+5sV2YM9rD/1Rs/396qYr0mNbCh83P9GlZ5NZtWLQePJroHe3iQ18X3YHEcb50OTfRmKNoXTldQBD9iKNkwlFpWfruVdBWT+JRM77+yIV9ORjY7UE4ZtH8HxAg4bX+ey+C5axgxQk569h3CdLmVapFt6wovCSVk="
12
10
 
13
11
  before_install:
12
+ - rvm list
14
13
  - |
15
- # Currently, Travis can't treat jruby 9.0.1.0
16
- if [[ ${TRAVIS_RUBY_VERSION} = "jruby-9.0.0.0" ]];then
17
- rvm get head
18
- rvm use jruby-9.0.1.0 --install
19
- ruby -v
20
- fi
14
+ # Currently, Travis can't treat jruby 9.0.5.0
15
+ ruby -v
16
+ rvm get head
17
+ rvm use jruby-9.0.5.0 --install
18
+ gem install bundler
19
+ ruby -v
20
+ - gem i bundler
21
21
 
22
22
  rvm:
23
- - jruby-19mode
24
- - jruby-9.0.0.0
23
+ - jruby-9.0.5.0
25
24
 
26
25
  gemfile:
27
- - gemfiles/embulk-0.6.0-latest
28
- - gemfiles/embulk-0.6.16
29
- - gemfiles/embulk-0.6.17
30
- - gemfiles/embulk-0.6.18
31
- - gemfiles/embulk-0.6.19
32
- - gemfiles/embulk-0.6.20
33
- - gemfiles/embulk-0.6.21
34
- - gemfiles/embulk-0.6.22
35
- - gemfiles/embulk-0.6.23
36
- - gemfiles/embulk-0.6.24
37
- - gemfiles/embulk-0.6.25
38
- - gemfiles/embulk-0.6.26
39
- - gemfiles/embulk-0.6.27
40
- - gemfiles/embulk-0.7.0
41
- - gemfiles/embulk-0.7.0-latest
42
- - gemfiles/embulk-0.7.1
43
- - gemfiles/embulk-0.7.2
44
- - gemfiles/embulk-0.7.3
45
- - gemfiles/embulk-0.7.4
46
- - gemfiles/embulk-0.7.5
26
+ - gemfiles/embulk-0.8.0-latest
27
+ - gemfiles/embulk-0.8.6
47
28
  - gemfiles/embulk-latest
48
29
 
49
30
  matrix:
50
- exclude:
51
- - jdk: oraclejdk8 # Ignore all matrix at first, use `include` to allow build
52
- include:
53
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.0-latest}
54
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.16}
55
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.17}
56
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.18}
57
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.19}
58
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.20}
59
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.21}
60
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.22}
61
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.23}
62
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.24}
63
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.25}
64
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.26}
65
- - {rvm: jruby-19mode, gemfile: gemfiles/embulk-0.6.27}
66
- - {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.0}
67
- - {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.0-latest}
68
- - {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.1}
69
- - {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.2}
70
- - {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.3}
71
- - {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.4}
72
- - {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-0.7.5}
73
- - {rvm: jruby-9.0.0.0, gemfile: gemfiles/embulk-latest}
74
-
75
-
76
31
  allow_failures:
77
- - gemfile: gemfiles/embulk-0.6.22
78
- - gemfile: gemfiles/embulk-0.7.0
79
- - gemfile: gemfiles/embulk-0.7.1
80
32
  # Ignore failure for *-latest
81
- - gemfile: embulk-0.6.0-latest
82
- - gemfile: embulk-0.7.0-latest
33
+ - gemfile: embulk-0.8.0-latest
83
34
  - gemfile: embulk-latest
84
35
 
data/.travis.yml.erb CHANGED
@@ -1,27 +1,26 @@
1
1
  language: ruby
2
2
 
3
3
  jdk: oraclejdk8
4
+ sudo: false
4
5
 
5
6
  addons:
6
7
  code_climate:
7
8
  repo_token:
8
9
  secure: "opE/ZhRzsEU2Fn6YEnItMD/rMs3O2OHVYQQ7Ly0dAkIc9ZrVMa//ogt4k7h0QGZUettRVV7kawCtRzde+QbOmezTRwWqQJ7Mi6D6qfwlYMz+D9FcufHaCJyLy+dYeBuQqr1d6n/3gVqVGh8MAMGHipYodudCub38DQ1sVWcCMDNNo4PMRFLS0pS839SC80HAS7tutOeaeohRc+Ct5yoY2ZDoTuGtNeJhwqmDAo13RwvVu9aZw97EZPvt8UcaW5oYDnx47kDpKi4XGrTPaWpSm/IitwW11FF+Kevt0RpUS0uVWqg4/6xTjDg++ETG+94ePYrOZGF4ne/CPtC0AtaWF1jgSlL9iu4IR/Awt+2BqawKzCnoSRgCGIHRZApErC3KacadJBaPCrKwf4xxxqRXex4lXcptKRygkG4ic2r+MblyPPwIsc1Wb1QYCeVjIEGWzOgKVEUpT8qN0DAj6KQe/HuyuXKE/FiPIRfkJkRY5oGCNZtzeCzXlC+IqhZYCg6HwcZuk3CbcxRrg5VFKDlL0VWacD/FQoGgfTp3SUmaL6NMcCKSrL0vjEgx98/yM9rsGZlZOU9ioN93PQVgqpI5dl+nm9vKkFyuzW07nNM+/6PNdHbbZBY1OLNd3RSpWVC9TDtZ3Q2gAx25+31TDzD2/3yjJjfdtwIH3bdyrO44MK8="
9
- notifications:
10
- slack:
11
- secure: "cAAHcb/HdJK6elr6gfxlotUJdZys8nA/BUb1rKVt7T7EShOjqNOwHo0vZBG5fXQEbUJjHCFAl8tH1N8wz+KLoVErlMmD2OgBKGgvgm3fddkIgGRRvxe8yB0yEFy5yuvfgqJDlwPHZxbwj2Ddb8uTaLd8yzmRzGWNwLyRQTDaQbaKBaB+emP2t/1AilQHyItN02NuW3qcEGr7Hzg+IsKabDRzhMi89RV0xk2eP5iWTYW76ULbbfP3NqBpcVLskAqVQd1YOFUSEb2fdzRj7UuLUUp3C0Kb5gKfXPHb97XuMqwyviakTr02omdaM82NvB8GKn7QKBbcwA1Iz1euinxQQ7MTzJe8wLMH8q205lTpl96CANKwIxrk/HestgEboq97xSp5Wc1Qn1ynnrLOvBYW7EG/e6exguojQmkLkV9P6LW9g4nYsR8UEjyuRd252xch4+b4M3lxtlAXtpWguPfm5ZKhICBsJMlYm6//q1cBlNUOzR0cufCHDTNdlB/YLynvdg1ykFISYARP+5sV2YM9rD/1Rs/396qYr0mNbCh83P9GlZ5NZtWLQePJroHe3iQ18X3YHEcb50OTfRmKNoXTldQBD9iKNkwlFpWfruVdBWT+JRM77+yIV9ORjY7UE4ZtH8HxAg4bX+ey+C5axgxQk569h3CdLmVapFt6wovCSVk="
12
10
 
13
11
  before_install:
12
+ - rvm list
14
13
  - |
15
- # Currently, Travis can't treat jruby 9.0.1.0
16
- if [[ ${TRAVIS_RUBY_VERSION} = "jruby-9.0.0.0" ]];then
17
- rvm get head
18
- rvm use jruby-9.0.1.0 --install
19
- ruby -v
20
- fi
14
+ # Currently, Travis can't treat jruby 9.0.5.0
15
+ ruby -v
16
+ rvm get head
17
+ rvm use jruby-9.0.5.0 --install
18
+ gem install bundler
19
+ ruby -v
20
+ - gem i bundler
21
21
 
22
22
  rvm:
23
- - jruby-19mode
24
- - jruby-9.0.0.0
23
+ - jruby-9.0.5.0
25
24
 
26
25
  gemfile:
27
26
  <% versions.each do |file| -%>
@@ -29,17 +28,7 @@ gemfile:
29
28
  <% end -%>
30
29
 
31
30
  matrix:
32
- exclude:
33
- - jdk: oraclejdk8 # Ignore all matrix at first, use `include` to allow build
34
- include:
35
- <% matrix.each do |m| -%>
36
- <%= m %>
37
- <% end %>
38
-
39
31
  allow_failures:
40
- - gemfile: gemfiles/embulk-0.6.22
41
- - gemfile: gemfiles/embulk-0.7.0
42
- - gemfile: gemfiles/embulk-0.7.1
43
32
  # Ignore failure for *-latest
44
33
  <% versions.find_all{|file| file.to_s.match(/-latest/)}.each do |file| -%>
45
34
  - gemfile: <%= file %>
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ ## 0.4.0 - 2016-03-04
2
+
3
+ This version contains compatibility breaking. Only support Embulk 0.8 or later since this version, no longer support Embulk 0.7.x or earlier.
4
+
5
+ * [enhancement] Support json type [#35](https://github.com/treasure-data/embulk-input-mixpanel/pull/35)
6
+ * [enhancement] Check Mixpanel availability before run [#37](https://github.com/treasure-data/embulk-input-mixpanel/pull/37)
7
+ * [enhancement] Guessing time column as statically [#36](https://github.com/treasure-data/embulk-input-mixpanel/pull/36)
8
+ * [enhancement] Reduce guess and preview records [#34](https://github.com/treasure-data/embulk-input-mixpanel/pull/34)
9
+ * [maintenance] Use perfect_retry [#33](https://github.com/treasure-data/embulk-input-mixpanel/pull/33)
10
+
11
+
1
12
  ## 0.3.4 - 2015-11-02
2
13
 
3
14
  * [enhancement] Create `unknown_columns` only when option is true [#32](https://github.com/treasure-data/embulk-input-mixpanel/pull/32)
@@ -1,7 +1,7 @@
1
1
 
2
2
  Gem::Specification.new do |spec|
3
3
  spec.name = "embulk-input-mixpanel"
4
- spec.version = "0.3.4"
4
+ spec.version = "0.4.0"
5
5
  spec.authors = ["yoshihara", "uu59"]
6
6
  spec.summary = "Mixpanel input plugin for Embulk"
7
7
  spec.description = "Loads records from Mixpanel."
@@ -15,9 +15,10 @@ Gem::Specification.new do |spec|
15
15
 
16
16
  spec.add_dependency 'httpclient'
17
17
  spec.add_dependency 'tzinfo'
18
+ spec.add_dependency 'perfect_retry', ["~> 0.3"]
18
19
  spec.add_development_dependency 'bundler', ['~> 1.0']
19
20
  spec.add_development_dependency 'rake', ['>= 10.0']
20
- spec.add_development_dependency 'embulk', ['>= 0.6.16', '< 1.0']
21
+ spec.add_development_dependency 'embulk', ['>= 0.8.6', '< 1.0']
21
22
  spec.add_development_dependency 'pry'
22
23
  spec.add_development_dependency 'test-unit'
23
24
  spec.add_development_dependency 'test-unit-rr'
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org/'
2
2
  gemspec :path => '../'
3
3
 
4
- gem "embulk", "~> 0.6.0"
4
+ gem "embulk", "~> 0.8.0"
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org/'
2
2
  gemspec :path => '../'
3
3
 
4
- gem "embulk", "0.7.0"
4
+ gem "embulk", "0.8.6"
@@ -1,4 +1,4 @@
1
1
  source 'https://rubygems.org/'
2
2
  gemspec :path => '../'
3
3
 
4
- gem "embulk", "> 0.6.16"
4
+ gem "embulk", ">= 0.8.6"
@@ -1,4 +1,5 @@
1
1
  require "tzinfo"
2
+ require "perfect_retry"
2
3
  require "embulk/input/mixpanel_api/client"
3
4
  require "range_generator"
4
5
  require "timezone_validator"
@@ -47,7 +48,7 @@ module Embulk
47
48
  end
48
49
 
49
50
  if fetch_unknown_columns
50
- columns << Column.new(nil, "unknown_columns", :string)
51
+ columns << Column.new(nil, "unknown_columns", :json)
51
52
  end
52
53
 
53
54
  resume(task, columns, 1, &control)
@@ -66,17 +67,19 @@ module Embulk
66
67
  end
67
68
 
68
69
  def self.guess(config)
70
+ giveup_when_mixpanel_is_down
71
+
69
72
  client = MixpanelApi::Client.new(config.param(:api_key, :string), config.param(:api_secret, :string))
70
73
 
71
74
  range = guess_range(config)
72
75
  Embulk.logger.info "Guessing schema using #{range.first}..#{range.last} records"
73
76
 
74
77
  params = export_params(config).merge(
75
- from_date: range.first,
76
- to_date: range.last,
78
+ "from_date" => range.first,
79
+ "to_date" => range.last,
77
80
  )
78
81
 
79
- columns = guess_from_records(client.export(params))
82
+ columns = guess_from_records(client.export_for_small_dataset(params))
80
83
  return {"columns" => columns}
81
84
  end
82
85
 
@@ -88,11 +91,23 @@ module Embulk
88
91
  @schema = task[:schema]
89
92
  @dates = task[:dates]
90
93
  @fetch_unknown_columns = task[:fetch_unknown_columns]
94
+ @retryer = PerfectRetry.new do |config|
95
+ config.limit = task[:retry_limit]
96
+ config.sleep = proc{|n| task[:retry_initial_wait_sec] * (2 * (n - 1)) }
97
+ config.dont_rescues = [Embulk::ConfigError]
98
+ config.rescues = [RuntimeError]
99
+ config.log_level = nil
100
+ config.logger = Embulk.logger
101
+ end
91
102
  end
92
103
 
93
104
  def run
105
+ self.class.giveup_when_mixpanel_is_down
106
+
94
107
  @dates.each_slice(SLICE_DAYS_COUNT) do |dates|
95
- Embulk.logger.info "Fetching data from #{dates.first} to #{dates.last} ..."
108
+ unless preview?
109
+ Embulk.logger.info "Fetching data from #{dates.first} to #{dates.last} ..."
110
+ end
96
111
 
97
112
  fetch(dates).each do |record|
98
113
  values = extract_values(record)
@@ -114,6 +129,12 @@ module Embulk
114
129
 
115
130
  private
116
131
 
132
+ def self.giveup_when_mixpanel_is_down
133
+ unless MixpanelApi::Client.mixpanel_available?
134
+ raise Embulk::DataError.new("Mixpanel service is down. Please retry later.")
135
+ end
136
+ end
137
+
117
138
  def extract_values(record)
118
139
  @schema.map do |column|
119
140
  extract_value(record, column["name"])
@@ -155,7 +176,14 @@ module Embulk
155
176
  "to_date" => to_date,
156
177
  )
157
178
  client = MixpanelApi::Client.new(@api_key, @api_secret)
158
- client.export_with_retry(params, task[:retry_initial_wait_sec], task[:retry_limit])
179
+
180
+ @retryer.with_retry do
181
+ if preview?
182
+ client.export_for_small_dataset(params)
183
+ else
184
+ client.export(params)
185
+ end
186
+ end
159
187
  end
160
188
 
161
189
  def adjust_timezone(epoch)
@@ -204,14 +232,16 @@ module Embulk
204
232
  sample_props = records.first(GUESS_RECORDS_COUNT).map{|r| r["properties"]}
205
233
  schema = Guess::SchemaGuess.from_hash_records(sample_props)
206
234
  columns = schema.map do |col|
235
+ next if col.name == "time"
207
236
  result = {
208
237
  name: col.name,
209
238
  type: col.type,
210
239
  }
211
240
  result[:format] = col.format if col.format
212
241
  result
213
- end
242
+ end.compact
214
243
  columns.unshift(name: NOT_PROPERTY_COLUMN, type: :string)
244
+ columns.unshift(name: "time", type: :long)
215
245
  end
216
246
  end
217
247
 
@@ -9,23 +9,55 @@ module Embulk
9
9
  class Client
10
10
  ENDPOINT_EXPORT = "https://data.mixpanel.com/api/2.0/export/".freeze
11
11
  TIMEOUT_SECONDS = 3600
12
+ PING_TIMEOUT_SECONDS = 3
13
+ PING_RETRY_LIMIT = 3
14
+ PING_RETRY_WAIT = 2
15
+
16
+ def self.mixpanel_available?
17
+ retryer = PerfectRetry.new do |config|
18
+ config.limit = PING_RETRY_LIMIT
19
+ config.sleep = PING_RETRY_WAIT
20
+ config.logger = Embulk.logger
21
+ config.log_level = nil
22
+ end
23
+
24
+ begin
25
+ retryer.with_retry do
26
+ client = HTTPClient.new
27
+ client.connect_timeout = PING_TIMEOUT_SECONDS
28
+ client.get("https://data.mixpanel.com")
29
+ end
30
+ true
31
+ rescue PerfectRetry::TooManyRetry
32
+ false
33
+ end
34
+ end
12
35
 
13
36
  def initialize(api_key, api_secret)
14
37
  @api_key = api_key
15
38
  @api_secret = api_secret
16
39
  end
17
40
 
18
- def export_with_retry(params = {}, retry_initial_wait_sec, retry_limit)
19
- body = with_retry(retry_initial_wait_sec, retry_limit) do
20
- request(params)
21
- end
22
-
41
+ def export(params = {})
42
+ body = request(params)
23
43
  response_to_enum(body)
24
44
  end
25
45
 
26
- def export(params = {})
46
+ def export_for_small_dataset(params = {}, times = 0)
47
+ days = (1 * (10 ** times))
48
+ to_date = Date.parse(params["from_date"].to_s) + days
49
+ params["to_date"] = to_date.strftime("%Y-%m-%d")
50
+
27
51
  body = request(params)
28
- response_to_enum(body)
52
+ result = response_to_enum(body)
53
+ if result.to_a.length.zero?
54
+ if times >= 5
55
+ raise ConfigError.new "#{params["from_date"]} + #{days} days has no record. too old date?"
56
+ end
57
+ export_for_small_dataset(params, times + 1)
58
+ else
59
+ result
60
+ end
29
61
  end
30
62
 
31
63
  private
@@ -56,29 +88,9 @@ module Embulk
56
88
  response.body
57
89
  end
58
90
 
59
- def with_retry(initial_wait, retry_limit, &block)
60
- retry_count = 0
61
- wait_sec = initial_wait
62
- begin
63
- yield
64
- rescue Embulk::ConfigError => e # TODO: rescue Embulk::DataError for Embulk 0.7+
65
- # Don't retry
66
- raise e
67
- rescue => e
68
- if retry_limit <= retry_count
69
- Embulk.logger.error "'#{e}(#{e.class})' error occured and reached retry limit (#{retry_limit} times)"
70
- raise e
71
- end
72
- retry_count += 1
73
- Embulk.logger.warn "Retrying after #{wait_sec} seconds [#{retry_count}/#{retry_limit}] '#{e}(#{e.class})' error occured"
74
- sleep wait_sec
75
- wait_sec *= 2
76
- retry
77
- end
78
- end
79
-
80
91
  def signature(params)
81
92
  # https://mixpanel.com/docs/api-documentation/data-export-api#auth-implementation
93
+ params.delete(:sig)
82
94
  sorted_keys = params.keys.map(&:to_s).sort
83
95
  signature = sorted_keys.inject("") do |sig, key|
84
96
  value = params[key] || params[key.to_sym]
@@ -89,69 +89,30 @@ module Embulk
89
89
  end
90
90
  end
91
91
 
92
- class ExportRetryTest < self
93
- def setup
94
- @httpclient = HTTPClient.new
95
- @client = Client.new(API_KEY, API_SECRET)
96
- @retry_initial_wait_sec = 1
97
- @retry_limit = 3
98
- stub_client
99
- end
100
-
101
- def test_retry_with_500
102
- stub_response(failure_response(500))
103
-
104
- @retry_limit.times do |n|
105
- mock(@client).sleep(@retry_initial_wait_sec * (2**n))
106
- end
107
- mock(Embulk.logger).warn(/retry/i).times(@retry_limit)
108
- mock(Embulk.logger).error(/retry/i).once
92
+ class ExportSmallDataset < self
93
+ def test_to_date_after_1_day
94
+ to = (Date.parse(params["from_date"]) + 1).to_s
95
+ mock(@client).request(params.merge("to_date" => to)) { jsonl_dummy_responses }
109
96
 
110
- assert_raise do
111
- @client.export_with_retry(params, @retry_initial_wait_sec, @retry_limit)
112
- end
97
+ @client.export_for_small_dataset(params)
113
98
  end
114
99
 
115
- def test_retry_with_timeout
116
- @httpclient.connect_timeout = 0.000000000000000000001
117
-
118
- @retry_limit.times do |n|
119
- mock(@client).sleep(@retry_initial_wait_sec * (2**n))
120
- end
121
- mock(Embulk.logger).warn(/retry/i).times(@retry_limit)
122
- mock(Embulk.logger).error(/retry/i).once
100
+ def test_to_date_after_1_day_after_10_days_if_empty
101
+ to1 = (Date.parse(params["from_date"]) + 1).to_s
102
+ to2 = (Date.parse(params["from_date"]) + 10).to_s
103
+ mock(@client).request(params.merge("to_date" => to1)) { "" }
104
+ mock(@client).request(params.merge("to_date" => to2)) { jsonl_dummy_responses }
123
105
 
124
- assert_raise(HTTPClient::TimeoutError) do
125
- @client.export_with_retry(params, @retry_initial_wait_sec, @retry_limit)
126
- end
106
+ @client.export_for_small_dataset(params)
127
107
  end
128
108
 
129
- def test_not_retry_with_401
130
- @httpclient.test_loopback_http_response << "HTTP/1.1 401\r\n\r\n"
131
- mock(Embulk.logger).warn(/retry/i).never
132
- mock(Embulk.logger).error(/retry/i).never
109
+ def test_config_error_when_too_long_empty_dates
110
+ stub(@client).request(anything) { "" }
133
111
 
134
112
  assert_raise(Embulk::ConfigError) do
135
- @client.export_with_retry(params, 0, 1).each do |record|
136
- record
137
- end
113
+ @client.export_for_small_dataset(params)
138
114
  end
139
115
  end
140
-
141
- def test_not_retry_with_invalid_json
142
- omit "Embulk 0.6 or earlier has no DataError (enable to uncomment below code)"
143
-
144
- # @httpclient.test_loopback_http_response << "HTTP/1.1 200\r\n\r\ninvalid json"
145
- # mock(Embulk.logger).warn(/retry/i).never
146
- # mock(Embulk.logger).error(/retry/i).never
147
-
148
- # assert_raise(Embulk::DataError) do
149
- # @client.export_with_retry(params, 0, 1).each do |record|
150
- # # DataError will raised in each block
151
- # record
152
- # end
153
- # end
154
- end
155
116
  end
156
117
 
157
118
  private
@@ -176,10 +137,10 @@ module Embulk
176
137
 
177
138
  def params
178
139
  {
179
- api_key: API_KEY,
180
- api_secret: API_SECRET,
181
- from_date: "2015-01-01",
182
- to_date: "2015-03-02",
140
+ "api_key" => API_KEY,
141
+ "api_secret" => API_SECRET,
142
+ "from_date" => "2015-01-01",
143
+ "to_date" => "2015-03-02",
183
144
  }
184
145
  end
185
146
 
@@ -24,6 +24,7 @@ module Embulk
24
24
  def setup
25
25
  setup_client
26
26
  setup_logger
27
+ stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { true }
27
28
  end
28
29
 
29
30
  def setup_client
@@ -53,6 +54,7 @@ module Embulk
53
54
  def setup
54
55
  # Do nothing from parent
55
56
  mute_warn
57
+ stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { true }
56
58
  end
57
59
 
58
60
  def test_from_date_old_date
@@ -112,11 +114,33 @@ module Embulk
112
114
  Mixpanel.guess(embulk_config(config))
113
115
  end
114
116
 
117
+ def test_json_type
118
+ sample_records = records.map do |r|
119
+ r.merge("properties" => {"array" => [1,2], "hash" => {foo: "FOO"}})
120
+ end
121
+ actual = Mixpanel.guess_from_records(sample_records)
122
+ assert actual.include?(name: "array", type: :json)
123
+ assert actual.include?(name: "hash", type: :json)
124
+ end
125
+
126
+ def test_mixpanel_is_down
127
+ stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { false }
128
+ config = {
129
+ type: "mixpanel",
130
+ api_key: API_KEY,
131
+ api_secret: API_SECRET,
132
+ }
133
+
134
+ assert_raise(Embulk::DataError) do
135
+ Mixpanel.guess(embulk_config(config))
136
+ end
137
+ end
138
+
115
139
  private
116
140
 
117
141
  def stub_export_all
118
142
  any_instance_of(MixpanelApi::Client) do |klass|
119
- stub(klass).export(anything) { records }
143
+ stub(klass).export_for_small_dataset(anything) { records }
120
144
  end
121
145
  end
122
146
 
@@ -131,9 +155,9 @@ module Embulk
131
155
  def expected
132
156
  {
133
157
  "columns" => [
158
+ {name: "time", type: :long},
134
159
  {name: "event", type: :string},
135
160
  {name: "foo", type: :string},
136
- {name: "time", type: :long},
137
161
  {name: "int", type: :long},
138
162
  ]
139
163
  }
@@ -364,6 +388,87 @@ module Embulk
364
388
  assert_equal(expected, actual)
365
389
  end
366
390
 
391
+ sub_test_case "retry" do
392
+ def setup
393
+ @page_builder = Object.new
394
+ @plugin = Mixpanel.new(task, nil, nil, @page_builder)
395
+ @plugin.init
396
+ @httpclient = HTTPClient.new
397
+ stub(HTTPClient).new { @httpclient }
398
+ stub(@page_builder).add {}
399
+ stub(@page_builder).finish {}
400
+ stub(Embulk.logger).warn {}
401
+ stub(Embulk.logger).info {}
402
+ stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { true }
403
+ end
404
+
405
+ test "200" do
406
+ stub_response(200)
407
+ mock(Embulk.logger).warn(/Retrying/).never
408
+ mock(@page_builder).finish
409
+ @plugin.run
410
+ end
411
+
412
+ test "400" do
413
+ stub_response(400)
414
+ mock(Embulk.logger).warn(/Retrying/).never
415
+ assert_raise(Embulk::ConfigError) do
416
+ @plugin.run
417
+ end
418
+ end
419
+
420
+ test "401" do
421
+ stub_response(401)
422
+ mock(Embulk.logger).warn(/Retrying/).never
423
+ assert_raise(Embulk::ConfigError) do
424
+ @plugin.run
425
+ end
426
+ end
427
+
428
+ test "500" do
429
+ stub_response(500)
430
+ mock(Embulk.logger).warn(/Retrying/).times(task[:retry_limit])
431
+ assert_raise(PerfectRetry::TooManyRetry) do
432
+ @plugin.run
433
+ end
434
+ end
435
+
436
+ test "timeout" do
437
+ stub(@httpclient).get { raise HTTPClient::TimeoutError, "timeout" }
438
+ mock(Embulk.logger).warn(/Retrying/).times(task[:retry_limit])
439
+
440
+ assert_raise(PerfectRetry::TooManyRetry) do
441
+ @plugin.run
442
+ end
443
+ end
444
+
445
+ test "Mixpanel is down" do
446
+ stub(Embulk::Input::MixpanelApi::Client).mixpanel_available? { false }
447
+
448
+ assert_raise(Embulk::DataError) do
449
+ @plugin.run
450
+ end
451
+ end
452
+
453
+ def stub_response(code)
454
+ stub(@httpclient.test_loopback_http_response).shift { "HTTP/1.1 #{code}\r\n\r\n" }
455
+ end
456
+
457
+ def task
458
+ {
459
+ api_key: API_KEY,
460
+ api_secret: API_SECRET,
461
+ timezone: TIMEZONE,
462
+ schema: schema,
463
+ dates: DATES.to_a.map(&:to_s),
464
+ params: Mixpanel.export_params(embulk_config),
465
+ fetch_unknown_columns: false,
466
+ retry_initial_wait_sec: 0,
467
+ retry_limit: 3,
468
+ }
469
+ end
470
+ end
471
+
367
472
  class RunTest < self
368
473
  def setup_client
369
474
 
@@ -379,14 +484,6 @@ module Embulk
379
484
  @plugin = Mixpanel.new(task, nil, nil, @page_builder)
380
485
  end
381
486
 
382
- def test_preview_check
383
- mock(@plugin).preview? { true }
384
- stub(@page_builder).add(anything)
385
- stub(@page_builder).finish
386
-
387
- @plugin.run
388
- end
389
-
390
487
  def test_preview
391
488
  stub(@plugin).preview? { true }
392
489
  mock(@page_builder).add(anything).times(records.length)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: embulk-input-mixpanel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.4
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - yoshihara
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-11-02 00:00:00.000000000 Z
12
+ date: 2016-03-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  requirement: !ruby/object:Gem::Requirement
@@ -39,6 +39,20 @@ dependencies:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.3'
48
+ name: perfect_retry
49
+ prerelease: false
50
+ type: :runtime
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '0.3'
42
56
  - !ruby/object:Gem::Dependency
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
@@ -72,7 +86,7 @@ dependencies:
72
86
  requirements:
73
87
  - - ">="
74
88
  - !ruby/object:Gem::Version
75
- version: 0.6.16
89
+ version: 0.8.6
76
90
  - - "<"
77
91
  - !ruby/object:Gem::Version
78
92
  version: '1.0'
@@ -83,7 +97,7 @@ dependencies:
83
97
  requirements:
84
98
  - - ">="
85
99
  - !ruby/object:Gem::Version
86
- version: 0.6.16
100
+ version: 0.8.6
87
101
  - - "<"
88
102
  - !ruby/object:Gem::Version
89
103
  version: '1.0'
@@ -175,26 +189,8 @@ files:
175
189
  - README.md
176
190
  - Rakefile
177
191
  - embulk-input-mixpanel.gemspec
178
- - gemfiles/embulk-0.6.0-latest
179
- - gemfiles/embulk-0.6.16
180
- - gemfiles/embulk-0.6.17
181
- - gemfiles/embulk-0.6.18
182
- - gemfiles/embulk-0.6.19
183
- - gemfiles/embulk-0.6.20
184
- - gemfiles/embulk-0.6.21
185
- - gemfiles/embulk-0.6.22
186
- - gemfiles/embulk-0.6.23
187
- - gemfiles/embulk-0.6.24
188
- - gemfiles/embulk-0.6.25
189
- - gemfiles/embulk-0.6.26
190
- - gemfiles/embulk-0.6.27
191
- - gemfiles/embulk-0.7.0
192
- - gemfiles/embulk-0.7.0-latest
193
- - gemfiles/embulk-0.7.1
194
- - gemfiles/embulk-0.7.2
195
- - gemfiles/embulk-0.7.3
196
- - gemfiles/embulk-0.7.4
197
- - gemfiles/embulk-0.7.5
192
+ - gemfiles/embulk-0.8.0-latest
193
+ - gemfiles/embulk-0.8.6
198
194
  - gemfiles/embulk-latest
199
195
  - gemfiles/template.erb
200
196
  - lib/embulk/input/mixpanel.rb
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.16"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.17"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.18"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.19"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.20"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.21"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.22"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.23"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.24"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.25"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.26"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.6.27"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "~> 0.7.0"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.7.1"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.7.2"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.7.3"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.7.4"
@@ -1,4 +0,0 @@
1
- source 'https://rubygems.org/'
2
- gemspec :path => '../'
3
-
4
- gem "embulk", "0.7.5"