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 +4 -4
- data/lib/search_engine/base/index_maintenance/lifecycle.rb +19 -4
- data/lib/search_engine/base/index_maintenance.rb +38 -2
- data/lib/search_engine/config.rb +4 -0
- data/lib/search_engine/errors.rb +7 -0
- data/lib/search_engine/interruptible_pool.rb +14 -5
- data/lib/search_engine/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ed93c9aa019a0f633ad5c7cc47ec08ea303f5e51491cfc3130e677271b000e1f
|
|
4
|
+
data.tar.gz: 6446746c790fc6b1c0fa084a5ba9bebd555f5e298738f7b8800fd2717257659f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
146
|
+
__se_finish_indexation_step(step, result)
|
|
143
147
|
end
|
|
144
148
|
|
|
145
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
data/lib/search_engine/config.rb
CHANGED
|
@@ -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
|
data/lib/search_engine/errors.rb
CHANGED
|
@@ -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 [
|
|
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
|
-
|
|
26
|
-
pool.wait_for_termination(
|
|
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
|