Skip to content

Commit 5ae8acb

Browse files
committed
Avoid catching Xandra errors, let RPC take care of temporary failures
This change avoids catching and managing Xandra errors within the code dedicated to interact with the database, where the concern does not require handling expections. Exceptions and temporary failures are better handled by whomever calls Pairing functionality: in this case RPC, in the future it might be directly a Phoenix conn handling a request. Note that Astarte RPC already handles failures by responding with a generic error to the caller. The exception is logged for operational purposes, so developers can troubleshoot the issue, but these kind of database errors are not of much use to API users. Signed-off-by: Davide Briani <davide.briani@secomind.com>
1 parent acdcf58 commit 5ae8acb

File tree

3 files changed

+53
-125
lines changed

3 files changed

+53
-125
lines changed

apps/astarte_pairing/lib/astarte_pairing/queries.ex

Lines changed: 31 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -30,53 +30,16 @@ defmodule Astarte.Pairing.Queries do
3030
require Logger
3131
import Ecto.Query
3232

33-
@keyspace_does_not_exist_regex ~r/Keyspace (.*) does not exist/
34-
3533
def get_agent_public_key_pems(realm_name) do
3634
keyspace = CQLUtils.realm_name_to_keyspace_name(realm_name, Config.astarte_instance_id!())
3735

38-
try do
39-
with {:ok, pem} <-
40-
KvStore.fetch_value("auth", "jwt_public_key_pem", :string,
41-
prefix: keyspace,
42-
consistency: :quorum,
43-
error: :public_key_not_found
44-
) do
45-
{:ok, [pem]}
46-
end
47-
rescue
48-
err -> handle_xandra_error(err)
49-
end
50-
end
51-
52-
defp handle_xandra_error(%Xandra.ConnectionError{} = error) do
53-
_ =
54-
Logger.warning("Database connection error #{Exception.message(error)}.",
55-
tag: "database_connection_error"
56-
)
57-
58-
{:error, :database_connection_error}
59-
end
60-
61-
defp handle_xandra_error(%Xandra.Error{} = error) do
62-
%Xandra.Error{message: message} = error
63-
64-
case Regex.run(@keyspace_does_not_exist_regex, message) do
65-
[_message, keyspace] ->
66-
Logger.warning("Keyspace #{keyspace} does not exist.",
67-
tag: "realm_not_found"
68-
)
69-
70-
{:error, :realm_not_found}
71-
72-
nil ->
73-
_ =
74-
Logger.warning(
75-
"Database error: #{Exception.message(error)}.",
76-
tag: "database_error"
77-
)
78-
79-
{:error, :database_error}
36+
with {:ok, pem} <-
37+
KvStore.fetch_value("auth", "jwt_public_key_pem", :string,
38+
prefix: keyspace,
39+
consistency: :quorum,
40+
error: :public_key_not_found
41+
) do
42+
{:ok, [pem]}
8043
end
8144
end
8245

@@ -155,15 +118,11 @@ defmodule Astarte.Pairing.Queries do
155118
keyspace_name =
156119
CQLUtils.realm_name_to_keyspace_name(realm_name, Config.astarte_instance_id!())
157120

158-
try do
159-
Repo.fetch(Device, device_id,
160-
prefix: keyspace_name,
161-
consistency: :quorum,
162-
error: :device_not_found
163-
)
164-
rescue
165-
err -> handle_xandra_error(err)
166-
end
121+
Repo.fetch(Device, device_id,
122+
prefix: keyspace_name,
123+
consistency: :quorum,
124+
error: :device_not_found
125+
)
167126
end
168127

169128
def update_device_after_credentials_request(realm_name, device, cert_data, device_ip, nil) do
@@ -201,42 +160,34 @@ defmodule Astarte.Pairing.Queries do
201160
def fetch_device_registration_limit(realm_name) do
202161
keyspace = CQLUtils.realm_name_to_keyspace_name("astarte", Config.astarte_instance_id!())
203162

204-
try do
205-
case Repo.fetch(Realm, realm_name,
206-
prefix: keyspace,
207-
consistency: :one,
208-
error: :realm_not_found
209-
) do
210-
{:ok, realm} ->
211-
{:ok, realm.device_registration_limit}
212-
213-
{:error, :realm_not_found} ->
214-
Logger.warning(
215-
"cannot fetch device registration limit: realm #{realm_name} not found",
216-
tag: "realm_not_found"
217-
)
163+
case Repo.fetch(Realm, realm_name,
164+
prefix: keyspace,
165+
consistency: :one,
166+
error: :realm_not_found
167+
) do
168+
{:ok, realm} ->
169+
{:ok, realm.device_registration_limit}
170+
171+
{:error, :realm_not_found} ->
172+
Logger.warning(
173+
"cannot fetch device registration limit: realm #{realm_name} not found",
174+
tag: "realm_not_found"
175+
)
218176

