Skip to content

Commit

Permalink
Merge branch 'release/v0.6.1' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
general-CbIC committed Mar 25, 2023
2 parents c91eef5 + 3d82113 commit dee0360
Show file tree
Hide file tree
Showing 16 changed files with 157 additions and 107 deletions.
17 changes: 14 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [0.6.1] - 2023-03-25

### Documentation updates

- Refactored some custom types and added some typedocs.
- Added `diff` syntax highlighting support.
- Updated guides:
- The pages were merged into a group called `Guides`.
- Tried to refresh some pages with [cheatmd](https://hexdocs.pm/ex_doc/cheatsheet.html).

## [0.6.0] - 2023-03-09

### Changed
Expand Down Expand Up @@ -39,7 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- [Docs] Simple [migration guide from `:poolboy`](docs/guides/migration-from-poolboy.md)
- [Docs] Simple [migration guide from `:poolboy`](https://hexdocs.pm/poolex/migration-from-poolboy.html)

### Fixed

Expand Down Expand Up @@ -77,7 +87,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Overflow feature. [Example of use](docs/guides/example-of-use.md)
- Overflow feature. [Example of use](https://hexdocs.pm/poolex/example-of-use.html)
- Speeding up CI by adding dialyzer PLT files caches.

### Fixed
Expand Down Expand Up @@ -145,7 +155,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Supported main interface `Poolex.run/3` with `:timeout` option.

[unreleased]: https://github.com/general-CbIC/poolex/compare/v0.6.0...HEAD
[unreleased]: https://github.com/general-CbIC/poolex/compare/v0.6.1...HEAD
[0.6.1]: https://github.com/general-CbIC/poolex/compare/v0.6.0...v0.6.1
[0.6.0]: https://github.com/general-CbIC/poolex/compare/v0.5.1...v0.6.0
[0.5.1]: https://github.com/general-CbIC/poolex/compare/v0.5.0...v0.5.1
[0.5.0]: https://github.com/general-CbIC/poolex/compare/v0.4.0...v0.5.0
Expand Down
33 changes: 16 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,19 @@ With `poolex` you can:
## Table of Contents

- [Installation](#installation)
- [Getting Started](docs/guides/getting-started.md)
- [Starting pool of workers](docs/guides/getting-started.md#starting-pool-of-workers)
- [Poolex configuration options](docs/guides/getting-started.md#poolex-configuration-options)
- [Working with the pool](docs/guides/getting-started.md#working-with-the-pool)
- [Migration from `:poolboy`](docs/guides/migration-from-poolboy.md)
- [Example of use](docs/guides/example-of-use.md)
- [Defining the worker](docs/guides/example-of-use.md#defining-the-worker)
- [Configuring Poolex](docs/guides/example-of-use.md#configuring-poolex)
- [Using Poolex](docs/guides/example-of-use.md#using-poolex)
- [Custom implementations](docs/guides/custom-implementations.md)
- [Callers](docs/guides/custom-implementations.md#callers)
- [Workers](docs/guides/custom-implementations.md#workers)
- [Writing custom implementations](docs/guides/custom-implementations.md#writing-custom-implementations)
- [Getting Started](https://hexdocs.pm/poolex/getting-started.html)
- [Starting pool of workers](https://hexdocs.pm/poolex/getting-started.html#starting-pool-of-workers)
- [Poolex configuration options](https://hexdocs.pm/poolex/getting-started.html#starting-pool-of-workers)
- [Working with the pool](https://hexdocs.pm/poolex/getting-started.html#working-with-the-pool)
- [Migration from `:poolboy`](https://hexdocs.pm/poolex/migration-from-poolboy.html)
- [Example of use](https://hexdocs.pm/poolex/example-of-use.html)
- [Defining the worker](https://hexdocs.pm/poolex/example-of-use.html#defining-the-worker)
- [Configuring Poolex](https://hexdocs.pm/poolex/example-of-use.html#defining-the-worker)
- [Using Poolex](https://hexdocs.pm/poolex/example-of-use.html#using-poolex)
- [Custom implementations](https://hexdocs.pm/poolex/custom-implementations.html)
- [Callers](https://hexdocs.pm/poolex/custom-implementations.html#callers)
- [Workers](https://hexdocs.pm/poolex/custom-implementations.html#workers)
- [Writing custom implementations](https://hexdocs.pm/poolex/custom-implementations.html#writing-custom-implementations)
- [Contributions](#contributions)

## Installation
Expand All @@ -67,11 +67,10 @@ In the most typical use of Poolex, you only need to start a pool of workers as a

```elixir
children = [
Poolex.child_spec(
{Poolex,
pool_id: :worker_pool,
worker_module: SomeWorker,
workers_count: 5
)
workers_count: 5}
]

Supervisor.start_link(children, strategy: :one_for_one)
Expand All @@ -84,7 +83,7 @@ iex> Poolex.run(:worker_pool, &(is_pid?(&1)), timeout: 1_000)
{:ok, true}
```

A detailed description of the available configuration or examples of use can be found in [documentation](docs/guides.md).
A detailed description of the available configuration or examples of use can be found in [documentation](https://hexdocs.pm/poolex/getting-started.html).

## Contributions

Expand Down
5 changes: 0 additions & 5 deletions docs/guides.md

This file was deleted.

6 changes: 4 additions & 2 deletions docs/guides/custom-implementations.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

## Callers

**Callers** are processes that have requested to get a worker (used `run/3` or `run!/3`). Each pool keeps the information about **callers** to distribute workers to them when they are free.
`Callers` are processes that have requested to get a worker (used `run/3` or `run!/3`). Each pool keeps the information about `callers` to distribute workers to them when they are free.

:warning: **Caller's typespec is `GenServer.from()` not a `pid()`** :warning:
> ### Caller's typespec {: .warning}
>
> Caller's typespec is `GenServer.from()` not a `pid()`.
The implementation of the caller storage structure should be conceptually similar to a queue since by default we want to give workers in the order they are requested. But this logic can be easily changed by writing your implementation.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ defmodule PoolexExample.Application do
use Application

def start(_type, _args) do
Poolex.child_spec(
pool_id: :worker_pool,
worker_module: PoolexExample.Worker,
workers_count: 5,
max_overflow: 2
)
children = [
{Poolex,
pool_id: :worker_pool,
worker_module: PoolexExample.Worker,
workers_count: 5,
max_overflow: 2}
]

Supervisor.start_link(children, strategy: :one_for_one)
Expand Down Expand Up @@ -92,7 +92,7 @@ Run the test function `PoolexExample.Test.start()` and see the result.

Note that 7 workers started at once. 5 of them were launched at initialization and 2 workers were started over the limit based on the `max_overflow` setting.

All supported configuration options are presented in [Getting Started guide](getting-started.md#poolex-configuration-options).
All supported configuration options are presented in [Getting Started guide](https://hexdocs.pm/poolex/getting-started.html#poolex-configuration-options).

```text
process #PID<0.351.0> calculating square root of 3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,19 @@ In general, you should place it into your Supervision tree for fault tolerance.

```elixir
children = [
Poolex.child_spec(
pool_id: :my_pool,
worker_module: SomeWorker,
workers_count: 10,
max_overflow: 10
)
{Poolex,
pool_id: :my_pool,
worker_module: SomeWorker,
workers_count: 10,
max_overflow: 10}
]

Supervisor.start_link(children, strategy: :one_for_one)
```

The second argument should contain a set of options for starting the pool.

### Poolex configuration options
## Poolex configuration options

| Option | Description | Example | Default value |
|------------------------|------------------------------------------------------|-----------------------|-----------------------------------|
Expand Down Expand Up @@ -57,4 +56,4 @@ iex> Poolex.run!(:agent_pool, fn pid -> Agent.get(pid, &(&1)) end)
5
```

If you would like to see examples of using Poolex, then check out [Example of Use](example-of-use.md).
If you would like to see examples of using Poolex, then check out [Example of Use](https://hexdocs.pm/poolex/example-of-use.html).
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ If you are using `:poolboy` and want to use `Poolex` instead, then you need to f

## I. Install the `Poolex` dependency

#### mix.exs

```diff
# mix.exs
defp deps do
[
- {:poolboy, "~> 1.5.0"}
Expand All @@ -14,6 +15,12 @@ defp deps do
end
```

Install it.

```bash
mix deps.get
```

Well, you can also clean up installed dependencies locally and remove them from the `lock` file.

```bash
Expand All @@ -22,8 +29,9 @@ mix deps.clean --unlock --unused

## II. Update child specs

#### Your Application or Supervisor file

```diff
# Your Application or Supervisor file
def init(_args) do
children = [
- :poolboy.child_spec(:some_pool,
Expand All @@ -46,9 +54,10 @@ end

## III. Update call site

Use `run!/3` to leave the same behavior.
If you want a safe interface with error handling, then use `run/3`.

```diff
# Use `run!/3` to leave the same behavior.
# If you want a safe interface with error handling, then use `run/3`.
- :poolboy.transaction(
- :some_pool,
- fn pid -> some_function(pid) end,
Expand Down
10 changes: 4 additions & 6 deletions examples/poolex_example/lib/poolex_example/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@ defmodule PoolexExample.Application do
def start(_type, _args) do
children = [
{Poolex,
[
pool_id: :worker_pool,
worker_module: PoolexExample.Worker,
workers_count: 5,
max_overflow: 2
]}
pool_id: :worker_pool,
worker_module: PoolexExample.Worker,
workers_count: 5,
max_overflow: 2}
]

Supervisor.start_link(children, strategy: :one_for_one)
Expand Down
85 changes: 60 additions & 25 deletions lib/poolex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ defmodule Poolex do
| `waiting_callers_impl` | Module that describes how to work with callers queue | `WaitingCallersImpl` | `Poolex.Callers.Impl.ErlangQueue` |
"""

@typedoc """
Any atom naming your pool, e.g. `:my_pool`.
"""
@type pool_id() :: atom()
@typedoc """
#{@poolex_options_table}
"""
@type poolex_option() ::
{:pool_id, pool_id()}
| {:worker_module, module()}
Expand All @@ -63,6 +69,27 @@ defmodule Poolex do
| {:idle_workers_impl, module()}
| {:waiting_callers_impl, module()}

@typedoc """
Process id of `worker`.
**Workers** are processes launched in a pool.
"""
@type worker() :: pid()

@typedoc """
Tuple describing the `caller`.
**Callers** are processes that have requested to get a worker.
"""
@type caller() :: GenServer.from()

@typedoc """
| Option | Description | Example | Default value |
|---------|----------------------------------------------------|----------|----------------------------|
| timeout | How long we can wait for a worker on the call site | `60_000` | `#{@default_wait_timeout}` |
"""
@type run_option() :: {:timeout, timeout()}

@doc """
Starts a Poolex process without links (outside of a supervision tree).
Expand Down Expand Up @@ -145,7 +172,6 @@ defmodule Poolex do
iex> Poolex.run(:some_pool, fn pid -> Agent.get(pid, &(&1)) end)
{:ok, 5}
"""
@type run_option() :: {:timeout, timeout()}
@spec run(pool_id(), (worker :: pid() -> any()), list(run_option())) ::
{:ok, any()} | :all_workers_are_busy | {:runtime_error, any()}
def run(pool_id, fun, options \\ []) do
Expand Down Expand Up @@ -355,36 +381,45 @@ defmodule Poolex do
end

@impl GenServer
def handle_cast({:release_busy_worker, worker_pid}, %State{} = state) do
def handle_cast({:release_busy_worker, worker}, %State{} = state) do
if WaitingCallers.empty?(state.pool_id, state.waiting_callers_state) do
if BusyWorkers.member?(state.pool_id, state.busy_workers_state, worker_pid) do
busy_workers_state =
BusyWorkers.remove(state.pool_id, state.busy_workers_state, worker_pid)

if state.overflow > 0 do
stop_worker(state.supervisor, worker_pid)

{:noreply, %State{state | busy_workers_state: busy_workers_state}}
else
{:noreply,
%State{
state
| busy_workers_state: busy_workers_state,
idle_workers_state:
IdleWorkers.add(state.pool_id, state.idle_workers_state, worker_pid)
}}
end
new_state = release_busy_worker(state, worker)
{:noreply, new_state}
else
new_state = provide_worker_to_waiting_caller(state, worker)
{:noreply, new_state}
end
end

@spec release_busy_worker(State.t(), worker()) :: State.t()
defp release_busy_worker(%State{} = state, worker) do
if BusyWorkers.member?(state.pool_id, state.busy_workers_state, worker) do
busy_workers_state = BusyWorkers.remove(state.pool_id, state.busy_workers_state, worker)

if state.overflow > 0 do
stop_worker(state.supervisor, worker)

%State{state | busy_workers_state: busy_workers_state}
else
{:noreply, state}
%State{
state
| busy_workers_state: busy_workers_state,
idle_workers_state: IdleWorkers.add(state.pool_id, state.idle_workers_state, worker)
}
end
else
{caller, new_waiting_callers_state} =
WaitingCallers.pop(state.pool_id, state.waiting_callers_state)
state
end
end

GenServer.reply(caller, {:ok, worker_pid})
@spec provide_worker_to_waiting_caller(State.t(), worker()) :: State.t()
defp provide_worker_to_waiting_caller(%State{} = state, worker) do
{caller, new_waiting_callers_state} =
WaitingCallers.pop(state.pool_id, state.waiting_callers_state)

{:noreply, %{state | waiting_callers_state: new_waiting_callers_state}}
end
GenServer.reply(caller, {:ok, worker})

%{state | waiting_callers_state: new_waiting_callers_state}
end

@impl GenServer
Expand Down
8 changes: 4 additions & 4 deletions lib/poolex/busy_workers.ex
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ defmodule Poolex.BusyWorkers do
end

@doc false
@spec add(Poolex.pool_id(), Behaviour.state(), Behaviour.worker()) :: Behaviour.state()
@spec add(Poolex.pool_id(), Behaviour.state(), Poolex.worker()) :: Behaviour.state()
def add(pool_id, state, worker), do: impl(pool_id).add(state, worker)

@doc false
@spec member?(Poolex.pool_id(), Behaviour.state(), Behaviour.worker()) :: boolean()
@spec member?(Poolex.pool_id(), Behaviour.state(), Poolex.worker()) :: boolean()
def member?(pool_id, state, worker), do: impl(pool_id).member?(state, worker)

@doc false
@spec remove(Poolex.pool_id(), Behaviour.state(), Behaviour.worker()) :: Behaviour.state()
@spec remove(Poolex.pool_id(), Behaviour.state(), Poolex.worker()) :: Behaviour.state()
def remove(pool_id, state, worker), do: impl(pool_id).remove(state, worker)

@doc false
@spec count(Poolex.pool_id(), Behaviour.state()) :: non_neg_integer()
def count(pool_id, state), do: impl(pool_id).count(state)

@doc false
@spec to_list(Poolex.pool_id(), Behaviour.state()) :: list(Behaviour.worker())
@spec to_list(Poolex.pool_id(), Behaviour.state()) :: list(Poolex.worker())
def to_list(pool_id, state), do: impl(pool_id).to_list(state)

@doc false
Expand Down
Loading

0 comments on commit dee0360

Please sign in to comment.