ActorSimulation (GenServerVirtualTime v0.1.0)
View SourceA DSL for simulating actor systems with message rates and statistics.
This module provides a way to define actors, their message sending patterns, and simulate their interactions using virtual time.
Example
simulation =
ActorSimulation.new()
|> ActorSimulation.add_actor(:producer,
send_pattern: {:periodic, 100, {:data, :id}},
targets: [:consumer])
|> ActorSimulation.add_actor(:consumer,
on_receive: fn msg, state ->
# Process message and maybe send response
{:ok, state}
end)
|> ActorSimulation.run(duration: 5000)
stats = ActorSimulation.get_stats(simulation)
IO.inspect(stats)
Summary
Functions
Adds an actor to the simulation.
Adds a real GenServerVirtualTime process to the simulation ("Process in the Loop").
Enables message tracing for the simulation.
Gets statistics from the simulation.
Gets the message trace from the simulation. Returns a list of trace events for building sequence diagrams.
Creates a new actor simulation.
Runs the simulation for the specified duration (in milliseconds).
Stops the simulation and cleans up resources.
Formats the trace as a Mermaid sequence diagram with enhanced styling.
Formats the trace as a PlantUML sequence diagram.
Functions
Adds an actor to the simulation.
Options:
:send_pattern- How this actor sends messages:{:periodic, interval, message}- Send message every interval ms{:rate, messages_per_second, message}- Send at a specific rate{:burst, count, interval, message}- Send count messages every interval
:targets- List of actor names to send messages to:on_receive- Function called when receiving a message:fn msg, state -> {:ok, new_state} | {:send, msgs, new_state} end:on_match- Pattern matching responses:[{pattern, response_fn}]:initial_state- Initial state for the actor (default: %{})
Adds a real GenServerVirtualTime process to the simulation ("Process in the Loop").
This allows you to test real GenServer implementations alongside simulated actors.
Options:
:module- The GenServer module to start (required):args- Arguments to pass to the module's init/1:targets- List of actor names this process can send to (optional)
Example
defmodule MyRealServer do
use VirtualTimeGenServer
def init(args), do: {:ok, args}
def handle_call(:ping, _from, state), do: {:reply, :pong, state}
end
simulation =
ActorSimulation.new()
|> ActorSimulation.add_process(:my_server, module: MyRealServer, args: %{})
|> ActorSimulation.add_actor(:pinger,
send_pattern: {:periodic, 100, {:call, :my_server, :ping}})
Enables message tracing for the simulation.
Gets statistics from the simulation.
Gets the message trace from the simulation. Returns a list of trace events for building sequence diagrams.
Each event is a map with:
:timestamp- Virtual time when message was sent:from- Sender actor name:to- Receiver actor name:message- The message sent:type-:cast,:call, or:send
Creates a new actor simulation.
Options:
:trace- Enable message tracing for sequence diagrams (default: false)
Example
iex> simulation = ActorSimulation.new()
iex> is_pid(simulation.clock)
true
iex> simulation.actors
%{}
Runs the simulation for the specified duration (in milliseconds).
Stops the simulation and cleans up resources.
Formats the trace as a Mermaid sequence diagram with enhanced styling.
Mermaid is widely supported in GitHub, GitLab, and many markdown viewers. Uses features from Mermaid sequence diagrams:
- Different arrow types for call/cast/send
- Activation boxes for processing
- Notes with timestamps
- Background highlighting for grouped interactions
Example
iex> simulation = %ActorSimulation{trace: [
...> %{from: :alice, to: :bob, message: :hello, type: :send, timestamp: 100},
...> %{from: :bob, to: :alice, message: :hi, type: :send, timestamp: 200}
...> ]}
iex> mermaid = ActorSimulation.trace_to_mermaid(simulation)
iex> String.contains?(mermaid, "sequenceDiagram")
true
iex> String.contains?(mermaid, "alice->>bob")
true
Formats the trace as a PlantUML sequence diagram.
Example
simulation = ActorSimulation.new(trace: true)
|> add_actor(:client, send_pattern: {:periodic, 100, :ping}, targets: [:server])
|> add_actor(:server)
|> run(duration: 200)
plantuml = ActorSimulation.trace_to_plantuml(simulation)
File.write!("sequence.puml", plantuml)