search-engine-for-typesense 30.1.6.7 → 30.1.6.8

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
  SHA256:
3
- metadata.gz: 17890bf666142ee9e0cd293c1ea5fc13dcf4089c50bb1e721708b7c9972f5e15
4
- data.tar.gz: 84866d6a6d238f29e3eda054f445a88780c98ab9eff75673f6930c044a336a02
3
+ metadata.gz: ed93c9aa019a0f633ad5c7cc47ec08ea303f5e51491cfc3130e677271b000e1f
4
+ data.tar.gz: 6446746c790fc6b1c0fa084a5ba9bebd555f5e298738f7b8800fd2717257659f
5
5
  SHA512:
6
- metadata.gz: 01aa100a2d5a612c56a85cd6f4e02d232476911ceea18cd7f024904a477874ab492d675d0ad9624212a4891e15e0a17371cc2c9314b38bb2bcb332e36212faba
7
- data.tar.gz: fb6ba4067d04afdb1cc0bc2236c0040832fc6632d8cd0320080c77b7b9b6fa8d9b8ce6dca99ab725757ca4124107f67570ad2281e03404193c746258becef127
6
+ metadata.gz: 99aa8f0be6a9b43d0de16e402fe22cb60614861c73f26f122f0c155e3d35de33053a7822170c440bb407bcac73d7a5ba42f57ba0eda825a49fa210e369ba7ea3
7
+ data.tar.gz: a6526cc8752cdc5a8f61c03a55519e5cf18da1ac538e1028a881b8e5a2d147d5c44cb26b3f4fbbb46907589985564baa895166320b3c1eee230d6557f1890976
@@ -133,22 +133,37 @@ module SearchEngine
133
133
  result = nil
134
134
  step = SearchEngine::Logging::StepLine.new('Indexing')
135
135
  if applied && indexed_inside_apply
136
- step.skip('performed during schema apply')
137
136
  result = indexed_inside_apply if indexed_inside_apply.is_a?(Hash)
137
+ if __se_result_status(result) == :ok
138
+ step.skip('performed during schema apply')
139
+ else
140
+ __se_finish_indexation_step(step, result)
141
+ end
138
142
  else
139
143
  step.update('indexing')
140
144
  step.yield_line!
141
145
  result = __se_index_partitions!(into: nil)
142
- step.finish('done')
146
+ __se_finish_indexation_step(step, result)
143
147
  end
144
148
 
145
- cascade_ok = result.is_a?(Hash) ? result[:status] == :ok : false
146
- __se_cascade_after_indexation!(context: :full) if cascade_ok
149
+ __se_cascade_after_indexation!(context: :full) if __se_result_status(result) == :ok
147
150
  result
148
151
  ensure
149
152
  step&.close
150
153
  end
151
154
 
155
+ def __se_result_status(result)
156
+ result.is_a?(Hash) ? result[:status] : :ok
157
+ end
158
+
159
+ def __se_finish_indexation_step(step, result)
160
+ case __se_result_status(result)
161
+ when :ok then step.finish('done')
162
+ when :partial then step.finish_warn('partial')
163
+ else step.finish_warn('failed')
164
+ end
165
+ end
166
+
152
167
  def __se_full_retention(applied, logical, client)
153
168
  step = SearchEngine::Logging::StepLine.new('Retention')
154
169
  if applied
@@ -373,7 +373,15 @@ module SearchEngine
373
373
  warn("\n Interrupted \u2014 stopping parallel partition workers\u2026")
374
374
  end
375
375
 
376
- SearchEngine::InterruptiblePool.run(pool, on_interrupt: on_interrupt) do
376
+ pool_timeout = begin
377
+ SearchEngine.config.indexer.pool_timeout
378
+ rescue StandardError
379
+ nil
380
+ end
381
+
382
+ pool_status = SearchEngine::InterruptiblePool.run(
383
+ pool, on_interrupt: on_interrupt, timeout: pool_timeout
384
+ ) do
377
385
  parts.each_with_index do |part, idx|
378
386
  break if cancelled.true?
379
387
 
@@ -400,6 +408,8 @@ module SearchEngine
400
408
  end
401
409
  end
402
410
 
411
+ __se_flag_incomplete_slots!(renderer, parts, partition_errors, mtx, pool_timeout) if pool_status == :timed_out
412
+
403
413
  begin
404
414
  renderer.stop
405
415
  rescue StandardError
@@ -442,7 +452,33 @@ module SearchEngine
442
452
  nil
443
453
  end
444
454
 
