CampaignFlow.MockServer.Webhooks.Dispatcher (CampaignFlow Client v2.2.0)
View SourceOutbound webhook dispatch for the mock server.
Responsibilities:
- Persist every event to
cf_mock_webhook_events(one row per attempt lifecycle). - Sign and POST the payload to the configured
webhook_urlvia Req. - Track delivery status, attempts, and
next_retry_aton the row. - Drive sync vs async delivery based on the
webhook_delivery_modeconfig flag.
The Webhooks.RetryScheduler GenServer drives retries by periodically
calling list_pending_due/0 and re-dispatching each event via
deliver_now/1.
Summary
Functions
Builds the payload for a campaign_status_change webhook event.
Synchronously delivers (or re-delivers) a single webhook event by id.
Persists a webhook event row and dispatches delivery (sync or async
depending on webhook_delivery_mode config).
Builds the payload for a finance_application_status_change webhook
event.
Returns webhook events that are eligible for delivery: status pending,
attempts below max, and next_retry_at either nil or in the past.
Functions
@spec campaign_status_change( CampaignFlow.MockServer.Schema.Campaign.t(), String.t() | nil ) :: {String.t(), map()}
Builds the payload for a campaign_status_change webhook event.
Returns {event_type, payload} for direct passing to enqueue/2.
@spec deliver_now(integer()) :: {:ok, %CampaignFlow.MockServer.Schema.WebhookEvent{ __meta__: term(), attempts: term(), delivered_at: term(), event_type: term(), id: term(), inserted_at: term(), last_attempt_at: term(), last_error: term(), max_attempts: term(), next_retry_at: term(), payload: term(), response_body: term(), response_status: term(), status: term(), target_url: term(), updated_at: term() }} | {:error, term()}
Synchronously delivers (or re-delivers) a single webhook event by id.
Idempotent: events already in a terminal status (delivered, failed,
skipped) are returned unchanged.
Returns {:ok, event} for both happy and retry-able failure outcomes —
callers introspect the row to determine status. Only terminal config
errors return {:error, reason}.
@spec enqueue(String.t(), map()) :: {:ok, %CampaignFlow.MockServer.Schema.WebhookEvent{ __meta__: term(), attempts: term(), delivered_at: term(), event_type: term(), id: term(), inserted_at: term(), last_attempt_at: term(), last_error: term(), max_attempts: term(), next_retry_at: term(), payload: term(), response_body: term(), response_status: term(), status: term(), target_url: term(), updated_at: term() }} | {:error, term()}
Persists a webhook event row and dispatches delivery (sync or async
depending on webhook_delivery_mode config).
@spec finance_application_status_change( CampaignFlow.MockServer.Schema.Campaign.t(), CampaignFlow.MockServer.Schema.FinanceApplication.t(), String.t() | nil, String.t() | nil ) :: {String.t(), map()}
Builds the payload for a finance_application_status_change webhook
event.
The payload includes a snapshot of the linked campaign so receivers can correlate the event to a campaign without an extra round-trip.
The campaign_previous_status argument controls what appears in the
finance event payload's campaign.previousStatus field:
- When the finance status change does NOT trigger a campaign side-effect,
callers should pass
campaign.statusso the field mirrors the current status (matching the documented payload shape for non-cascading events). - When the finance status change DOES trigger a campaign side-effect,
callers should pass
nil— the actual campaign transition is reported by a separatecampaign_status_changeevent with its own properpreviousStatus, so embedding it here would be redundant.
Returns {event_type, payload} for direct passing to enqueue/2.
@spec list_pending_due() :: [ %CampaignFlow.MockServer.Schema.WebhookEvent{ __meta__: term(), attempts: term(), delivered_at: term(), event_type: term(), id: term(), inserted_at: term(), last_attempt_at: term(), last_error: term(), max_attempts: term(), next_retry_at: term(), payload: term(), response_body: term(), response_status: term(), status: term(), target_url: term(), updated_at: term() } ]
Returns webhook events that are eligible for delivery: status pending,
attempts below max, and next_retry_at either nil or in the past.