fair_champion_harvester 0.1.16 → 0.1.17

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: ebd706f0e7aea904a19364640429bdec400a208ce4503f363f7d6bc8924351b7
4
- data.tar.gz: f7d1def76e7b3b5715a14c4f90d107f2fe23154aa9a63c7c9c7892cd71fce26c
3
+ metadata.gz: f36986c04c73a293f76a80e6415296024153b1c2c756bd8777f67d17c05e0a32
4
+ data.tar.gz: c2e22acdc3c74da575c380e9eb9f7be40b0594f6a78525ead0ff39d3fdf3149f
5
5
  SHA512:
6
- metadata.gz: 03121c8e7bfd86f47a50ef007a1382d0a063d8ae5bed9aefe1144b131d64524c50a8d9ad372ccf74dd26fa594f6d474473d4d736cb072406e415d5db086f3f8b
7
- data.tar.gz: e61abd8e1212cd453196c2f83d096f60d70b330362aa20ca5c934b86007896ad9ce17ecae68e1210b0ac830ee276fdd089ad599c769c44b75616d9fa014d6e4d
6
+ metadata.gz: 7e8075969817d032ca9e84dfe02260981eb78043390ddfdb415019ea102e1aa549b9828d68b13661e34f3c83f2da32f1b89a2e2091f4ab9dec6d98e47d68e389
7
+ data.tar.gz: 223e4cf7c16da80ba9b2756db342c2398e97cf7f05b31169add185c4a4f5e331663502a6fd0e1e89114b9ba8d42c9f8b9776b32b58aaff0b69a273790bf6396a
data/CHANGELOG.md CHANGED
@@ -2,6 +2,12 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.1.17] - 2026-08-11
6
+
7
+ ### Fixed
8
+
9
+ - `Cache.checkCache` and `Cache.checkRDFCache` (`lib/cache.rb`) never expired anything — once a `/tmp/<md5>_*` entry was written, `harvester.rb#fetch` returned it forever, since `/tmp` inside the `communitytests` container is not a persistent volume and the only ways to clear a stale entry were a full container restart or manually deleting files over SSH. Added a `cached_at` timestamp file per entry (and per RDF graph cache entry) plus a TTL check on read, configurable via `CACHE_TTL` (default 300s / 5 minutes — short by design, since harvested DCAT/TTL records under test change frequently and testers need to see edits reflected quickly, unlike FDP-Index-Proxy's 24h `FDP_CACHE_TTL`). Also added `Cache.purge(uri, headers)` to force-evict a specific entry without waiting for TTL expiry.
10
+
5
11
  ## [0.1.16] - 2026-08-05
6
12
 
7
13
  ### Fixed
data/lib/cache.rb CHANGED
@@ -4,14 +4,34 @@ module FAIRChampionHarvester
4
4
  ################### CACHE FUNCTIONS #####################
5
5
  ################### #####################################
6
6
 
7
+ # Cache time-to-live in seconds. Configurable via the +CACHE_TTL+ env
8
+ # var; defaults to 5 minutes (short by design, unlike FDP-Index-Proxy's
9
+ # 24h FDP_CACHE_TTL, since harvested DCAT/TTL records under test change
10
+ # frequently and testers need to see edits reflected quickly).
11
+ CACHE_TTL = (ENV.fetch("CACHE_TTL", 300)).to_i
12
+
13
+ def self.expired?(timestamp_file)
14
+ return true unless File.exist?(timestamp_file)
15
+
16
+ age = Time.now - Marshal.load(File.read(timestamp_file))
17
+ age > CACHE_TTL
18
+ end
19
+
7
20
  def self.checkRDFCache(body)
8
21
  g = RDF::Graph.new
9
22
  key = Digest::MD5.hexdigest body
10
23
  graph_file = "/tmp/#{key}_graph"
11
24
  body_file = "/tmp/#{key}_graphbody"
25
+ time_file = "/tmp/#{key}_graphtime"
12
26
 
13
27
  return g unless File.exist?(graph_file) && File.exist?(body_file)
14
28
 
29
+ if expired?(time_file)
30
+ warn "RDF Cache File #{key} EXPIRED"
31
+ purgeRDFFiles(key)
32
+ return g
33
+ end
34
+
15
35
  warn "RDF Cache File #{key} FOUND"
16
36
  graph = Marshal.load(File.read(graph_file))
17
37
  graph.each { |statement| g << statement }
@@ -26,17 +46,33 @@ module FAIRChampionHarvester
26
46
  warn "WRITING RDF TO CACHE #{filename}"
27
47
  File.binwrite("/tmp/#{filename}_graph", Marshal.dump(graph))
28
48
  File.binwrite("/tmp/#{filename}_graphbody", body)
49
+ File.binwrite("/tmp/#{filename}_graphtime", Marshal.dump(Time.now))
29
50
  warn "wrote RDF filename: #{filename}"
30
51
  end
31
52
 
32
53
  def self.checkCache(uri, headers)
33
54
  filename = Digest::MD5.hexdigest uri + headers.to_s
55
+ time_file = "/tmp/#{filename}_time"
34
56
  warn "Checking Error cache for #{filename}"
57
+
35
58
  if File.exist?("/tmp/#{filename}_error")
36
- warn "Error file found in cache... returning"
37
- return ["ERROR", nil, [uri]]
59
+ if expired?(time_file)
60
+ warn "Error cache file #{filename} EXPIRED"
61
+ purgeFiles(filename)
62
+ else
63
+ warn "Error file found in cache... returning"
64
+ return ["ERROR", nil, [uri]]
65
+ end
38
66
  end
67
+
39
68
  if File.exist?("/tmp/#{filename}_head") and File.exist?("/tmp/#{filename}_body")
69
+ if expired?(time_file)
70
+ warn "Cache #{filename} EXPIRED"
71
+ purgeFiles(filename)
72
+ warn "Not Found in Cache"
73
+ return
74
+ end
75
+
40
76
  warn "FOUND data in cache"
41
77
  head = Marshal.load(File.read("/tmp/#{filename}_head"))
42
78
  body = Marshal.load(File.read("/tmp/#{filename}_body"))
@@ -54,15 +90,42 @@ module FAIRChampionHarvester
54
90
  headfilename = filename + "_head"
55
91
  bodyfilename = filename + "_body"
56
92
  urifilename = filename + "_uri"
93
+ timefilename = filename + "_time"
57
94
  File.binwrite("/tmp/#{headfilename}", Marshal.dump(head))
58
95
  File.binwrite("/tmp/#{bodyfilename}", Marshal.dump(body))
59
96
  File.binwrite("/tmp/#{urifilename}", Marshal.dump(finalURI))
97
+ File.binwrite("/tmp/#{timefilename}", Marshal.dump(Time.now))
60
98
  end
61
99
 
62
100
  def self.writeErrorToCache(uri, headers)
63
101
  filename = Digest::MD5.hexdigest uri + headers.to_s
64
102
  warn "in writeErrorToCache Writing error to cache for #{filename}"
65
103
  File.binwrite("/tmp/#{filename}_error", "ERROR")
104
+ File.binwrite("/tmp/#{filename}_time", Marshal.dump(Time.now))
105
+ end
106
+
107
+ # Force-evicts the cache entry (data and/or error) for a given uri+headers,
108
+ # regardless of TTL. Use this to bypass a stale or bad cached result
109
+ # without waiting for CACHE_TTL to elapse or restarting the container.
110
+ def self.purge(uri, headers)
111
+ filename = Digest::MD5.hexdigest uri + headers.to_s
112
+ purgeFiles(filename)
113
+ end
114
+
115
+ def self.purgeFiles(filename)
116
+ %w[_head _body _uri _error _time].each do |suffix|
117
+ path = "/tmp/#{filename}#{suffix}"
118
+ File.delete(path) if File.exist?(path)
119
+ end
120
+ end
121
+ private_class_method :purgeFiles
122
+
123
+ def self.purgeRDFFiles(key)
124
+ %w[_graph _graphbody _graphtime].each do |suffix|
125
+ path = "/tmp/#{key}#{suffix}"
126
+ File.delete(path) if File.exist?(path)
127
+ end
66
128
  end
129
+ private_class_method :purgeRDFFiles
67
130
  end
68
131
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FairChampionHarvester
4
- VERSION = "0.1.16"
4
+ VERSION = "0.1.17"
5
5
  end
data/lib/harvester.rb CHANGED
@@ -1,4 +1,4 @@
1
- HARVESTER_VERSION = "Hvst-0.1.16".freeze
1
+ HARVESTER_VERSION = "Hvst-0.1.17".freeze
2
2
  # better output,
3
3
  # different dealing with DataCite (they have a unique type header)
4
4
  # handle large extruct output,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fair_champion_harvester
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.16
4
+ version: 0.1.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - markwilkinson