445
- private :__se_per_partition_docs_estimates, :__se_heuristic_docs_estimate
455
+ # Flag renderer slots that are still pending/in-progress after the pool
456
+ # timed out. Marks each as errored and appends to partition_errors so the
457
+ # caller raises and reports failure.
458
+ #
459
+ # @param renderer [SearchEngine::Logging::LiveRenderer]
460
+ # @param parts [Array] partition keys
461
+ # @param partition_errors [Array<StandardError>]
462
+ # @param mtx [Mutex]
463
+ # @param pool_timeout [Integer, nil] resolved timeout (seconds) from caller
464
+ # @return [void]
465
+ def __se_flag_incomplete_slots!(renderer, parts, partition_errors, mtx, pool_timeout)
466
+ effective_timeout = pool_timeout || SearchEngine::InterruptiblePool::GRACEFUL_TIMEOUT
467
+
468
+ parts.each_index do |idx|
469
+ slot = renderer[idx]
470
+ next if %i[done error].include?(slot.state)
471
+
472
+ error = SearchEngine::Errors::PartitionTimeout.new(
473
+ "partition #{parts[idx].inspect} was not processed — " \
474
+ "parallel pool timed out after #{effective_timeout}s"
475
+ )
476
+ slot.finish_error(error)
477
+ mtx.synchronize { partition_errors << error }
478
+ end
479
+ end
480
+
481
+ private :__se_per_partition_docs_estimates, :__se_heuristic_docs_estimate, :__se_flag_incomplete_slots!
446
482
  end
447
483
 
448
484
  class_methods do
@@ -105,6 +105,9 @@ module SearchEngine
105
105
  attr_accessor :queue_name
106
106
  # @return [Boolean] whether to run model.count for progress bar estimates (default true)
107
107
  attr_accessor :estimate_progress
108
+ # @return [Integer, nil] graceful-shutdown timeout (seconds) for the parallel
109
+ # partition pool. When nil, falls back to InterruptiblePool::GRACEFUL_TIMEOUT (3600s).
110
+ attr_accessor :pool_timeout
108
111
 
109
112
  def initialize
110
113
  @batch_size = 2000
@@ -114,6 +117,7 @@ module SearchEngine
114
117
  @dispatch = active_job_available? ? :active_job : :inline
115
118
  @queue_name = 'search_index'
116
119
  @estimate_progress = true
120
+ @pool_timeout = nil
117
121
  end
118
122
 
119
123
  private
@@ -120,6 +120,13 @@ module SearchEngine
120
120
  # the underlying HTTP client used by the official Typesense gem.
121
121
  class Timeout < Error; end
122
122
 
123
+ # Raised when one or more partitions were not processed because the
124
+ # parallel pool's graceful-shutdown timeout was exceeded.
125
+ #
126
+ # The pool kills remaining queued/running tasks after the timeout,
127
+ # leaving those partitions unindexed.
128
+ class PartitionTimeout < Error; end
129
+
123
130
  # Raised for network-level connectivity issues prior to receiving a response.
124
131
  #
125
132
  # Examples: DNS resolution failures, refused TCP connections, TLS handshake
@@ -11,19 +11,28 @@ module SearchEngine
11
11
 
12
12
  # Execute a block that posts work to a thread pool, then wait for completion.
13
13
  #
14
- # Normal path: graceful shutdown → long wait.
14
+ # Normal path: graceful shutdown → long wait → :ok.
15
+ # Timeout: graceful wait expires → pool.kill → :timed_out.
15
16
  # Interrupt: on_interrupt callback → pool.kill → short wait → re-raise.
16
17
  # Other error: ensure kill → short wait.
17
18
  #
18
19
  # @param pool [Concurrent::FixedThreadPool]
19
20
  # @param on_interrupt [Proc, nil] callback invoked before killing the pool
21
+ # @param timeout [Integer, nil] override for graceful-shutdown timeout (seconds);
22
+ # defaults to {GRACEFUL_TIMEOUT} when nil
20
23
  # @yield block that posts work to the pool
21
- # @return [void]
22
- def self.run(pool, on_interrupt: nil)
24
+ # @return [Symbol] :ok on clean completion, :timed_out when the graceful timeout was exceeded
25
+ def self.run(pool, on_interrupt: nil, timeout: nil)
23
26
  yield
24
27
  pool.shutdown
25
- pool.wait_for_termination(GRACEFUL_TIMEOUT) || pool.kill
26
- pool.wait_for_termination(CLEANUP_TIMEOUT)
28
+ effective_timeout = timeout || GRACEFUL_TIMEOUT
29
+ completed = pool.wait_for_termination(effective_timeout)
30
+ unless completed
31
+ pool.kill
32
+ pool.wait_for_termination(CLEANUP_TIMEOUT)
33
+ return :timed_out
34
+ end
35
+ :ok
27
36
  rescue Interrupt
28
37
  on_interrupt&.call
29
38
  pool.kill
@@ -3,5 +3,5 @@
3
3
  module SearchEngine
4
4
  # Current gem version.
5
5
  # @return [String]
6
- VERSION = '30.1.6.7'
6
+ VERSION = '30.1.6.8'
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: search-engine-for-typesense
3
3
  version: !ruby/object:Gem::Version
4
- version: 30.1.6.7
4
+ version: 30.1.6.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nikita Shkoda