please

Elixir node mesh network for request balancing.


License
MIT

Documentation

Please

"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.

Usage

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.

Configuration

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.

A word of caution

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.

Installation

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.