View Source Runbox.Runtime.Stage.Emulator (runbox v13.0.3)
StageBased scenario runtime single-process emulator.
Using this module you can emulate multi-process StageBased scenario inside a single process. The
emulation uses the original templates, i.e. modules implementing
Runbox.Scenario.Template.StageBased
behavior.
The emulation is designed to emulate a StageBased scenario in another scenario, usually in another
scenario type (like Simple). You can also use this to test StageBased scenarios, however,
Runbox.Runtime.Stage.Sandbox
might be a better fit for testing.
If you plan to use this in a Simple scenario checkout a macro
Runbox.Runtime.Simple.StageBasedEmulator
. It provides deeper integration with Simple scenario
runtime and enables you to quickly and easily convert StageBased scenario to Simple scenario
emulating the original behavior.
Example use
The emulation consists of the following steps and activities. The emulated scenario is defined by a list of modules - templates. The emulation has its own internal state, so you don't need to remember the modules yourself.
First it's usually needed to know which logical topics are required by the emulated scenario. You
can use function input_topics/1
for this purpose. It returns list of all input topics defined in
templates' subscriptions as well as the type of the topic (input or load).
Then you can actually start executing the emulated scenario. At first you need to initialize it
via initialize/2
. This initializes the internals of the emulator, creates all static units
(those defined in Runbox.Scenario.Template.StageBased.instances/0
) in every template and also
executes the Runbox.Scenario.Template.StageBased.init/2
callback for each of these units.
Then you can start handling messages via the function handle_message/3
. Apart from regular
scenario outputs, like output actions, this also outputs timeout registrations that need to be
handled externally. This is done because handling timeouts internally might lead to problems when
using the emulator in a scenario.
If you are persisting the internal state, such as in a savepoint, you need to use
reinitialize_state/1
to refresh information that might not survive a persistence. Note the state
is only designed to be persisted via ETF, it doesn't support JSON or other more restrictive
formats.
Summary
Functions
Handles a message in the emulation session.
Initializes an emulation session.
Returns input topics the templates are subscribed to.
Re-initializes a state after it has been persisted and loaded.
Types
@type output() :: Runbox.Scenario.OutputAction.oa_params() | Runbox.Runtime.RuntimeInstruction.t()
@opaque state()
@opaque timeout_message_type()
Functions
@spec handle_message( message :: Runbox.Message.t(), origin_logical_topic :: String.t() | any(), state() ) :: {:ok, [output()], state()}
Handles a message in the emulation session.
Takes a message, the logical topic it came from and the state of the emulation session and handles the message by the emulated scenario. This can produce outputs and also can change the state of the emulated scenario.
One of the outputs is a Runbox.Runtime.RuntimeInstruction
. The caller is responsible for
evaluating these instructions. E.g. if a timeout is registered the caller must ensure the timeout
message is handled at the appropriate time.
Note that when handling such timeouts the argument from
is ignored. Timeout messages are
automatically routed to the unit they were created in and are not subjected to the regular message
routing.
@spec initialize(templates :: [module()], start_from_timestamp :: non_neg_integer()) :: {:ok, [output()], state()}
Initializes an emulation session.
The emulation is started by an initialization. This takes a list of templates and parameters
needed for their initialization. The templates are used to create an emulated version of the
computation network, much like a true StageBased scenario. This is encapsulated in an internal
state. The state holds all the information needed for the emulation, including the current scenario
state, and is then passed to handle_message/3
when consuming messages.
Statically defined units (defined via Runbox.Scenario.Template.StageBased.instances/0
) are
instantiated and initialized. This can produce output actions which are returned from this
function.
One of the outputs is a Runbox.Runtime.RuntimeInstruction
. The caller is responsible for
evaluating these instructions. E.g. if a timeout is registered the caller must ensure the timeout
message is handled at the appropriate time.
@spec input_topics(templates :: [module()]) :: [ {:input_topic | :load_topic, topic :: String.t()} ]
Returns input topics the templates are subscribed to.
Goes through every specified template and finds all input topics in the subscriptions. Returns a list of all topics the templates are subscribed to including the type of the topic.
Re-initializes a state after it has been persisted and loaded.
The emulation state can be persisted into ETF. However, when such state is loaded some internal references might not work correctly and it is required to re-initialize the state. Call this function after you load the state and before you start using it.