gooddata 2.3.1-java → 2.3.2-java

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.
@@ -33,6 +33,9 @@ module GoodData
33
33
 
34
34
  description 'Sync failed list'
35
35
  param :sync_failed_list, instance_of(Type::HashType), required: false
36
+
37
+ description 'Number Of Threads'
38
+ param :number_of_threads, instance_of(Type::StringType), required: false, default: '10'
36
39
  end
37
40
 
38
41
  RESULT_HEADER = %i[from to count status]
@@ -45,8 +48,9 @@ module GoodData
45
48
 
46
49
  client = params.gdc_gd_client
47
50
  development_client = params.development_client
51
+ number_of_threads = Integer(params.number_of_threads || '8')
48
52
 
49
- params.synchronize.peach do |info|
53
+ params.synchronize.peach(number_of_threads) do |info|
50
54
  from_project = info.from
51
55
  to_projects = info.to
52
56
 
@@ -60,7 +64,7 @@ module GoodData
60
64
  if dataset_mapping&.dig('datasetMappings', 'items').nil? || dataset_mapping['datasetMappings']['items'].empty?
61
65
  params.gdc_logger.info "Project: '#{from.title}', PID: '#{from.pid}' has no model mapping, skip synchronizing model mapping."
62
66
  else
63
- to_projects.peach do |to|
67
+ to_projects.peach(number_of_threads) do |to|
64
68
  pid = to[:pid]
65
69
  next if sync_failed_project(pid, params)
66
70
 
@@ -74,6 +74,9 @@ module GoodData
74
74
 
75
75
  description 'Makes the brick run without altering user filters'
76
76
  param :dry_run, instance_of(Type::StringType), required: false, default: false
77
+
78
+ description 'Number Of Threads'
79
+ param :number_of_threads, instance_of(Type::StringType), required: false, default: '10'
77
80
  end
78
81
 
79
82
  class << self
@@ -104,6 +107,7 @@ module GoodData
104
107
  symbolized_config = GoodData::Helpers.symbolize_keys(symbolized_config)
105
108
  symbolized_config[:labels] = symbolized_config[:labels].map { |l| GoodData::Helpers.symbolize_keys(l) }
106
109
  multiple_projects_column = params.multiple_projects_column
110
+ number_of_threads = Integer(params.number_of_threads || '10')
107
111
 
108
112
  mode = params.sync_mode
109
113
  unless MODES.include?(mode)
@@ -196,7 +200,7 @@ module GoodData
196
200
 
197
201
  unless run_params[:do_not_touch_filters_that_are_not_mentioned]
198
202
  to_be_deleted_clients = UserBricksHelper.non_working_clients(domain_clients, working_client_ids)
199
- to_be_deleted_clients.peach do |c|
203
+ to_be_deleted_clients.peach(number_of_threads) do |c|
200
204
  begin
201
205
  current_project = c.project
202
206
  users = users_by_project[c.client_id]
@@ -295,6 +295,10 @@ module GoodData
295
295
  end
296
296
 
297
297
  def perform(mode, params = {})
298
+ # Default setting for $pmap_default_thread_count = 20 in gooddata.rb file. We are going to decrease default
299
+ # number of threads count to 10 for LCM bricks only
300
+ $pmap_default_thread_count = 10 # rubocop:disable GlobalVars
301
+
298
302
  params = convert_params(params)
299
303
 
300
304
  GoodData.gd_logger.brick = mode
@@ -22,7 +22,15 @@ module GoodData
22
22
  'pt-PT' => 'Portuguese/Portugal',
23
23
  'fr-FR' => 'French',
24
24
  'de-DE' => 'German',
25
- 'ja-JP' => 'Japanese'
25
+ 'ja-JP' => 'Japanese',
26
+ 'it-IT' => 'Italian',
27
+ 'es-419' => 'Spanish/Latin America',
28
+ 'fr-CA' => 'French/Canada',
29
+ 'en-GB' => 'English/UK',
30
+ 'en-AU' => 'English/Australian',
31
+ 'fi-FI' => 'Finnish',
32
+ 'zh-Hant' => 'Traditional Chinese',
33
+ 'zh-HK' => 'Cantonese'
26
34
  }
27
35
 
28
36
  class << self
