Module: Legion::LLM::Cache::Response

Extended by:
Legion::Logging::Helper
Defined in:
lib/legion/llm/cache/response.rb

Class Method Summary collapse

Class Method Details

.cleanup(request_id) ⇒ Object

Removes all cache keys for a request (and any spool file).



84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/legion/llm/cache/response.rb', line 84

def cleanup(request_id)
  raw = Legion::Cache.get(response_key(request_id))
  if raw&.start_with?('spool:')
    path = raw.delete_prefix('spool:')
    FileUtils.rm_f(path)
  end

  Legion::Cache.delete(status_key(request_id))
  Legion::Cache.delete(response_key(request_id))
  Legion::Cache.delete(meta_key(request_id))
  Legion::Cache.delete(error_key(request_id))
end

.complete(request_id, response:, meta:, ttl: default_ttl) ⇒ Object



19
20
21
22
23
# File 'lib/legion/llm/cache/response.rb', line 19

def complete(request_id, response:, meta:, ttl: default_ttl)
  write_response(request_id, response, ttl)
  cache_set(meta_key(request_id), Legion::JSON.dump(meta), ttl)
  cache_set(status_key(request_id), 'done', ttl)
end

.error(request_id) ⇒ Object

Returns { code:, message: } hash, or nil.



56
57
58
59
60
61
# File 'lib/legion/llm/cache/response.rb', line 56

def error(request_id)
  raw = Legion::Cache.get(error_key(request_id))
  return nil if raw.nil?

  ::JSON.parse(raw, symbolize_names: true)
end

.fail_request(request_id, code:, message:, ttl: default_ttl) ⇒ Object



25
26
27
28
29
30
# File 'lib/legion/llm/cache/response.rb', line 25

def fail_request(request_id, code:, message:, ttl: default_ttl)
  log.warn("ResponseCache fail_request request_id=#{request_id} code=#{code} message=#{message}")
  payload = Legion::JSON.dump({ code: code, message: message })
  cache_set(error_key(request_id), payload, ttl)
  cache_set(status_key(request_id), 'error', ttl)
end

.init_request(request_id, ttl: default_ttl) ⇒ Object



15
16
17
# File 'lib/legion/llm/cache/response.rb', line 15

def init_request(request_id, ttl: default_ttl)
  cache_set(status_key(request_id), 'pending', ttl)
end

.meta(request_id) ⇒ Object

Returns meta hash with symbolized keys, or nil.



48
49
50
51
52
53
# File 'lib/legion/llm/cache/response.rb', line 48

def meta(request_id)
  raw = Legion::Cache.get(meta_key(request_id))
  return nil if raw.nil?

  ::JSON.parse(raw, symbolize_names: true)
end

.poll(request_id, timeout: default_ttl, interval: 0.1) ⇒ Object



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/legion/llm/cache/response.rb', line 63

def poll(request_id, timeout: default_ttl, interval: 0.1)
  deadline = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + timeout

  loop do
    current = status(request_id)
    log.debug("ResponseCache poll request_id=#{request_id} status=#{current}")

    case current
    when :done
      return { status: :done, response: response(request_id), meta: meta(request_id) }
    when :error
      return { status: :error, error: error(request_id) }
    end

    return { status: :timeout } if ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) >= deadline

    sleep interval
  end
end

.response(request_id) ⇒ Object

Returns the response string (handles spool overflow transparently).



39
40
41
42
43
44
45
# File 'lib/legion/llm/cache/response.rb', line 39

def response(request_id)
  raw = Legion::Cache.get(response_key(request_id))
  return nil if raw.nil?
  return File.read(raw.delete_prefix('spool:')) if raw.start_with?('spool:')

  raw
end

.status(request_id) ⇒ Object

Returns :pending, :done, :error, or nil.



33
34
35
36
# File 'lib/legion/llm/cache/response.rb', line 33

def status(request_id)
  raw = Legion::Cache.get(status_key(request_id))
  raw&.to_sym
end