LiveLoad.Cluster (LiveLoad v0.0.1-rc.46)

Copy Markdown View Source

LiveLoad.Cluster defines the creation of an ephemeral cluster of nodes (via FLAME) that LiveLoad runs its scenarios on.

A cluster is started for each run of a scenario. It is initialized eagerly by placing FLAME.Trackable resources on each node and ensuring that a node can have a maximum concurrency of 1, to ensure that only a single FLAME process is run on each node.

The cluster initialization goes through optimization phases by checking the expected resource usage of a browser and calculating how many nodes will be necessary based on the node's actual resource availability. A LiveLoad.Browser.Connection must provide 2 callbacks: LiveLoad.Browser.Connection.browser_memory_usage_bytes/0 and LiveLoad.Browser.Connection.context_memory_usage_bytes/0 to allow the cluster initialization to calculate how many nodes are necessary in order to pre-warm the pool. If the amount of nodes necessary exceeds the configured max_allowed_nodes, an error will be returned and the scenario will not be run.

Summary

Types

An error returned from the cluster initialization when the creation of a cluster node crashes due to the FLAME.Pool name being invalid.

An error returned from the cluster initialization when the creation of a cluster node takes longer than the configured timeout for the FLAME.Pool.

A module implementing the FLAME.Backend behaviour.

Options passed to the given flame_backend/0 on initialization of the FLAME.Pool.

Options passed to the FLAME.Pool on initialization.

Defines the maximum nodes that this load test can create when setting up a cluster.

An error returned from the cluster initialization when the node started by the given FLAME.Backend implementation and the given flame_pool_opts_opt/0 options is too small to actually handle creating a browser on the node.

An error returned from the cluster initialization when the given max_allowed_nodes_opt/0 is smaller than the calculated necessary nodes needed to run the load test on the FLAME nodes configured by the the given FLAME configurations.

Initialization options for running a LiveLoad.Cluster.

An error returned from the cluster initialization when the scenario is currently running and a new pool cannot be started.

t()

Types

cluster_initialization_error()

@type cluster_initialization_error() ::
  scenario_already_running_error()
  | not_enough_nodes_error()
  | node_too_small_error()
  | cluster_node_creation_timeout_error()
  | {:error, term()}

cluster_name_invalid_error()

@type cluster_name_invalid_error() :: {:error, :cluster_name_invalid}

An error returned from the cluster initialization when the creation of a cluster node crashes due to the FLAME.Pool name being invalid.

cluster_node_creation_timeout_error()

@type cluster_node_creation_timeout_error() ::
  {:error, :cluster_node_creation_timeout}

An error returned from the cluster initialization when the creation of a cluster node takes longer than the configured timeout for the FLAME.Pool.

flame_backend()

@type flame_backend() :: module()

A module implementing the FLAME.Backend behaviour.

flame_backend_opts_opt()

@type flame_backend_opts_opt() :: {:flame_backend_opts, Keyword.t()}

Options passed to the given flame_backend/0 on initialization of the FLAME.Pool.

Defaults to an empty list.

flame_pool_opts_opt()

@type flame_pool_opts_opt() :: {:flame_pool_opts, Keyword.t()}

Options passed to the FLAME.Pool on initialization.

The following options are automatically overridden by LiveLoad.Cluster and cannot be manually passed in:

  • :name
  • :max_concurrency
  • :track_resources
  • :min
  • :max
  • :single_use

See FLAME.Pool for all other available options.

Defaults to an empty list.

max_allowed_nodes_opt()

@type max_allowed_nodes_opt() :: {:max_allowed_nodes, pos_integer()}

Defines the maximum nodes that this load test can create when setting up a cluster.

Nodes are created eagerly on initialization of the cluster and maintained until the end of the load test's run. During cluster initialization, an optimization phase will be run to calculate the number of nodes required for this load test to complete based on the number of users for this load test, the resources available on a cluster node, and the resources required by the LiveLoad.Browser.Connection module used in this load test. Should the number of nodes required exceed the given value, an error will be returned.

The value given to this option must be a positive integer. If a negative integer or 0 is passed in, an ArgumentError will be raised.

Defaults to 100 nodes.

node_too_small_error()

@type node_too_small_error() :: {:error, :node_too_small}

An error returned from the cluster initialization when the node started by the given FLAME.Backend implementation and the given flame_pool_opts_opt/0 options is too small to actually handle creating a browser on the node.

This is determined by the LiveLoad.Cluster.Node started during the cluster initialization.

not_enough_nodes_error()

@type not_enough_nodes_error() ::
  {:error,
   {:necessary_nodes_exceeds_max_allowed_nodes, necessary :: pos_integer()}}

An error returned from the cluster initialization when the given max_allowed_nodes_opt/0 is smaller than the calculated necessary nodes needed to run the load test on the FLAME nodes configured by the the given FLAME configurations.

The calculation of necessary nodes is a heuristic based on the expected resource usage per user process determined by the LiveLoad.Browser.Connection.browser_memory_usage_bytes/0 and LiveLoad.Browser.Connection.context_memory_usage_bytes/0 callbacks on the selected LiveLoad.Browser.Connection implementation for this run.

option()

Initialization options for running a LiveLoad.Cluster.

scenario_already_running_error()

@type scenario_already_running_error() :: {:error, :scenario_is_already_running}

An error returned from the cluster initialization when the scenario is currently running and a new pool cannot be started.

This error is a limitation of FLAME, as FLAME requires atoms as pool names due to the usage of named ETS tables.

t()

@type t() :: %LiveLoad.Cluster{
  pool_name: atom(),
  pool_node_names: [node()],
  pool_nodes: [LiveLoad.Cluster.Node.t()]
}