219-
{:error, :realm_not_found}
220-
end
221-
rescue
222-
err -> handle_xandra_error(err)
177+
{:error, :realm_not_found}
223178
end
224179
end
225180

226181
def fetch_registered_devices_count(realm_name) do
227182
keyspace =
228183
CQLUtils.realm_name_to_keyspace_name(realm_name, Config.astarte_instance_id!())
229184

230-
try do
231-
count =
232-
Device
233-
|> select([d], count())
234-
|> Repo.one!(prefix: keyspace, consistency: :one)
185+
count =
186+
Device
187+
|> select([d], count())
188+
|> Repo.one!(prefix: keyspace, consistency: :one)
235189

236-
{:ok, count}
237-
rescue
238-
err -> handle_xandra_error(err)
239-
end
190+
{:ok, count}
240191
end
241192

242193
defp do_register_device(

apps/astarte_pairing/test/astarte_pairing/engine_test.exs

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ defmodule Astarte.Pairing.EngineTest do
6363

6464
describe "get_agent_public_key_pem" do
6565
test "fails with non-existing realm" do
66-
assert {:error, :realm_not_found} = Engine.get_agent_public_key_pems("nonexisting")
66+
assert_raise Xandra.Error, "Keyspace nonexisting does not exist", fn ->
67+
Engine.get_agent_public_key_pems("nonexisting")
68+
end
6769
end
6870

6971
test "successful call" do
@@ -214,7 +216,9 @@ defmodule Astarte.Pairing.EngineTest do
214216
realm = "nonexisting"
215217
device_id = TestHelper.random_128_bit_hw_id()
216218

217-
assert {:error, :realm_not_found} = Engine.unregister_device(realm, device_id)
219+
assert_raise Xandra.Error, "Keyspace nonexisting does not exist", fn ->
220+
Engine.unregister_device(realm, device_id)
221+
end
218222
end
219223

220224
test "fails with invalid device_id" do
@@ -292,15 +296,16 @@ defmodule Astarte.Pairing.EngineTest do
292296
test "fails with unexisting realm", %{hw_id: hw_id, secret: secret} do
293297
realm = "unexisting"
294298

295-
assert {:error, :realm_not_found} =
296-
Engine.get_credentials(
297-
@astarte_protocol,
298-
@astarte_credentials_params,
299-
realm,
300-
hw_id,
301-
secret,
302-
@valid_ip
303-
)
299+
assert_raise Xandra.Error, "Keyspace unexisting does not exist", fn ->
300+
Engine.get_credentials(
301+
@astarte_protocol,
302+
@astarte_credentials_params,
303+
realm,
304+
hw_id,
305+
secret,
306+
@valid_ip
307+
)
308+
end
304309
end
305310

306311
test "fails with not registered device" do

apps/astarte_pairing/test/astarte_pairing/rpc/handler_test.exs

Lines changed: 6 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -127,23 +127,9 @@ defmodule Astarte.Pairing.RPC.HandlerTest do
127127
%Call{call: {:get_agent_public_key_pems, %GetAgentPublicKeyPEMs{realm: "invalid"}}}
128128
|> Call.encode()
129129

130-
{:ok, reply} = Handler.handle_rpc(encoded)
131-
132-
expected_err_reply = %Reply{
133-
error: true,
134-
reply:
135-
{:generic_error_reply,
136-
%GenericErrorReply{
137-
error_name: "realm_not_found",
138-
error_data: nil,
139-
user_readable_error_name: nil,
140-
user_readable_message: nil,
141-
user_readable_message: nil
142-
}},
143-
version: 0
144-
}
145-
146-
assert Reply.decode(reply) == expected_err_reply
130+
assert_raise Xandra.Error, "Keyspace invalid does not exist", fn ->
131+
Handler.handle_rpc(encoded)
132+
end
147133
end
148134

149135
test "successful call" do
@@ -183,23 +169,9 @@ defmodule Astarte.Pairing.RPC.HandlerTest do
183169
%Call{call: {:get_info, %GetInfo{realm: "invalid", hw_id: hw_id, secret: secret}}}
184170
|> Call.encode()
185171

186-
{:ok, reply} = Handler.handle_rpc(encoded)
187-
188-
expected_err_reply = %Reply{
189-
error: true,
190-
reply:
191-
{:generic_error_reply,
192-
%GenericErrorReply{
193-
error_name: "realm_not_found",
194-
error_data: nil,
195-
user_readable_error_name: nil,
196-
user_readable_message: nil,
197-
user_readable_message: nil
198-
}},
199-
version: 0
200-
}
201-
202-
assert Reply.decode(reply) == expected_err_reply
172+
assert_raise Xandra.Error, "Keyspace invalid does not exist", fn ->
173+
Handler.handle_rpc(encoded)
174+
end
203175
end
204176

205177
test "successful call with pending device", %{hw_id: hw_id, secret: secret} do

0 commit comments

Comments
 (0)