legion-data 1.10.28 → 1.11.7

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.
@@ -10,56 +10,62 @@ module Legion
10
10
  class << self
11
11
  include Legion::Logging::Helper
12
12
 
13
- def archive_to_warm(table:, age_days: 90, batch_size: 1000)
14
- return { archived: 0, reason: 'no_connection' } unless Legion::Data.connection
15
- return { archived: 0, reason: 'no_archive_table' } unless Legion::Data.connection.table_exists?(:data_archive)
13
+ def archive_to_warm(model:, age_days: 90, batch_size: 1000)
14
+ return { archived: 0, reason: 'no_connection' } unless Legion::Data.connected?
15
+
16
+ table = model.table_name
17
+ db = model.db
18
+ raise ArgumentError, 'source model must use the DataArchive database' unless db.equal?(Legion::Data::Model::DataArchive.db)
16
19
 
17
20
  cutoff = Time.now - (age_days * 86_400)
18
- records = Legion::Data.connection[table].where { created_at < cutoff }.limit(batch_size).all
19
- return { archived: 0 } if records.empty?
21
+ archived = db.transaction(savepoint: true, **(db.database_type == :sqlite ? { mode: :immediate } : {})) do
22
+ candidates = model.where { created_at < cutoff }.order(:id).limit(batch_size)
23
+ candidates = candidates.for_update unless db.database_type == :sqlite
24
+ records = candidates.all
25
+ next 0 if records.empty?
20
26
 
21
- Legion::Data.connection.transaction do
22
27
  records.each do |record|
