Commanded Application Configuration

View Source

The application section allows you to configure the Commanded application that manages command dispatch, event publishing, and process management for your domain. The Commanded application is the core component that orchestrates the event-sourced domain.

Basic Usage

The application section is defined at the domain level, allowing each domain to have its own Commanded application configuration:

defmodule ECommerce.Store do
  use Ash.Domain, extensions: [AshCommanded.Commanded.Dsl]

  resources do
    resource ECommerce.Product
    resource ECommerce.Customer
    resource ECommerce.Order
  end

  commanded do
    application do
      otp_app :ecommerce
      event_store Commanded.EventStore.Adapters.EventStore
    end
  end
end

Configuration Options

The following options can be configured in the application section:

OptionTypeRequiredDefaultDescription
otp_appatomYes-The OTP application name to use for configuration
event_storeatom or keyword listYes-The event store adapter to use (e.g., Commanded.EventStore.Adapters.EventStore)
pubsubatomNo:localThe pubsub adapter to use (:local or :phoenix)
registryatomNo:localThe registry adapter to use (:local or :global)
snapshottingkeyword listNo[]Configuration for aggregate snapshotting
include_supervisor?booleanNofalseWhether to include a supervisor for the application
prefixstringNonilApplication module prefix for generated code

Events Stores

AshCommanded supports all Commanded event store adapters:

Example using the default EventStore adapter:

commanded do
  application do
    otp_app :ecommerce
    event_store Commanded.EventStore.Adapters.EventStore
  end
end

Example using the InMemory adapter for testing:

commanded do
  application do
    otp_app :ecommerce
    event_store Commanded.EventStore.Adapters.InMemory
  end
end

Generated Application Module

The DSL will generate an application module using the configuration. This module extends the Commanded.Application behavior:

defmodule ECommerce.Store.Application do
  use Commanded.Application,
    otp_app: :ecommerce,
    event_store: Commanded.EventStore.Adapters.EventStore,
    pubsub: :local,
    registry: :local,
    router: ECommerce.Store.Router

  # Supervision for projectors (only included if include_supervisor? is true)
  def child_spec() do
    Supervisor.child_spec(
      {Supervisor, [
        strategy: :one_for_one,
        name: Module.concat(__MODULE__, Supervisor)
      ]},
      id: Module.concat(__MODULE__, Supervisor)
    )
  end
end

Supervision

By default, Commanded applications are not supervised. To include a supervisor for your application, set include_supervisor? to true:

commanded do
  application do
    otp_app :ecommerce
    event_store Commanded.EventStore.Adapters.EventStore
    include_supervisor? true
  end
end

This will generate a supervisor for your application that you can add to your supervision tree:

defmodule ECommerce.Application do
  use Application

  def start(_type, _args) do
    children = [
      # ...other children
      ECommerce.Store.Application.child_spec()
    ]

    opts = [strategy: :one_for_one, name: ECommerce.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Multiple Applications

AshCommanded supports defining multiple Commanded applications across different domains. This is useful for separating different bounded contexts in your application:

defmodule ECommerce.Customers do
  use Ash.Domain, extensions: [AshCommanded.Commanded.Dsl]

  resources do
    resource ECommerce.Customer
  end

  commanded do
    application do
      otp_app :ecommerce
      event_store Commanded.EventStore.Adapters.EventStore, schema: "customers"
    end
  end
end

defmodule ECommerce.Orders do
  use Ash.Domain, extensions: [AshCommanded.Commanded.Dsl]

  resources do
    resource ECommerce.Order
    resource ECommerce.OrderItem
  end

  commanded do
    application do
      otp_app :ecommerce
      event_store Commanded.EventStore.Adapters.EventStore, schema: "orders"
    end
  end
end

Usage

Once the application is configured, you can dispatch commands through the domain's router:

command = %ECommerce.Commands.RegisterCustomer{id: "123", email: "customer@example.com", name: "John Doe"}
ECommerce.Customers.Router.dispatch(command)

The router will automatically route the command to the appropriate aggregate and handle it according to your command handlers.