48 lines
1.7 KiB
Elixir
48 lines
1.7 KiB
Elixir
defmodule ElixirAi.AudioProcessing do
|
|
@moduledoc """
|
|
Public API for the demand-driven audio transcription pool.
|
|
|
|
Dispatch strategy:
|
|
1. Pick a random idle worker from the :available pg group.
|
|
2. If none are idle and the pool is below @max_workers, spawn a fresh worker
|
|
under AudioWorkerSupervisor and route the job directly to it.
|
|
3. If already at @max_workers, queue the job to a random existing worker via
|
|
its Erlang mailbox — it will process it when its current job finishes.
|
|
|
|
Scale-up is fully automatic (on demand). Scale-down is handled by each worker's
|
|
idle-timeout logic; workers exit after idling and the pool can reach 0.
|
|
"""
|
|
|
|
@max_workers 10
|
|
@all_group :all
|
|
@available_group :available
|
|
|
|
@doc """
|
|
Submit audio for transcription. The result is delivered asynchronously to
|
|
`caller_pid` as:
|
|
|
|
{:transcription_result, {:ok, text} | {:error, reason}}
|
|
"""
|
|
def submit(audio_binary, mime_type, caller_pid) do
|
|
case :pg.get_members(ElixirAi.AudioProcessingPG, @available_group) do
|
|
[] ->
|
|
all = :pg.get_members(ElixirAi.AudioProcessingPG, @all_group)
|
|
|
|
if length(all) < @max_workers do
|
|
{:ok, pid} =
|
|
DynamicSupervisor.start_child(ElixirAi.AudioWorkerSupervisor, ElixirAi.AudioWorker)
|
|
|
|
GenServer.cast(pid, {:transcribe, caller_pid, audio_binary, mime_type})
|
|
else
|
|
# At max capacity — overflow to a random worker's mailbox
|
|
GenServer.cast(Enum.random(all), {:transcribe, caller_pid, audio_binary, mime_type})
|
|
end
|
|
|
|
available ->
|
|
GenServer.cast(Enum.random(available), {:transcribe, caller_pid, audio_binary, mime_type})
|
|
end
|
|
|
|
:ok
|
|
end
|
|
end
|