embulk-input-mixpanel 0.3.4 → 0.4.0

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 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"