Skip to content

Commit 67f217e

Browse files
authored
fix: heath check should check the conn managed by Tenants.Connect (#699)
* fix: heath check should check the conn managed by Tenants.Connect * fix: dialyzer warnings
1 parent 29152cb commit 67f217e

File tree

5 files changed

+35
-38
lines changed

5 files changed

+35
-38
lines changed

lib/realtime/tenants.ex

+13-19
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ defmodule Realtime.Tenants do
55

66
require Logger
77
alias Realtime.Repo.Replica
8-
alias Realtime.Api
9-
alias Realtime.{Api.Tenant, PostgresCdc, UsersCounter}
8+
alias Realtime.{Api.Tenant, UsersCounter, Tenants}
109

1110
@doc """
1211
Gets a list of connected tenant `external_id` strings in the cluster or a node.
@@ -23,21 +22,20 @@ defmodule Realtime.Tenants do
2322
end
2423

2524
@doc """
26-
Gets the database connection pid of the SubscriptionManager `manager` and the
27-
Postgrex connection pool `subs_pool`.
28-
29-
When this function returns `:wait` the database connection tree is starting and the
30-
caller should not try to start the database connection tree again.
25+
Gets the database connection pid managed by the Tenants.Connect process.
3126
3227
## Examples
3328
34-
iex> get_manager_conn(Extensions.PostgresCdcRls, "not_started_external_id")
35-
{:error, nil}
29+
iex> get_health_conn(%Tenant{external_id: "not_found_tenant"})
30+
{:error, :tenant_database_unavailable}
3631
"""
3732

38-
@spec get_manager_conn(:atom, %Tenant{}) :: {:error, :wait | nil} | {:ok, pid(), pid()}
39-
def get_manager_conn(module, %Tenant{external_id: external_id}) do
40-
module.get_manager_conn(external_id)
33+
@spec get_health_conn(%Tenant{}) :: {:error, term()} | {:ok, pid()}
34+
def get_health_conn(%Tenant{external_id: external_id}) do
35+
case Tenants.Connect.get_status(external_id) do
36+
{:ok, conn} -> {:ok, conn}
37+
{:error, reason} -> {:error, reason}
38+
end
4139
end
4240

4341
@doc """
@@ -60,19 +58,15 @@ defmodule Realtime.Tenants do
6058
| %{connected_cluster: pos_integer, db_connected: false, healthy: false}}
6159
| {:ok, %{connected_cluster: non_neg_integer, db_connected: true, healthy: true}}
6260
def health_check(external_id) when is_binary(external_id) do
63-
with %Tenant{} = tenant <- Api.get_tenant_by_external_id(external_id),
64-
{:ok, module} <- PostgresCdc.driver(tenant.postgres_cdc_default),
65-
{:error, _} <- get_manager_conn(module, tenant),
61+
with %Tenant{} = tenant <- Tenants.Cache.get_tenant_by_external_id(external_id),
62+
{:error, _} <- get_health_conn(tenant),
6663
connected_cluster when connected_cluster > 0 <- UsersCounter.tenant_users(external_id) do
6764
{:error, %{healthy: false, db_connected: false, connected_cluster: connected_cluster}}
6865
else
6966
nil ->
7067
{:error, :tenant_not_found}
7168

72-
{:error, _mod} ->
73-
{:error, "Bad value for tenant field `postgres_cdc_default`"}
74-
75-
{:ok, _manager, _subs_pool} ->
69+
{:ok, _health_conn} ->
7670
connected_cluster = UsersCounter.tenant_users(external_id)
7771

7872
{:ok, %{healthy: true, db_connected: true, connected_cluster: connected_cluster}}

lib/realtime/tenants/connect.ex

+16-9
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,23 @@ defmodule Realtime.Tenants.Connect do
1717
@spec lookup_or_start_connection(binary()) :: {:ok, DBConnection.t()} | {:error, term()}
1818
def lookup_or_start_connection(tenant_id) do
1919
case get_status(tenant_id) do
20-
:undefined -> call_external_node(tenant_id)
2120
{:ok, conn} -> {:ok, conn}
22-
_ -> {:error, :tenant_database_unavailable}
21+
{:error, :tenant_database_unavailable} -> call_external_node(tenant_id)
22+
{:error, :initializing} -> {:error, :tenant_database_unavailable}
23+
end
24+
end
25+
26+
@doc """
27+
Returns the database connection pid from :syn if it exists.
28+
"""
29+
30+
@spec get_status(binary()) ::
31+
{:ok, DBConnection.t()} | {:error, :tenant_database_unavailable | :initializing}
32+
def get_status(tenant_id) do
33+
case :syn.lookup(__MODULE__, tenant_id) do
34+
{_, %{conn: conn}} when not is_nil(conn) -> {:ok, conn}
35+
{_, %{conn: nil}} -> {:error, :initializing}
36+
_error -> {:error, :tenant_database_unavailable}
2337
end
2438
end
2539

@@ -74,13 +88,6 @@ defmodule Realtime.Tenants.Connect do
7488

7589
## Private functions
7690

77-
defp get_status(tenant_id) do
78-
case :syn.lookup(__MODULE__, tenant_id) do
79-
{_, %{conn: conn}} when not is_nil(conn) -> {:ok, conn}
80-
error -> error
81-
end
82-
end
83-
8491
defp call_external_node(tenant_id) do
8592
with tenant <- Tenants.Cache.get_tenant_by_external_id(tenant_id),
8693
{:ok, node} <- Realtime.Nodes.get_node_for_tenant(tenant) do

lib/realtime_web/controllers/tenant_controller.ex

-5
Original file line numberDiff line numberDiff line change
@@ -261,11 +261,6 @@ defmodule RealtimeWeb.TenantController do
261261
conn
262262
|> put_status(404)
263263
|> render("not_found.json", tenant: nil)
264-
265-
{:error, message} when is_binary(message) ->
266-
conn
267-
|> put_status(422)
268-
|> json(%{errors: [message]})
269264
end
270265
end
271266
end

mix.exs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ defmodule Realtime.MixProject do
44
def project do
55
[
66
app: :realtime,
7-
version: "2.25.0",
7+
version: "2.25.1",
88
elixir: "~> 1.14.0",
99
elixirc_paths: elixirc_paths(Mix.env()),
1010
start_permanent: Mix.env() == :prod,

test/realtime_web/controllers/tenant_controller_test.exs

+5-4
Original file line numberDiff line numberDiff line change
@@ -211,10 +211,11 @@ defmodule RealtimeWeb.TenantControllerTest do
211211
UsersCounter.add(self(), ext_id)
212212

213213
# Fake a db connection
214-
{:ok, mod} = PostgresCdc.driver(tenant.postgres_cdc_default)
215-
:syn.add_node_to_scopes([mod])
216-
:syn.register(mod, ext_id, self(), %{region: nil, manager: nil, subs_pool: nil})
217-
mod.update_meta(ext_id, self(), self())
214+
:syn.register(Realtime.Tenants.Connect, ext_id, self(), %{conn: nil})
215+
216+
:syn.update_registry(Realtime.Tenants.Connect, ext_id, fn _pid, meta ->
217+
%{meta | conn: conn}
218+
end)
218219

219220
conn = get(conn, Routes.tenant_path(conn, :health, ext_id))
220221
data = json_response(conn, 200)["data"]

0 commit comments

Comments
 (0)