View Source Sorcery.Domain.Server (Sorcery v0.1.0)

The server component that manages domain instances and processes commands.

The DomainServer is responsible for:

  1. Managing domain process lifecycles
  2. Processing commands and generating events
  3. Maintaining domain state by applying events
  4. Handling event subscriptions

Types of Domains

Sorcery supports two types of domains:

  1. ID-Based Domains - Multiple instances of the same domain type, each with a unique ID
  2. Singleton Domains - Single instance domains that manage global state

Auto-Starting

Domains can be configured to auto-start when your application boots. This ensures that:

  1. All domains are ready to handle commands immediately
  2. Domains listening for events from other domains don't miss any events
  3. Event handlers are always active

Configure auto-starting in your config:

config :sorcery, :auto_start,
  domains: [
    MyApp.UserDomain,
    MyApp.SettingsDomain
  ]

Domains not configured for auto-start will be started on-demand when they receive their first command.

ID-Based Domains

Use these when you need multiple instances of the same domain type:

# Start and execute a command on a user domain
Sorcery.DomainServer.execute(
  MyApp.UserDomain,
  "user-123",
  %MyApp.UserDomain.Commands.RegisterUser{
    name: "John Doe",
    email: "john@example.com"
  }
)

Singleton Domains

Use these for global state or configuration:

# Start and execute a command on a settings domain
Sorcery.DomainServer.execute(
  MyApp.SettingsDomain,
  %MyApp.SettingsDomain.Commands.UpdateTheme{
    theme: "dark"
  }
)

Process Management

Each domain instance is a separate process that:

  • Subscribes to the event store
  • Maintains its own state
  • Processes commands
  • Generates and applies events

Event Handling

When events occur:

  1. The event is stored in the event store
  2. All domain processes receive the event
  3. Each domain filters events relevant to it
  4. Relevant events are applied to update state

Process Registry

Domain processes are registered with unique names:

  • ID-based domains: {DomainModule, "id"}
  • Singleton domains: DomainModule

This ensures:

  • Only one process per domain instance
  • Easy lookup of existing processes
  • Automatic process cleanup on termination

Summary

Functions

Returns a specification to start this module under a supervisor.

Gets the current state of a domain instance.

Initializes a domain process with its initial state.

Starts a new DomainServer process.

Starts a singleton instance of a domain. This is used for auto-starting domains at application boot.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

execute(domain_module, id_or_command, maybe_command \\ nil)

Executes a command on a domain.

This is the main entry point for changing domain state. It will:

  1. Start the domain process if it doesn't exist
  2. Send the command to the process
  3. Handle command validation
  4. Generate and store events
  5. Apply events to update state

Examples

For ID-based domains:

Sorcery.DomainServer.execute(
  MyApp.UserDomain,
  "user-123",
  %MyApp.UserDomain.Commands.RegisterUser{
    name: "John Doe",
    email: "john@example.com"
  }
)

For singleton domains:

Sorcery.DomainServer.execute(
  MyApp.SettingsDomain,
  %MyApp.SettingsDomain.Commands.UpdateTheme{
    theme: "dark"
  }
)

Returns

  • :ok - Command succeeded
  • {:error, reason} - Command failed with reason

get_state(domain_module, id)

Gets the current state of a domain instance.

Arguments

  • domain_module - The domain module
  • id - The instance ID (or nil for singleton domains)

Returns

  • {:ok, state} - The current state of the domain
  • {:error, :not_found} - If the domain instance doesn't exist

init(arg)

Initializes a domain process with its initial state.

The process will:

  1. Subscribe to the event store
  2. Load historical events
  3. Build initial state by applying events

start_link(opts)

Starts a new DomainServer process.

Arguments

Can be called in two ways:

  1. With module and ID: start_link(domain_module, id_or_command, maybe_command)

  2. With keyword options: start_link(domain: domain_module, id: id)

start_link(domain_module, id_or_command, maybe_command \\ nil)

start_singleton(domain_module)

Starts a singleton instance of a domain. This is used for auto-starting domains at application boot.