View Source Handler.Pool (handler v0.5.0)

Manage a pool of resources used to run dangerous functions

The Pool provides both a synchrous interface (run/3) as well as an asynchronous interface (async/3 and await/1) for running functions.

composing-pools

Composing Pools

This module also provides a way to have limited resources for particular use-cases, that end up sharing bigger pools of resources. Take for instance a hosted multi-tenant application where you can safely use up to 10GB of memory for a particular task, but you don't want any one customer to use the whole pool, so each customer has a limit of just 5GB. You can handle this scenario using the delegate_to configuration.

{:ok, _pid} = Handler.Pool.start_link(%Handler.Pool{
  max_memory: 10 * 1024 * 1024 * 1024,
  name: :shared_pool
})
{:ok, _pid} = Handler.Pool.start_link(%Handler.Pool{
  delegate_to: :shared_pool,
  max_memory: 5 * 1024 * 1024 * 1024,
  name: :customer_pool
})

100 = Pool.run(:customer_pool, fn -> 10 * 10 end, max_heap_bytes: 100 * 1024)

Link to this section Summary

Link to this section Types

Specs

Specs

name() :: GenServer.name()

Specs

opt() ::
  Handler.opt()
  | {:task_name, String.t()}
  | {:delegate_param, term()}
  | {:pool_timeout, Handler.milliseconds()}

Specs

opts() :: [opt()]

Specs

pool() :: GenServer.server()

Specs

t() :: %Handler.Pool{
  delegate_fun: nil | {module(), fn_name :: atom(), first_argument :: term()},
  delegate_to: nil | name(),
  max_memory_bytes: non_neg_integer(),
  max_workers: non_neg_integer(),
  name: nil | name()
}

Link to this section Functions

Specs

async(pool(), (() -> any()), opts()) ::
  {:ok, reference()} | {:reject, exception()}

Asynchronously start a job

Take a potentially dangerous function and run it in the pool. You'll either get back an ok tuple with a reference you can pass to the await/1 function, or a reject tuple with an exception describing why the function couldn't be started.

Specs

await(reference()) :: any() | {:error, Handler.exception()}

Wait for the result of a job kicked off by async

Returns a specification to start this module under a supervisor.

See Supervisor.

Link to this function

flush(pool, exception \\ %{__exception__: true, __struct__: Handler.ProcessExit, message: "User killed the process", reason: :user_killed})

View Source

Kill all jobs in a pool. Returns the number of killed jobs.

The client that kicked off the work will receive an {:error, exception} as the result for the job. If you don't pass an exception, you will get back a Handler.ProcessExit{reason: :user_killed} by default.

Link to this function

kill(pool, task_name, exception \\ %{__exception__: true, __struct__: Handler.ProcessExit, message: "User killed the process", reason: :user_killed})

View Source

Kill jobs by their :name

When kicking off a job the :name option can be set and then later this function can be used to kill any jobs in progress with a :name matching the task_name of this function.

The client that kicked off the work will receive an {:error, exception} as the result for the job. If you don't pass an exception, you will get back a Handler.ProcessExit{reason: :user_killed} by default.

Link to this function

kill_by_ref(pool, ref, exception \\ %{__exception__: true, __struct__: Handler.ProcessExit, message: "User killed the process", reason: :user_killed})

View Source

Kill a job by its ref

When kicking off a job with the async/3 function a ref is returned and that job can later be killed.

The client that kicked off the work will receive an {:error, exception} as the result for the job. If you don't pass an exception, you will get back a Handler.ProcessExit{reason: :user_killed} by default.

Specs

run(pool(), (() -> any()), opts()) ::
  any() | {:error, Handler.exception()} | {:reject, exception()}

Run a potentially dangerous function in the pool

This function has pretty much the same interface as Handler.run/2 with the addition of the {:reject, t:exception()} return values when the pool does not have enough resources to start a particular function.

Specs

start_link(t()) :: :ignore | {:error, any()} | {:ok, pid()}