• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / supavisor / 22738398145

05 Mar 2026 09:50PM UTC coverage: 43.243%. First build
22738398145

Pull #865

github

web-flow
Merge 910c5a91f into 609d94708
Pull Request #865: fix: use a Dynamic Supervisor for starting proxy connections

5 of 85 new or added lines in 6 files covered. (5.88%)

1328 of 3071 relevant lines covered (43.24%)

3949.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/lib/supavisor/client_handler/proxy.ex
1
defmodule Supavisor.ClientHandler.Proxy do
2
  @moduledoc """
3
  Handles proxy connection logic for ClientHandler.
4
  """
5

6
  require Logger
7

8
  alias Supavisor.ClientHandler.Proxy.Supervisor, as: ProxySupervisor
9

10
  @max_sup_retries 3
11

12
  @type start_error ::
13
          :max_proxy_connections_reached
14
          | :failed_to_start_proxy_connection
15
          | :proxy_supervisor_unavailable
16

17
  @doc """
18
  Starts a proxy DbHandler for the given tenant.
19

20
  Ensures the proxy supervisor tree exists, then starts a DbHandler under it.
21

22
  Retries up to #{@max_sup_retries} times when the supervisor disappears between
23
  lookup and use (race with watchdog shutdown).
24

25
  Returns `{:ok, db_pid}` on success, or one of:
26
  - `{:error, :max_proxy_connections_reached}` if the connection limit has been reached
27
  - `{:error, :failed_to_start_proxy_connection}` if the child process failed to start
28
  - `{:error, :proxy_supervisor_unavailable}` if the supervisor could not be started after retries
29
  """
30
  @spec start_proxy_connection(Supavisor.id(), pos_integer(), map(), map(), map()) ::
31
          {:ok, pid()} | {:error, start_error()}
32
  def start_proxy_connection(id, max_clients, auth, tenant_feature_flags, pool_ranch) do
NEW
33
    child_spec =
×
34
      Supavisor.DbHandler.child_spec(
35
        build_db_handler_args(id, auth, tenant_feature_flags, pool_ranch)
36
      )
37

NEW
38
    do_start_proxy_connection(id, max_clients, child_spec, @max_sup_retries)
×
39
  end
40

41
  # This function is public for test purposes, so we can test the logic
42
  # with mock processes, not DbHandlers
43
  @doc false
44
  @spec do_start_proxy_connection(
45
          Supavisor.id(),
46
          max_clients :: pos_integer(),
47
          Supervisor.child_spec(),
48
          attempts_remaining :: non_neg_integer()
49
        ) ::
50
          {:ok, pid()} | {:error, start_error()}
NEW
51
  def do_start_proxy_connection(_id, _max_clients, _child_spec, 0) do
×
52
    {:error, :proxy_supervisor_unavailable}
53
  end
54

NEW
55
  def do_start_proxy_connection(id, max_clients, child_spec, retries) do
×
NEW
56
    with :ok <- ProxySupervisor.ensure_started(id, max_clients),
×
NEW
57
         {:ok, pid} <- ProxySupervisor.start_connection(id, child_spec) do
×
58
      {:ok, pid}
59
    else
NEW
60
      {:error, :max_children} ->
×
61
        {:error, :max_proxy_connections_reached}
62

63
      {:error, :proxy_sup_not_found} ->
NEW
64
        do_start_proxy_connection(id, max_clients, child_spec, retries - 1)
×
65

NEW
66
      {:error, :failed_to_start} ->
×
67
        {:error, :failed_to_start_proxy_connection}
68
    end
69
  catch
70
    :exit, _reason ->
NEW
71
      do_start_proxy_connection(id, max_clients, child_spec, retries - 1)
×
72
  end
73

74
  @spec build_db_handler_args(Supavisor.id(), map(), map(), map()) :: map()
75
  defp build_db_handler_args(id, auth, tenant_feature_flags, pool_ranch) do
NEW
76
    {tenant, user, _mode, _db_name, _search_path} = id
×
77

NEW
78
    proxy_auth =
×
79
      Map.merge(auth, %{
NEW
80
        port: pool_ranch.port,
×
NEW
81
        host: to_charlist(pool_ranch.host),
×
82
        ip_version: :inet,
83
        upstream_ssl: false,
84
        upstream_tls_ca: nil,
85
        upstream_verify: nil
86
      })
87

88
    %{
×
89
      id: id,
90
      auth: proxy_auth,
91
      user: user,
92
      tenant: tenant,
93
      tenant_feature_flags: tenant_feature_flags,
94
      replica_type: :write,
95
      mode: :proxy,
96
      proxy: true,
97
      log_level: nil
98
    }
99
  end
100
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc