Skip to content
/ glass Public

Easy, **Transparent** RPC library for Elixir

License

Notifications You must be signed in to change notification settings

vereis/glass

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Glass

Glass is a small library which provides a way to transparently proxy function calls in a pluggable fashion.

Installation

Add :glass to the list of dependencies in mix.exs:

def deps do
  [
    {:glass, "~> 0.1.0"}
  ]
end

About

This is immediately useful if you're working with multiple applications potentially deployed in different releases/environments but need to call functions between them.

Usually, you could do this via the built-in :rpc or :erpc modules (amongst others), but this requires ceremony and boilerplate to set up and maintain.

Glass aims to live up to its name, and the idea that the BEAM is network-transparent, by completely hiding the fact that you're not just calling a local function.

Usage

Once installed, you can use Glass as simply as adding the following to your code:

# 1) Setup and initialize `Glass`
use Glass

# 2) Define a `GlassProxy` for the target module, which for this example, we can
#    imagine is in another Elixir application which is bundled in the same umbrella
#    project as the current application, but is *released separately* in a production
#    environment so *we can't directly call functions in it*.
defglass ReportService, via: Glass.Methods.RPC

# 3) Be blown away by `Glass` letting you call these functions directly...
def accounts_receivable_report do
  current_user()
  |> MyApp.Accounting.accounts_receivable()
  |> ReportService.to_excel!()
end

Configuration

Glass is designed to be pluggable and extensible, and comes with a few built-in methods for proxying function calls between modules.

Built-in Methods

  • Glass.Methods.Apply (default): Useful for prototyping locally, this method simply calls the target function directly in the target module via Kernel.apply/3.
  • Glass.Methods.RPC: This method uses :rpc to call the target function in the target module. The node the rpc call is executed on is currently limited to a random node in the cluster (:erlang.nodes()), but this may be configurable in the future.

Custom Methods

You can also define your own method for proxying function calls by implementing the Glass.Method behaviour. If you want to customize the way Glass proxies function calls, you can define your own module and pass it as the :via option to defglass.

defmodule MyApp.Tupleize do
  @behaviour Glass.Method

  @impl Glass.Method
  def handle_proxy(module, function, args) do
    {module, function, args}
  end
end

defmodule MyApp.Users do
  use Glass

  defglass ReportService, via: MyApp.Tupleize

  ...

  def users_report do
    current_org()
    |> list_users()
    |> Enum.map(&build_report_rows/1)
    |> ReportService.to_csv!()
  end
end

iex(1)> MyApp.Users.users_report()
{ReportService, :to_csv!, [ ... ]}

Additional Configuration

  • :private (default: true): Whether or not to generate the proxy module as private. This is useful if you want to prevent direct access to the proxy module and force all calls to go through Glass. Mainly affects tab-completion in IEx.

  • :debug (default: false): Whether or not to generate debug information when proxying function calls. This is useful for debugging and tracing calls between modules.

  • :as: If provided, aliases and binds the created Glass proxy to the specified alias. If not provided, any Glass proxy must be called via its fully qualified name.

Caveats

  • Magic: This is a very magical library and should be used with caution. It's designed to be a transparent proxy, but this means that it can be difficult to debug when things go wrong. Use with caution and test thoroughly.

  • Performance: The easier it is to write network-transparent code, the easier it is to write slow network-transparent code.

    Be mindful of the performance implications of calling functions between modules in this way as depending on the :via method used, there may be a non-trivial serialization-deserialization overhead, or limitations on how much data can be sent between nodes before issues arise.

  • Security: This library is designed to be used in a trusted environment where you have control over the nodes in the cluster.

    It's not designed to be used in a hostile environment where you need to worry about malicious actors. Be mindful of the security implications of calling functions between modules in this way.

    You can mitigate some of these concerns by using the :via option to define your own method for proxying function calls with additional security checks, but this is left as an exercise to the reader.

Future Work

  • Anonymous via functions: Allow for anonymous functions to be passed as the :via option to defglass to allow for more flexible proxying of function calls.

  • Customizable debug output: Allow for custom debug output to be generated when proxying function calls.

  • Customizable error handling: Allow for custom error handling to be defined when proxying function calls.

  • Telemetry integration: Allow for Telemetry events to be emitted when proxying function calls to allow for better observability of function calls between modules.

  • Testing utilities: Allow for easier testing of Glass-proxied functions by providing utilities to mock out the Glass proxying mechanism.

License

Glass is released under the MIT License. See the LICENSE file for more information.

About

Easy, **Transparent** RPC library for Elixir

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published