publish aggregate when task is complete
All checks were successful
Build and Publish / build-release (push) Successful in 1m26s

This commit is contained in:
2026-04-17 13:32:46 -05:00
parent 4bd1ff4124
commit 67837ff3ea
5 changed files with 76 additions and 92 deletions

View File

@@ -52,7 +52,7 @@ defmodule WorkloadService.Consumers.QuoteRequestedConsumer do
defp handle_event(
%{
"id" => %{"org_id" => org_id, "application_id" => app_id, "policy_type" => policy_type} = application_id,
"id" => %{"org_id" => org_id, "application_id" => app_id, "policy_type" => policy_type},
"provider_id" => provider_id,
"policy_details" => policy_details,
"applicant_info" => applicant_info

View File

@@ -0,0 +1,51 @@
defmodule WorkloadService.Handlers.TaskCompletedHandler do
use Commanded.Event.Handler,
application: WorkloadService.CommandedApp,
name: "TaskCompletedHandler"
require Logger
alias WorkloadService.Events.TaskCompleted
alias Commanded.Aggregates.Aggregate
alias WorkloadService.MessageBus
alias WorkloadService.Aggregates.{
QuoteTask,
SolicitationTask
}
def handle(%TaskCompleted{} = event, _metadata) do
aggregate_module =
case event.id.type do
"quote" -> QuoteTask
# "solicitation" -> SolicitationTask
_ -> nil
end
if aggregate_module do
case Aggregate.aggregate_state(
WorkloadService.CommandedApp,
aggregate_module,
event.id
) do
nil ->
Logger.warning("TaskCompletedHandler: aggregate not found for #{event.id}")
state ->
MessageBus.publish(
"workload_service.events.quote_task_completed",
"quote_task_completed",
state
)
Logger.info("TaskCompletedHandler: published for #{event.id}")
end
end
:ok
rescue
e ->
Logger.error("TaskCompletedHandler: failed to process - #{inspect(e)}")
:ok
end
end

View File

@@ -1,86 +1,21 @@
defmodule WorkloadService.MessageBus do
@moduledoc false
use AMQP
use GenServer
require Logger
def publish(exchange, routing_key, event) do
payload = Jason.encode!(event)
alias AMQP.{Connection, Channel, Exchange}
@reconnect_interval 5_000
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, opts, name: __MODULE__)
end
def publish(routing_key, payload) when is_binary(payload) do
GenServer.cast(__MODULE__, {:publish, routing_key, payload})
end
def publish(routing_key, payload) do
GenServer.cast(__MODULE__, {:publish, routing_key, Jason.encode!(payload)})
end
@impl true
def init(_opts) do
send(self(), :connect)
{:ok, %{channel: nil, connection: nil}}
end
@impl true
def handle_info(:connect, _state) do
case connect() do
{:ok, connection, channel} ->
{:noreply, %{connection: connection, channel: channel}}
{:error, reason} ->
Logger.error("Failed to connect to RabbitMQ: #{inspect(reason)}")
schedule_reconnect()
{:noreply, %{channel: nil, connection: nil}}
end
end
@impl true
def handle_info({:DOWN, _, :process, _pid, reason}, _state) do
Logger.error("RabbitMQ connection lost: #{inspect(reason)}")
schedule_reconnect()
{:noreply, %{channel: nil, connection: nil}}
end
@impl true
def handle_cast({:publish, _routing_key, _payload}, %{channel: nil} = state) do
Logger.warning("RabbitMQ not connected, message dropped")
{:noreply, state}
end
@impl true
def handle_cast({:publish, routing_key, payload}, %{channel: channel} = state) do
Exchange.direct(channel, exchange_name(), durable: true)
AMQP.Basic.publish(channel, exchange_name(), routing_key, payload,
:ok =
AMQP.Basic.publish(channel(), exchange, routing_key, payload,
content_type: "application/json",
persistent: true
)
{:noreply, state}
end
defp connect do
config = Application.get_env(:workload_service, WorkloadService.MessageBus, [])
with {:ok, connection} <- Connection.open(config),
{:ok, channel} <- Channel.open(connection) do
Exchange.declare(channel, exchange_name(), :direct, durable: true)
Process.monitor(connection.pid)
{:ok, connection, channel}
end
defp channel do
{:ok, conn} = AMQP.Connection.open(amqp_url())
{:ok, chan} = AMQP.Channel.open(conn)
chan
end
defp exchange_name do
Application.get_env(:workload_service, WorkloadService.MessageBus, [])
|> Keyword.get(:exchange, "workload_service.events")
end
defp schedule_reconnect do
Process.send_after(self(), :connect, @reconnect_interval)
end
defp amqp_url, do: Application.fetch_env!(:workload_service, :amqp_url)
end

View File

@@ -10,8 +10,6 @@ defmodule WorkloadService.Projectors.TaskProjector do
import Ecto.Query
project(%Events.TaskCreated{} = e, _meta, fn multi ->
application_id_str = to_string(e.application_id)
Ecto.Multi.insert(multi, :task, %Task{
id: to_string(e.id),
org_id: e.id.org_id,

View File

@@ -140,14 +140,14 @@ rawResources:
configure: ".*"
read: ".*"
exchange-task-completed:
exchange-quote-task-completed:
enabled: true
apiVersion: rabbitmq.com/v1beta1
kind: Exchange
suffix: exchange-task-completed
suffix: exchange-quote-task-completed
spec:
spec:
name: workload_service.events.task_completed
name: workload_service.events.quote_task_completed
type: topic
durable: true
vhost: "application"