Skip to content

sneako/finch

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

710 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Finch

Finch

CI Hex pm Hexdocs.pm

An HTTP client with a focus on performance, built on top of Mint and NimblePool.

We attempt to achieve this goal by providing efficient connection pooling strategies and avoiding copying of memory wherever possible.

Most developers will most likely prefer to use the fabulous HTTP client Req which takes advantage of Finch's pooling and provides an extremely friendly and pleasant to use API.

Usage

In order to use Finch, you must start it and provide a :name. Often in your supervision tree:

children = [
  {Finch, name: MyFinch}
]

Or, in rare cases, dynamically:

Finch.start_link(name: MyFinch)

Once you have started your instance of Finch, you are ready to start making requests:

Finch.build(:get, "https://hex.pm") |> Finch.request(MyFinch)

When using HTTP/1, Finch will parse the passed in URL into a {scheme, host, port} tuple, and maintain one or more connection pools for each {scheme, host, port} you interact with.

You can also configure a pool size and count to be used for specific URLs that are known before starting Finch. The passed URLs will be parsed into {scheme, host, port}, and the corresponding pools will be started. See Finch.start_link/1 for configuration options.

children = [
  {Finch,
   name: MyConfiguredFinch,
   pools: %{
     :default => [size: 10, count: 2],
     "https://hex.pm" => [size: 32, count: 8]
   }}
]

Pools will be started for each configured {scheme, host, port} when Finch is started. For any unconfigured {scheme, host, port}, the pool will be started the first time it is requested using the :default configuration. This means given the pool configuration above each origin/{scheme, host, port} will launch 2 (:count) new pool processes. So, if you encountered 10 separate combinations, that'd be 20 pool processes.

Pool Tagging

Finch supports pool tagging, which allows you to create separate pools for the same {scheme, host, port} combination or Unix socket. This is useful when you need different configurations or want to isolate traffic for different purposes (e.g., API vs web requests, tenants, JWT tokens, etc).

You can configure tagged pools using Finch.Pool.new/2:

children = [
  {Finch,
   name: MyTaggedFinch,
   pools: %{
     Finch.Pool.new("https://api.example.com") => [size: 50, count: 4],
     Finch.Pool.new("https://api.example.com", tag: :web) => [size: 20, count: 2],
     Finch.Pool.new("http+unix:///tmp/api.sock", tag: :api) => [size: 30, count: 2],
     Finch.Pool.new("http+unix:///tmp/api.sock", tag: :web) => [size: 10, count: 1],
     :default => [size: 10, count: 1]
   }}
]

When making requests, you can specify which pool to use by setting the :pool_tag option:

# Uses the :api tagged pool
request = Finch.build(:get, "https://api.example.com/users", [], nil, pool_tag: :api)
Finch.request(request, MyTaggedFinch)

# Uses the :web tagged pool
request = Finch.build(:get, "https://api.example.com/users", [], nil, pool_tag: :web)
Finch.request(request, MyTaggedFinch)

# Uses :default tag (or falls back to default config)
request = Finch.build(:get, "https://api.example.com/users")
Finch.request(request, MyTaggedFinch)

# Tagged Unix socket pool
request =
  Finch.build(
    :get,
    "http://localhost/",
    [],
    nil,
    unix_socket: "/tmp/api.sock",
    pool_tag: :api
  )
Finch.request(request, MyTaggedFinch)

When making a request with a specific :pool_tag, the tag must exist in your pool configuration. If it doesn't exist, the request will use the :default configuration. This allows you to have specific configurations for tagged pools while maintaining sensible defaults for untagged requests.

Note pools are not automatically terminated by default, if you need to terminate them after some idle time, use the pool_max_idle_time option (available only for HTTP1 pools).

User-managed pools

You can start pools under your own supervision tree using Finch.Pool.child_spec/1. The Finch instance must be started first. User-managed pools integrate with Finch.request/2, Finch.stop_pool/2, Finch.get_pool_status/2, and Finch.find_pool/2:

children = [
  {Finch, name: MyFinch},
  {Finch.Pool, finch: MyFinch, pool: Finch.Pool.new("https://api.internal", tag: :api), size: 10},
  {Finch.Pool, finch: MyFinch, pool: Finch.Pool.new("https://node-2.internal", tag: :node2), size: 10}
]
Supervisor.start_link(children, strategy: :one_for_one)

To add pools dynamically under Finch's internal supervisor, use Finch.start_pool/3:

Finch.start_pool(MyFinch, Finch.Pool.new("https://api.example.com", tag: :api), size: 10)

Use Finch.find_pool/2 to check if a pool exists:

case Finch.find_pool(MyFinch, Finch.Pool.new("https://api.internal", tag: :api)) do
  {:ok, _pid} -> # Pool exists
  :error -> # Pool not found
end

Telemetry

Finch uses Telemetry to provide instrumentation. See the Finch.Telemetry module for details on specific events.

Logging TLS Secrets

Finch supports logging TLS secrets to a file. These can be later used in a tool such as Wireshark to decrypt HTTPS sessions. To use this feature you must specify the file to which the secrets should be written. If you are using TLSv1.3 you must also add keep_secrets: true to your pool :transport_opts. For example:

{Finch,
 name: MyFinch,
 pools: %{
   default: [conn_opts: [transport_opts: [keep_secrets: true]]]
 }}

There are two different ways to specify this file:

  1. The :ssl_key_log_file connection option in your pool configuration. For example:
{Finch,
 name: MyFinch,
 pools: %{
   default: [
     conn_opts: [
       ssl_key_log_file: "/writable/path/to/the/sslkey.log"
     ]
   ]
 }}
  1. Alternatively, you could also set the SSLKEYLOGFILE environment variable.

Installation

The package can be installed by adding finch to your list of dependencies in mix.exs:

def deps do
  [
    {:finch, "~> 0.20"}
  ]
end

The docs can be found at https://hexdocs.pm/finch.

About

Elixir HTTP client, focused on performance

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 59

Languages