active_sanction 1.0.1 → 1.1.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 +4 -4
- data/CHANGELOG.md +54 -1
- data/docs/api_stability.md +47 -2
- data/lib/active_sanction/client.rb +11 -2
- data/lib/active_sanction/configuration.rb +39 -0
- data/lib/active_sanction/fetcher.rb +38 -12
- data/lib/active_sanction/index.rb +61 -0
- data/lib/active_sanction/instrumentation/event.rb +122 -0
- data/lib/active_sanction/instrumentation/notifications.rb +122 -0
- data/lib/active_sanction/instrumentation.rb +245 -0
- data/lib/active_sanction/matcher.rb +82 -17
- data/lib/active_sanction/sources/base.rb +48 -6
- data/lib/active_sanction/sync.rb +54 -6
- data/lib/active_sanction/version.rb +1 -1
- data/lib/active_sanction.rb +1 -0
- metadata +4 -1
data/lib/active_sanction/sync.rb
CHANGED
|
@@ -5,6 +5,7 @@ require "sorbet-runtime"
|
|
|
5
5
|
|
|
6
6
|
require "uri"
|
|
7
7
|
require "active_sanction/error"
|
|
8
|
+
require "active_sanction/instrumentation"
|
|
8
9
|
require "active_sanction/sources"
|
|
9
10
|
require "active_sanction/storage"
|
|
10
11
|
require "active_sanction/sync/result"
|
|
@@ -149,6 +150,17 @@ module ActiveSanction
|
|
|
149
150
|
sig { returns(T.untyped) }
|
|
150
151
|
attr_reader :logger
|
|
151
152
|
|
|
153
|
+
# Where the `:sync` and `:store` events go, or nil for nothing listening.
|
|
154
|
+
#
|
|
155
|
+
# The `:fetch` and `:parse` events of the sources this run covers do not
|
|
156
|
+
# come from here: an adapter is constructed by the run and reads the
|
|
157
|
+
# configuration, exactly as it does for its logger and its User-Agent. So
|
|
158
|
+
# a host that instruments through `ActiveSanction.configure` sees all six
|
|
159
|
+
# events, and one that hands a run its own instrumenter sees the two this
|
|
160
|
+
# class emits. See Instrumentation.
|
|
161
|
+
sig { returns(T.untyped) }
|
|
162
|
+
attr_reader :instrumenter
|
|
163
|
+
|
|
152
164
|
sig { params(options: T.untyped, block: T.untyped).returns(Report) }
|
|
153
165
|
def self.call(**options, &block) = T.unsafe(self).new(**options).call(&block)
|
|
154
166
|
|
|
@@ -157,9 +169,10 @@ module ActiveSanction
|
|
|
157
169
|
# raises here, before the first list is downloaded, rather than after.
|
|
158
170
|
sig do
|
|
159
171
|
params(sources: T.untyped, store: T.untyped, force: T::Boolean, concurrency: T.untyped,
|
|
160
|
-
logger: T.untyped).void
|
|
172
|
+
logger: T.untyped, instrumenter: T.untyped).void
|
|
161
173
|
end
|
|
162
|
-
def initialize(sources: nil, store: nil, force: false, concurrency: nil, logger: ActiveSanction.config.logger
|
|
174
|
+
def initialize(sources: nil, store: nil, force: false, concurrency: nil, logger: ActiveSanction.config.logger,
|
|
175
|
+
instrumenter: ActiveSanction.config.instrumenter)
|
|
163
176
|
@sources = T.let(resolve(sources), T::Array[T.untyped])
|
|
164
177
|
@keys = T.let(@sources.map { |source| Sources::Definition.key!(source.key) }, T::Array[Symbol])
|
|
165
178
|
@store = T.let(store || ActiveSanction.storage, T.untyped)
|
|
@@ -168,6 +181,7 @@ module ActiveSanction
|
|
|
168
181
|
Configuration.sync_concurrency!(concurrency || ActiveSanction.config.sync_concurrency), Integer
|
|
169
182
|
)
|
|
170
183
|
@logger = T.let(logger, T.untyped)
|
|
184
|
+
@instrumenter = T.let(instrumenter, T.untyped)
|
|
171
185
|
@lock = T.let(Mutex.new, Mutex)
|
|
172
186
|
# The settings this run was started under, so a worker thread reads them
|
|
173
187
|
# rather than the default client's. A configuration is fiber-local and a
|
|
@@ -195,9 +209,17 @@ module ActiveSanction
|
|
|
195
209
|
started_at = Time.now.utc
|
|
196
210
|
began = monotonic
|
|
197
211
|
log_start
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
212
|
+
# The run's own duration is the Report's, taken from the same clock
|
|
213
|
+
# reading, so an event and the report a caller is holding never disagree
|
|
214
|
+
# about how long a run took.
|
|
215
|
+
report = Instrumentation.instrument(instrumenter, :sync,
|
|
216
|
+
{ sources: keys, forced: force, concurrency: concurrency }) do |event|
|
|
217
|
+
work = keys.each_with_index.map { |key, at| [at, key, sources.fetch(at)] }
|
|
218
|
+
results = run(work, &block).sort_by(&:first).map(&:last)
|
|
219
|
+
finished = Report.new(results: results, started_at: started_at, duration: elapsed(began))
|
|
220
|
+
summarize(event, finished)
|
|
221
|
+
finished
|
|
222
|
+
end
|
|
201
223
|
log_finish(report)
|
|
202
224
|
report
|
|
203
225
|
end
|
|
@@ -285,13 +307,39 @@ module ActiveSanction
|
|
|
285
307
|
snapshot = adapter.sync(force: force || previous.nil?)
|
|
286
308
|
return complete(key, :unchanged, previous, started) if unchanged?(previous, snapshot)
|
|
287
309
|
|
|
288
|
-
|
|
310
|
+
write(key, snapshot)
|
|
289
311
|
complete(key, :updated, Storage::Meta.from_snapshot(snapshot), started)
|
|
290
312
|
rescue StandardError => e
|
|
291
313
|
complete(key, :failed, previous, started, stamp(key, e))
|
|
292
314
|
end
|
|
293
315
|
end
|
|
294
316
|
|
|
317
|
+
# Writes one list, and says what it cost. Separate from the rest of
|
|
318
|
+
# #sync_source so the `:store` event times the write and nothing else --
|
|
319
|
+
# a store that takes eleven seconds to persist 19,321 entities is a
|
|
320
|
+
# different operational problem from a publisher that takes eleven seconds
|
|
321
|
+
# to serve them, and a timing that covered both could not tell a host
|
|
322
|
+
# which one it had.
|
|
323
|
+
sig { params(key: Symbol, snapshot: T.untyped).void }
|
|
324
|
+
def write(key, snapshot)
|
|
325
|
+
fields = { source: key, snapshot_id: snapshot.checksum, entities: snapshot.record_count,
|
|
326
|
+
store: store.class.name }
|
|
327
|
+
Instrumentation.instrument(instrumenter, :store, fields) { store.write_snapshot(snapshot) }
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
# What a run did, as counts rather than as the Report itself: a subscriber
|
|
331
|
+
# forwarding an event to a metrics backend wants numbers, and one that
|
|
332
|
+
# wants the whole report already has it as the return value of the call
|
|
333
|
+
# that emitted this.
|
|
334
|
+
sig { params(event: T.untyped, report: Report).void }
|
|
335
|
+
def summarize(event, report)
|
|
336
|
+
event[:outcomes] = report.results.to_h { |result| [result.source, result.status] }
|
|
337
|
+
event[:updated] = report.updated.size
|
|
338
|
+
event[:unchanged] = report.unchanged.size
|
|
339
|
+
event[:failed] = report.failed.size
|
|
340
|
+
event[:records] = report.record_count
|
|
341
|
+
end
|
|
342
|
+
|
|
295
343
|
# A failure captured for a source names that source, even when it was
|
|
296
344
|
# raised somewhere that could not know -- a store that will not open, an
|
|
297
345
|
# adapter constructor. Only ever fills a blank; see Error#in_source.
|
|
@@ -6,7 +6,7 @@ module ActiveSanction
|
|
|
6
6
|
# new source adapter, a storage fix or a documentation release -- none of
|
|
7
7
|
# which change what a name scores. MATCHER_VERSION, below, is the one that
|
|
8
8
|
# answers that question.
|
|
9
|
-
VERSION = "1.0
|
|
9
|
+
VERSION = "1.1.0"
|
|
10
10
|
|
|
11
11
|
# Which matching pipeline scored a decision, stamped onto every MatchResult
|
|
12
12
|
# and bumped whenever a change to the normalizer, the index, the similarity
|
data/lib/active_sanction.rb
CHANGED
|
@@ -6,6 +6,7 @@ require "sorbet-runtime"
|
|
|
6
6
|
require "active_sanction/error"
|
|
7
7
|
require "active_sanction/version"
|
|
8
8
|
require "active_sanction/deprecation"
|
|
9
|
+
require "active_sanction/instrumentation"
|
|
9
10
|
require "active_sanction/configuration"
|
|
10
11
|
require "active_sanction/name"
|
|
11
12
|
require "active_sanction/address"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: active_sanction
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Marshall Shen
|
|
@@ -102,6 +102,9 @@ files:
|
|
|
102
102
|
- lib/active_sanction/index/candidate.rb
|
|
103
103
|
- lib/active_sanction/index/entry.rb
|
|
104
104
|
- lib/active_sanction/index/features.rb
|
|
105
|
+
- lib/active_sanction/instrumentation.rb
|
|
106
|
+
- lib/active_sanction/instrumentation/event.rb
|
|
107
|
+
- lib/active_sanction/instrumentation/notifications.rb
|
|
105
108
|
- lib/active_sanction/match_result.rb
|
|
106
109
|
- lib/active_sanction/matcher.rb
|
|
107
110
|
- lib/active_sanction/name.rb
|