23
- Legion::Data.connection[:data_archive].insert(
28
+ Legion::Data::Model::DataArchive.create(
24
29
  source_table: table.to_s, source_id: record[:id],
25
- data: Legion::JSON.dump(record),
30
+ data: Legion::JSON.dump(record.values),
26
31
  tier: TIERS[:warm],
27
32
  archived_at: Time.now.utc
28
33
  )
29
34
  end
30
35
 
31
36
  ids = records.map { |r| r[:id] }
32
- Legion::Data.connection[table].where(id: ids).delete
37
+ model.where(id: ids).delete
33
38
  end
39
+ return { archived: 0 } if archived.zero?
34
40
 
35
- log.info "Archived #{records.size} row(s) from #{table} to warm tier"
36
- { archived: records.size, table: table.to_s }
41
+ log.info "Archived #{archived} row(s) from #{table} to warm tier"
42
+ { archived: archived, table: table.to_s }
37
43
  rescue StandardError => e
38
44
  handle_exception(e, level: :error, handled: false, operation: :archive_to_warm, table: table, age_days: age_days, batch_size: batch_size)
39
45
  raise
40
46
  end
41
47
 
42
48
  def export_to_cold(age_days: 365, batch_size: 5000)
43
- return { exported: 0 } unless Legion::Data.connection&.table_exists?(:data_archive)
49
+ return { exported: 0 } unless Legion::Data.connected?
44
50
 
45
51
  cutoff = Time.now - (age_days * 86_400)
46
- records = Legion::Data.connection[:data_archive]
47
- .where(tier: TIERS[:warm])
48
- .where { archived_at < cutoff }
49
- .limit(batch_size).all
52
+ records = Legion::Data::Model::DataArchive
53
+ .where(tier: TIERS[:warm])
54
+ .where { archived_at < cutoff }
55
+ .limit(batch_size).all
50
56
  return { exported: 0 } if records.empty?
51
57
 
52
58
  ids = records.map { |r| r[:id] }
53
- Legion::Data.connection[:data_archive].where(id: ids).update(tier: TIERS[:cold])
59
+ Legion::Data::Model::DataArchive.where(id: ids).update(tier: TIERS[:cold])
54
60
  log.info "Exported #{records.size} row(s) to cold tier"
55
- { exported: records.size, data: records }
61
+ { exported: records.size, data: records.map(&:values) }
56
62
  rescue StandardError => e
57
63
  handle_exception(e, level: :error, handled: false, operation: :export_to_cold, age_days: age_days, batch_size: batch_size)
58
64
  raise
59
65
  end
60
66
 
61
67
  def stats
62
- return {} unless Legion::Data.connection&.table_exists?(:data_archive)
68
+ return {} unless Legion::Data.connected?
63
69
 
64
70
  { warm: count_tier(:warm), cold: count_tier(:cold) }
65
71
  rescue StandardError => e
@@ -70,7 +76,7 @@ module Legion
70
76
  private
71
77
 
72
78
  def count_tier(tier)
73
- Legion::Data.connection[:data_archive].where(tier: TIERS[tier]).count
79
+ Legion::Data::Model::DataArchive.where(tier: TIERS[tier]).count
74
80
  rescue StandardError => e
75
81
  handle_exception(e, level: :warn, handled: true, operation: :storage_tiers_count, tier: tier)
76
82
  0
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Legion
4
+ module Data
5
+ module Task
6
+ module Status
7
+ STATUSES = {
8
+ scheduled: 'task.scheduled', queued: 'task.queued', running: 'task.running', completed: 'task.completed',
9
+ exception: 'task.exception', failed: 'task.failed', skipped: 'task.skipped',
10
+ cancelled: 'task.cancelled', expired: 'task.expired', delayed: 'task.delayed',
11
+ dispatching: 'task.dispatching', multiplied: 'task.multiplied', retry_pending: 'task.retry_pending',
12
+ unknown: 'task.unknown', conditioner_queued: 'conditioner.queued', conditioner_failed: 'conditioner.failed',
13
+ conditioner_exception: 'conditioner.exception', transformer_queued: 'transformer.queued',
14
+ transformer_succeeded: 'transformer.succeeded', transformer_validation_failed: 'transformer.validation_failed',
15
+ transformer_failed: 'transformer.failed', transformer_exception: 'transformer.exception', blocked: 'task.blocked'
16
+ }.freeze
17
+ TERMINAL_STATUSES = STATUSES.values_at(:completed, :failed, :exception, :skipped, :cancelled, :expired, :multiplied,
18
+ :conditioner_failed, :conditioner_exception, :transformer_validation_failed,
19
+ :transformer_failed, :transformer_exception, :unknown, :blocked).freeze
20
+ LEGACY_TERMINAL_STATUSES = %w[completed complete failed error cancelled canceled timeout timed_out exception skipped expired multiplied].freeze
21
+
22
+ module Helper
23
+ def task_status(name:)
24
+ raise ArgumentError, 'Task status name must be a String or Symbol' unless name.is_a?(String) || name.is_a?(Symbol)
25
+
26
+ STATUSES.fetch(name.to_sym) { raise ArgumentError, "Unknown task status name #{name.inspect}" }
27
+ end
28
+
29
+ def task_terminal_status?(status:)
30
+ TERMINAL_STATUSES.include?(status) || LEGACY_TERMINAL_STATUSES.include?(status)
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Legion
4
4
  module Data
5
- VERSION = '1.10.28'
5
+ VERSION = '1.11.7'
6
6
  end
7
7
  end
data/lib/legion/data.rb CHANGED
@@ -17,6 +17,7 @@ require_relative 'data/rls'
17
17
  require_relative 'data/extract'
18
18
  require_relative 'data/audit_record'
19
19
  require_relative 'data/audit_log_hash_chain'
20
+ require_relative 'data/task/status'
20
21
 
21
22
  unless Legion::Logging::Helper.method_defined?(:handle_exception)
22
23
  module Legion
@@ -83,6 +84,8 @@ module Legion
83
84
  end
84
85
 
85
86
  def setup_cache
87
+ return unless Legion::Settings[:data][:models][:loaded]
88
+
86
89
  cache_settings = Legion::Settings[:data][:cache]
87
90
  setup_static_cache if cache_settings[:static_cache]
88
91
  setup_external_cache if cache_settings[:auto_enable] && defined?(::Legion::Cache)
@@ -209,7 +212,7 @@ module Legion
209
212
  end
210
213
 
211
214
  def setup_external_cache
212
- ttl = Legion::Settings[:data][:cache][:ttl] || 60
215
+ ttl = Legion::Settings[:data][:cache][:ttl]
213
216
  {
214
217
  Model::Relationship => 10,
215
218
  Model::Node => 10,
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: legion-data
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.28
4
+ version: 1.11.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity
@@ -57,14 +57,14 @@ dependencies:
57
57
  requirements:
58
58
  - - ">="
59
59
  - !ruby/object:Gem::Version
60
- version: 1.3.26
60
+ version: 1.4.5
61
61
  type: :runtime
62
62
  prerelease: false
63
63
  version_requirements: !ruby/object:Gem::Requirement
64
64
  requirements:
65
65
  - - ">="
66
66
  - !ruby/object:Gem::Version
67
- version: 1.3.26
67
+ version: 1.4.5
68
68
  - !ruby/object:Gem::Dependency
69
69
  name: sequel
70
70
  requirement: !ruby/object:Gem::Requirement
@@ -126,7 +126,6 @@ files:
126
126
  - lib/legion/data/audit_record.rb
127
127
  - lib/legion/data/auth_failure_handler.rb
128
128
  - lib/legion/data/connection.rb
129
- - lib/legion/data/connection_pool.rb
130
129
  - lib/legion/data/database_lock.rb
131
130
  - lib/legion/data/encryption/cipher.rb
132
131
  - lib/legion/data/encryption/key_provider.rb
@@ -288,6 +287,7 @@ files:
288
287
  - lib/legion/data/migrations/136_drop_llm_messages_seq_unique.rb
289
288
  - lib/legion/data/migrations/137_preserve_task_archive_fields.rb
290
289
  - lib/legion/data/migrations/138_add_append_claims.rb
290
+ - lib/legion/data/migrations/139_create_task_logs.rb
291
291
  - lib/legion/data/model.rb
292
292
  - lib/legion/data/models/apollo/access_log.rb
293
293
  - lib/legion/data/models/apollo/entries.rb
@@ -299,13 +299,16 @@ files:
299
299
  - lib/legion/data/models/apollo_entry.rb
300
300
  - lib/legion/data/models/apollo_expertise.rb
301
301
  - lib/legion/data/models/apollo_relation.rb
302
+ - lib/legion/data/models/append_claim.rb
302
303
  - lib/legion/data/models/audit_log.rb
303
304
  - lib/legion/data/models/audit_record.rb
304
305
  - lib/legion/data/models/chain.rb
306
+ - lib/legion/data/models/data_archive.rb
305
307
  - lib/legion/data/models/digital_worker.rb
306
308
  - lib/legion/data/models/extension.rb
307
309
  - lib/legion/data/models/extract_step_timing.rb
308
310
  - lib/legion/data/models/function.rb
311
+ - lib/legion/data/models/governance_event.rb
309
312
  - lib/legion/data/models/identity/audit_log.rb
310
313
  - lib/legion/data/models/identity/group.rb
311
314
  - lib/legion/data/models/identity/group_memberships.rb
@@ -346,6 +349,7 @@ files:
346
349
  - lib/legion/data/settings.rb
347
350
  - lib/legion/data/spool.rb
348
351
  - lib/legion/data/storage_tiers.rb
352
+ - lib/legion/data/task/status.rb
349
353
  - lib/legion/data/vector.rb
350
354
  - lib/legion/data/version.rb
351
355
  - scripts/pre-commit-rubocop.sh
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'legion/logging/helper'
4
-
5
- module Legion
6
- module Data
7
- module ConnectionPool
8
- include Legion::Logging::Helper
9
-
10
- def self.extended(pool)
11
- pool.instance_variable_set(:@shutdown_mutex, Mutex.new)
12
- pool.instance_variable_set(:@shutdown_condition, ConditionVariable.new)
13
- pool.instance_variable_set(:@shutdown_owners, {}.compare_by_identity)
14
- pool.instance_variable_set(:@shutdown_state, :open)
15
- end
16
-
17
- def hold(server = :default)
18
- owner = Sequel.current
19
- @shutdown_mutex.synchronize do
20
- raise Sequel::Error, 'Database pool is shutting down or closed' unless @shutdown_state == :open || @shutdown_owners.key?(owner)
21
-
22
- @shutdown_owners[owner] = @shutdown_owners.fetch(owner, 0) + 1
23
- end
24
- begin
25
- super
26
- ensure
27
- finish = @shutdown_mutex.synchronize do
28
- @shutdown_owners[owner] -= 1
29
- @shutdown_owners.delete(owner) if @shutdown_owners[owner].zero?
30
- if @shutdown_state == :draining && @shutdown_owners.empty?
31
- @shutdown_state = :closing
32
- true
33
- end
34
- end
35
- finish_shutdown if finish
36
- end
37
- end
38
-
39
- def shutdown(timeout:, &on_closed)
40
- deadline = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + timeout
41
- finish = @shutdown_mutex.synchronize do
42
- @shutdown_callback ||= on_closed
43
- @shutdown_state = :draining if %i[open failed].include?(@shutdown_state)
44
- if @shutdown_state == :draining && @shutdown_owners.empty?
45
- @shutdown_state = :closing
46
- true
47
- end
48
- end
49
- finish_shutdown if finish
50
- @shutdown_mutex.synchronize do
51
- until @shutdown_state == :closed
52
- remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
53
- return false if remaining <= 0 || @shutdown_state == :failed || @shutdown_owners.key?(Sequel.current)
54
-
55
- @shutdown_condition.wait(@shutdown_mutex, remaining)
56
- end
57
- end
58
- true
59
- end
60
-
61
- def shutdown_status
62
- @shutdown_mutex.synchronize { { state: @shutdown_state, active_requests: @shutdown_owners.size } }
63
- end
64
-
65
- private
66
-
67
- def finish_shutdown
68
- disconnect
69
- @shutdown_callback.call
70
- @shutdown_mutex.synchronize do
71
- @shutdown_state = :closed
72
- @shutdown_condition.broadcast
73
- end
74
- rescue StandardError => e
75
- @shutdown_mutex.synchronize do
76
- @shutdown_state = :failed
77
- @shutdown_condition.broadcast
78
- end
79
- handle_exception(e, level: :error, handled: true, operation: :pool_shutdown)
80
- end
81
- end
82
- end
83
- end