@@ -276,12 +284,16 @@ to new properties (email=#{user_data[:email]}, sso_provider=#{user_data[:sso_pro
276
284
  [{ type: :successful, :action => :user_changed_in_domain, user: updated_user }]
277
285
  end
278
286
  rescue RuntimeError => e
287
+ error_message = e.message
288
+ user.delete(:password)
279
289
  if !domain_user
280
- GoodData.logger.error("Failed to add user=#{user_login} to domain=#{default_domain_name}. Error: #{e.message}")
290
+ GoodData.logger.error("Failed to add user=#{user_login} to domain=#{default_domain_name}. Error: #{error_message}")
281
291
  else
282
- GoodData.logger.error("Failed to update user=#{user_login} in domain=#{default_domain_name}. Error: #{e.message}")
292
+ error_message = 'Invalid user data or update new password cannot be the same as old password' if error_message == '400 Bad Request'
293
+
294
+ GoodData.logger.error("Failed to update user=#{user_login} in domain=#{default_domain_name}. Error: #{error_message}")
283
295
  end
284
- [{ type: :failed, :user => user, message: e }]
296
+ [{ type: :failed, :user => user, message: error_message }]
285
297
  end
286
298
  end
287
299
  end
@@ -44,14 +44,31 @@ module GoodData
44
44
  # In the case filter a specific value, because the API /validElements only filter by partial match, we need to filter again at client side for exact match.
45
45
  # @return [Array] Results
46
46
  def get_valid_elements(*args)
47
+ results = {}
47
48
  if args && !args.empty? && args.first[:filter]
49
+ # Support paging in case filter by a specific value
48
50
  params = args.first
49
- params[:limit] = 100_000
50
- results, = valid_elements params
51
- results['validElements']['items'] = results['validElements']['items'].select do |i|
52
- i['element']['title'] == params[:filter]
51
+ all_valid_elements = []
52
+ offset = 0
53
+ paging_limit = 10_000
54
+
55
+ loop do
56
+ params[:offset] = offset
57
+ params[:limit] = paging_limit
58
+ results, = valid_elements params
59
+ all_valid_elements += results['validElements']['items'].select do |i|
60
+ i['element']['title'] == params[:filter]
61
+ end
62
+
63
+ if results['validElements']['items'].count < paging_limit
64
+ results['validElements']['items'] = all_valid_elements
65
+ break
66
+ else
67
+ offset += paging_limit
68
+ end
53
69
  end
54
70
  else
71
+ # This case will support paging by the method which call this method eg: values(...) method
55
72
  results, = valid_elements(*args)
56
73
  end
57
74
  results
@@ -1434,9 +1434,13 @@ module GoodData
1434
1434
  :crossDataCenterExport => '1'
1435
1435
  }
1436
1436
  }
1437
- result = client.post("#{md['maintenance']}/partialmdexport", export_payload)
1437
+ export_uri = "/gdc/md/#{pid}/maintenance/partialmdexport"
1438
+ GoodData.gd_logger.info("Project export action=objects_export, project_id=#{pid}, uri=#{export_uri}, export_status=start, export_objs=#{export_payload}") if GoodData.gd_logger
1439
+
1440
+ result = client.post(export_uri, export_payload)
1438
1441
  polling_url = result['partialMDArtifact']['status']['uri']
1439
1442
  token = result['partialMDArtifact']['token']
1443
+ GoodData.gd_logger.info("Project export action=objects_export, project_id=#{pid}, uri=#{polling_url}, export_status=polling") if GoodData.gd_logger
1440
1444
 
1441
1445
  polling_result = client.poll_on_response(polling_url, options) do |body|
1442
1446
  body['wTaskStatus'] && body['wTaskStatus']['status'] == 'RUNNING'
@@ -1445,6 +1449,9 @@ module GoodData
1445
1449
  messages = GoodData::Helpers.interpolate_error_messages(polling_result['wTaskStatus']['messages']).join(' ')
1446
1450
  fail ObjectsExportError, "Exporting objects failed with messages. #{messages}"
1447
1451
  end
1452
+
1453
+ GoodData.gd_logger.info("Project export action=objects_export, project_id=#{pid}, export_status=success") if GoodData.gd_logger
1454
+
1448
1455
  token
1449
1456
  end
1450
1457
 
@@ -1467,8 +1474,12 @@ module GoodData
1467
1474
  }
1468
1475
  }
1469
1476
 
1470
- result = client.post("#{md['maintenance']}/partialmdimport", import_payload)
1477
+ import_uri = "/gdc/md/#{pid}/maintenance/partialmdimport"
1478
+ GoodData.gd_logger.info("Project import action=objects_import, project_id=#{pid}, uri=#{import_uri}, import_status=start") if GoodData.gd_logger
1479
+
1480
+ result = client.post(import_uri, import_payload)
1471
1481
  polling_url = result['uri']
