Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TBS-2755: Improve ETCD timeout handling #9

Merged
merged 2 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# Changelog
## 2.0.0

* `ETCD` oprations no longer crash on timeout
* `ETCD` oprations now return an error tuple `{:error, :timeout}` on timeout

## 1.3.0

Expand Down
34 changes: 28 additions & 6 deletions lib/etcd_ex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ defmodule EtcdEx do
@type watch_ref :: reference
@type watching_process :: pid

# Default timeout for all operations. After this time, operations will return {:error, :timeout}
@default_timeout :timer.seconds(5)

@doc """
Expand Down Expand Up @@ -158,8 +159,9 @@ defmodule EtcdEx do
filters out lesser create revisions.
* `:max_create_revision` - the upper bound for key create revisions;
filters out greater create revisions.
* `:timeout` - indicates max time to wait for a response. Defaults to
`:infinity`.
* `:timeout` - indicates max time to wait for a response. Defaults to 5 seconds.
If the operation takes longer than the specified timeout, it will return
`{:error, :timeout}` instead of crashing.

## Response

Expand Down Expand Up @@ -214,6 +216,12 @@ defmodule EtcdEx do
* `:mod_revision` - revision of the last modification on the key.
* `:lease` - the ID of the lease attached to the key. If lease is 0, then
no lease is attached to the key.

## Error Handling

The function will return `{:error, :timeout}` if the operation takes longer than
the specified timeout value. This is a graceful error handling mechanism that
prevents the process from crashing on timeouts.
"""
@spec get(conn, Types.key(), [Types.get_opt()], timeout) ::
{:ok, any} | {:error, Types.error()}
Expand All @@ -239,8 +247,15 @@ defmodule EtcdEx do
value. Returns an error if the key does not exist.
* `:ignore_lease` - when set, update the key without changing its current
lease. Returns an error if the key does not exist.
* `:timeout` - indicates max time to wait for a response. Defaults to
`:infinity`.
* `:timeout` - indicates max time to wait for a response. Defaults to 5 seconds.
If the operation takes longer than the specified timeout, it will return
`{:error, :timeout}` instead of crashing.

## Error Handling

The function will return `{:error, :timeout}` if the operation takes longer than
the specified timeout value. This is a graceful error handling mechanism that
prevents the process from crashing on timeouts.
"""
@spec put(conn, Types.key(), Types.value(), [Types.put_opt()], timeout) ::
{:ok, any} | {:error, Types.error()}
Expand All @@ -262,8 +277,15 @@ defmodule EtcdEx do
keys after `key` argument.
* `:prev_kv` - when set, return the contents of the deleted key-value
pairs.
* `:timeout` - indicates max time to wait for a response. Defaults to
`:infinity`.
* `:timeout` - indicates max time to wait for a response. Defaults to 5 seconds.
If the operation takes longer than the specified timeout, it will return
`{:error, :timeout}` instead of crashing.

## Error Handling

The function will return `{:error, :timeout}` if the operation takes longer than
the specified timeout value. This is a graceful error handling mechanism that
prevents the process from crashing on timeouts.
"""
@spec delete(conn, Types.key(), [Types.delete_opt()], timeout) ::
{:ok, any} | {:error, Types.error()}
Expand Down
36 changes: 28 additions & 8 deletions lib/etcd_ex/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,40 @@ defmodule EtcdEx.Connection do
]

@doc false
def unary(conn, fun, args, timeout),
do: Connection.call(conn, {:unary, fun, args}, timeout)
def unary(conn, fun, args, timeout) do
try do
Connection.call(conn, {:unary, fun, args}, timeout)
catch
:exit, {:timeout, _} -> {:error, :timeout}
end
end

@doc false
def watch(conn, watching_process, key, opts, timeout),
do: Connection.call(conn, {:watch, watching_process, key, opts}, timeout)
def watch(conn, watching_process, key, opts, timeout) do
try do
Connection.call(conn, {:watch, watching_process, key, opts}, timeout)
catch
:exit, {:timeout, _} -> {:error, :timeout}
end
end

@doc false
def cancel_watch(conn, watching_process, timeout),
do: Connection.call(conn, {:cancel_watch, watching_process}, timeout)
def cancel_watch(conn, watching_process, timeout) do
try do
Connection.call(conn, {:cancel_watch, watching_process}, timeout)
catch
:exit, {:timeout, _} -> {:error, :timeout}
end
end

@doc false
def list_watches(conn, watching_process, timeout),
do: Connection.call(conn, {:list_watches, watching_process}, timeout)
def list_watches(conn, watching_process, timeout) do
try do
Connection.call(conn, {:list_watches, watching_process}, timeout)
catch
:exit, {:timeout, _} -> {:error, :timeout}
end
end

@doc false
def child_spec(options) do
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule EtcdEx.MixProject do
def project do
[
app: :etcdex,
version: "1.3.0",
version: "2.0.0",
elixir: "~> 1.10",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
Expand Down
Loading