"Oh, I get by with a little help from my friends"
Please is a simple Elixir library that provides a way to seamesly balance requests across multiple Elixir nodes. It is designed to be used in a distributed system where multiple nodes are available to handle requests. Please will automatically distribute requests across all available nodes taking into account the amount and weight of the requests each node is currently handling, and if the nodes can handle the task at all.
First, you need to start the Please application on all nodes that you want to
balance requests across. To do so you may include it in your mix.exs
file:
def application do
[
extra_applications: [:please]
]
end
Then, use Please
in your module to be able to make requests to the node
network.
defmodule MyModule do
use Please
def my_function do
Please.make_it_so(SomeOtherModule, :some_other_function, [:some_arg, :some_other_arg, ...])
#=> {:ok, result, remitent_node} || {:error, :timeout}
end
end
The application will handle node list persistence, node availability, and
request balancing for you. You just need to call Please.make_it_so
with the
module and function you want to call, and optionally the arguments you want to
pass to it. If a node has such a combination of module, function and arity, it
will be elegible to handle the request, and the one with the least amount of
workload (based on requests currently being handled) will be chosen to handle
it.
Please can be configured to always try to connect to a coma-separated list of nodes. This referral list can be set in the config files of your application:
config :please,
referrals: "node1@localhost,node2@localhost"
It's possible to define a metadata map that will be sent to the nodes to keep in the node list. This metadata can be freely specified, but is only updated once at connection time. The metadata can be set in the config files of your application:
config :please,
metadata: %{"my_key" => "my_value"}
The weight and offset of specific modules and functions can also be configured in the config files of your application:
config :please,
busyness_weights: %{
MyModule: %{my_function: 200}
},
busyness_offset: %{
MyModule: %{my_function: -50}
}
The offset represent how eager a node is to handle a request. A negative offset will make the node more likely to be chosen to handle a request, while a positive offset will make it less likely. The weight represents how much work a request will be for the node. The higher the weight, the less likely the node will be chosen to handle the request if it is handling such a task.
Any unspecified combination of module and function that is defined in the node
will have a default weight of 100 and a default offset of 0. The weight and
offset is used to calculate the busyness of a node by adding the total weight
of requests currently being handled by the node and then adding the offset. If
the custom weight is set to :reject
, the node will be considered ineligible
to handle the request even if it has the module and function available.
For further configuration options, please refer to the documentation of each
module in the Please
namespace.
Such friendship requires a lot of trust. The erlang distribution protocol is not secure, and the nodes will trust each other blindly. Please make sure that you trust all nodes in your network AND the network itself, and that you have taken the necessary precautions to secure your network traffic.
A good practice is to use a VPN to secure the communication between nodes, and to use a firewall to restrict the access to the nodes to only the necessary ports.
It's available in Hex, the package can be installed
by adding please
to your list of dependencies in mix.exs
:
def deps do
[
{:please, "~> 0.1.0"}
]
end
Documentation can be found at https://hexdocs.pm/please.