Module: Labimotion::AiKlassQueue

Defined in:
lib/labimotion/libs/ai_klass_queue.rb

Overview

Hands AI template generation to the host's background worker.

Generating a template is one long provider call — 18s for a small segment, past 90s for a large one — and running it inside the request held the dialog open for all of it, losing the work if the tab was closed or reloaded. The endpoints enqueue instead and answer at once; the result comes back as a notification carrying a link into the designer.

The job itself belongs to the host: ActiveJob, the queue and the Message machinery are all its, and a gem that shipped its own would be defining infrastructure it does not own. So the host class is reached by its bare name and only if it exists — the same NameError-guarded pattern used for Matrice and Message elsewhere in this gem. A host without it gets the old inline behaviour rather than an error, which is what queue returning false tells the caller.

Constant Summary collapse

JOB =
'AiTemplateJob'

Class Method Summary collapse

Class Method Details

.inline?Boolean

Queued in every environment, development included: one code path, and the request returns straight away wherever it runs. Development therefore needs a worker like anywhere else — without one the job sits in the table and the notification never arrives.

LABIMOTION_AI_INLINE=true runs it in the request instead, for a machine with no worker to spare. Off unless asked for, because a create that blocks for the length of a provider call is not the behaviour anyone should get by accident.

Returns:

  • (Boolean)


51
52
53
54
55
# File 'lib/labimotion/libs/ai_klass_queue.rb', line 51

def self.inline?
  ENV['LABIMOTION_AI_INLINE'] == 'true'
rescue StandardError
  false
end

.job_classObject



68
69
70
71
72
# File 'lib/labimotion/libs/ai_klass_queue.rb', line 68

def self.job_class
  Object.const_get(JOB)
rescue NameError
  nil
end

.plain(params) ⇒ Object

Only what the helpers read, and stringified: file payloads included, since the reference files are part of the request the worker has to replay.

A JSON round trip rather than as_json, because that is precisely what the queue will do to these arguments anyway — so anything that would not survive being written to the jobs table fails here, in the request, rather than in a worker nobody is watching.



81
82
83
84
85
86
# File 'lib/labimotion/libs/ai_klass_queue.rb', line 81

def self.plain(params)
  return {} if params.nil?

  source = params.respond_to?(:to_unsafe_h) ? params.to_unsafe_h : params
  JSON.parse(JSON.generate(source))
end

.queue(kind:, params:, user:, element_klass_id: nil) ⇒ Boolean

Returns true when the work was handed off.

Returns:

  • (Boolean)

    true when the work was handed off



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/labimotion/libs/ai_klass_queue.rb', line 25

def self.queue(kind:, params:, user:, element_klass_id: nil)
  job = job_class
  return false if job.nil?

  # Grape params are a Hashie::Mash; the queue serialises what it is given,
  # and a Mash carries method_missing behaviour a worker process should not
  # be asked to rebuild. A plain hash is the whole contract.
  args = [kind.to_s, plain(params), user.id, element_klass_id]
  inline? ? run_now(job, args, user) : job.perform_later(*args)
  true
rescue StandardError => e
  # An enqueue that fails must not fail the request: the caller falls back
  # to generating inline, which is slower but still correct.
  Labimotion.log_exception(e, user)
  false
end

.run_now(job, args, user) ⇒ Object

Deliberately swallows: the job reports its own failure as a notification, exactly as it would on a worker, and letting it raise here would send the caller down the inline-generation fallback — spending a second provider call on work that has already been done and paid for.



61
62
63
64
65
66
# File 'lib/labimotion/libs/ai_klass_queue.rb', line 61

def self.run_now(job, args, user)
  job.perform_now(*args)
rescue StandardError => e
  Labimotion.log_exception(e, user)
  nil
end