Loader (loader v0.5.0)
Loader
is a load-generating library that allows you to define arbitrary distributions of arbitrary work via mathematical functions and small structs.
These distributions, called LoadProfile
s, can be paired up with a WorkSpec
and executed to generate load, and gather statistics from a client's perspective.
usage
Usage
In order to use Loader
you must start it and provide a :name
, typically in a supervision tree:
children = [
{Loader, name: MyLoader}
]
However you may want to use Loader
in an iex
session, or as part of a mix
script via Mix.install/2
, in which case you can also start Loader
dynamically:
Loader.start_link(name: MyLoader)
example
Example
Let's assume there is some service at http://website.io/public/api
, and we want to generate some simple, uniform load against that service.
alias Loader.{LoadProfile, WorkResponse, WorkSpec}
uniform_one_minute_profile =
LoadProfile.new(%{
target_running_time: 60,
function: &LoadProfile.Curves.uniform(&1, 10) # y = 10
})
service_call_spec = %WorkSpec{
task: fn ->
Finch.build(:get, "http://website.io/public/api", [])
|> Finch.request(MyApp.Finch)
end,
is_success?: fn %WorkResponse{data: res} ->
case res do
{:ok, _any} -> true
_any -> false
end
end
}
Loader.start_link(name: MyLoader)
Loader.execute({uniform_one_minute_profile, service_call_spec}, MyLoader)
The above example will generate a uniform 10 requests/ second against our imaginary service. We could also write additional load profiles, and run them concurrently to generate constructive interference!
linear_one_minute_profile =
LoadProfile.new(%{
target_running_time: 60,
function: &LoadProfile.Curves.linear(&1, 1.5, 5) # y = 1.5x + 5
})
sine_wave_one_minute_profile =
LoadProfile.new(%{
target_running_time: 60,
function: fn x -> 5 * (:math.sin(x) + 1) end # y = 5 * (sin(x) + 1)
})
[
{uniform_one_minute_profile, service_call_spec},
{linear_one_minute_profile, service_call_spec},
{sine_wave_one_minute_profile, service_call_spec},
]
|> Loader.execute(MyLoader)
Visualized, this second example would produce load on the service as shown, where x
is in seconds and y
is requests/ second:

telemetry
Telemetry
Loader
emits the following telemetry events:
[:loader, :load_profile_execution, :start]
- emitted whenLoader.execute/2
is called.[:loader, :load_profile_execution, :stop]
- emitted when aLoadProfile
has been fully executed, regardless of the number of successes or failures of individual tasks[:loader, :task, :start]
- emitted when the:task
callback from aLoader.WorkSpec
is invoked[:loader, :task, :stop]
- emitted when the:task
callback from aLoader.WorkSpec
is invoked[:loader, :task, :exception]
- emitted if there is an uncaught exception while invoking the:task
callback from aLoader.WorkSpec
See the documentation for the Loader.Telemetry
module for more information.
ets
ETS
Note that Loader
uses one ETS table per instance.
installation
Installation
The package can be installed by adding loader
to your list of dependencies in mix.exs
:
def deps do
[
{:loader, "~> 0.4.0"}
]
end
The docs can be found at https://hexdocs.pm/loader.
Link to this section Summary
Link to this section Functions
child_spec(init_arg)
Returns a specification to start this module under a supervisor.
See Supervisor
.
execute(profile_spec_pairs, instance_name)
@spec execute( {Loader.LoadProfile.t(), Loader.WorkSpec.t()}, atom() ) :: DynamicSupervisor.on_start_child()
@spec execute([{Loader.LoadProfile.t(), Loader.WorkSpec.t()}], atom()) :: [ DynamicSupervisor.on_start_child() ]
Execute tasks defined by the work_spec
, scheduled based on the load_profile
. When provided with a list, all profiles will be executed concurrently.
See Loader.LoadProfile
for more information on how to define a profile.
start_link(opts)
Start an instance of Loader
options
Options
:name
- The name of your Loader instance. This field is required.