1482
+ GoodData.gd_logger.info("Project import action=objects_import, project_id=#{pid}, uri=#{polling_url}, import_status=polling") if GoodData.gd_logger
1472
1483
 
1473
1484
  polling_result = client.poll_on_response(polling_url, options) do |body|
1474
1485
  body['wTaskStatus'] && body['wTaskStatus']['status'] == 'RUNNING'
@@ -1478,6 +1489,9 @@ module GoodData
1478
1489
  messages = GoodData::Helpers.interpolate_error_messages(polling_result['wTaskStatus']['messages']).join(' ')
1479
1490
  fail ObjectsImportError, "Importing objects failed with messages. #{messages}"
1480
1491
  end
1492
+
1493
+ GoodData.gd_logger.info("Project import action=objects_import, project_id=#{pid}, uri=#{import_uri}, import_status=success") if GoodData.gd_logger
1494
+
1481
1495
  true
1482
1496
  end
1483
1497
 
@@ -180,7 +180,8 @@ module GoodData
180
180
 
181
181
  def self.create_lookups_cache(small_labels)
182
182
  small_labels.reduce({}) do |a, e|
183
- lookup = e.values(:limit => 1_000_000).reduce({}) do |a1, e1|
183
+ # The validElements API allow maximum paging with 10000 items
184
+ lookup = e.values(:limit => 10_000).reduce({}) do |a1, e1|
184
185
  a1[e1[:value]] = e1[:uri]
185
186
  a1
186
187
  end
@@ -513,7 +514,7 @@ module GoodData
513
514
  if to_create.empty?
514
515
  create_results = []
515
516
  else
516
- create_results = to_create.each_slice(100).flat_map do |batch|
517
+ create_results = to_create.each_slice(50).flat_map do |batch|
517
518
  batch.pmapcat do |related_uri, group|
518
519
  group.each(&:save)
519
520
  res = client.get("/gdc/md/#{project.pid}/userfilters?users=#{related_uri}")
@@ -65,7 +65,7 @@ module GoodData
65
65
  ]
66
66
 
67
67
  RETRY_TIME_INITIAL_VALUE = 1
68
- RETRY_TIME_COEFFICIENT = 1.5
68
+ RETRY_TIME_COEFFICIENT = 2
69
69
  RETRYABLE_ERRORS << Net::ReadTimeout if Net.const_defined?(:ReadTimeout)
70
70
 
71
71
  RETRYABLE_ERRORS << OpenSSL::SSL::SSLErrorWaitReadable if OpenSSL::SSL.const_defined?(:SSLErrorWaitReadable)
@@ -94,7 +94,7 @@ module GoodData
94
94
 
95
95
  # Retry block if exception thrown
96
96
  def retryable(options = {}, &_block)
97
- opts = { :tries => 12, :on => RETRYABLE_ERRORS }.merge(options)
97
+ opts = { :tries => 14, :on => RETRYABLE_ERRORS }.merge(options)
98
98
 
99
99
  retry_exception = opts[:on]
100
100
  retries = opts[:tries]
@@ -114,21 +114,27 @@ module GoodData
114
114
  if (retries -= 1) > 0
115
115
  retry
116
116
  else
117
- fail e
117
+ process_retry_error(e, retry_time)
118
118
  end
119
119
  rescue RestClient::TooManyRequests, RestClient::ServiceUnavailable, *retry_exception => e
120
- GoodData.logger.warn "#{e.message}, retrying in #{retry_time} seconds"
121
120
  sleep retry_time
122
- retry_time *= RETRY_TIME_COEFFICIENT
123
- # 10 requests with 1.5 coefficent should take ~ 3 mins to finish
121
+ # Total 10 retry requests with 1.5 coefficent should take ~ 2 mins to finish
124
122
  if (retries -= 1) > 0
123
+ retry_time *= RETRY_TIME_COEFFICIENT
125
124
  retry
126
125
  else
127
- fail e
126
+ process_retry_error(e, retry_time)
128
127
  end
129
128
  end
130
129
  yield
131
130
  end
131
+
132
+ def process_retry_error(e, retry_time)
133
+ error_message = "#{e.message}, retrying in #{retry_time} seconds"
134
+ GoodData.logger.warn error_message
135
+ GoodData.gd_logger.warn error_message
136
+ fail e
137
+ end
132
138
  end
133
139
 
134
140
  attr_reader :request_params