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

Fix ChainSync reconnection #35

Merged
merged 3 commits into from
Jul 5, 2024
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed

- ChainSync reconnection issue (#33)

## [v0.4.0](https://github.com/wowica/xogmios/releases/tag/v0.4.0) (2024-05-31)

### Added
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,7 @@ For examples of applications using this library, see [Blocks](https://github.com
## Test

Run `mix test`. Tests do NOT rely on a running Ogmios instance.

## Help

Join the #elixir channel in the [TxPipe Discord](https://discord.gg/ZTHcHUy5HY)
32 changes: 15 additions & 17 deletions lib/xogmios/chain_sync.ex
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,20 @@ defmodule Xogmios.ChainSync do
@doc """
Invoked upon disconnecting from the server. This callback is optional.

Returning `{:ok, new_state}` will allow the connection to close.
Returning `{:reconnect, interval_in_ms, new_state}` will attempt a reconnection
after `interval_in_ms`.

Returning `{:reconnect, interval_in_ms}` will attempt a reconnection after `interval_in_ms`
Returning `{:close, reason, new_state}` will allow the connection to close and
shut the process down cleanly.

Returning `{:ok, new_state}` will allow the connection to close but keeps
process alive.
"""
@callback handle_disconnect(reason :: String.t(), state) ::
{:ok, new_state}
| {:reconnect, interval_in_ms :: non_neg_integer(), new_state}
when state: term(), new_state: term()
@callback handle_disconnect(reason, state) ::
{:reconnect, interval_in_ms :: non_neg_integer(), new_state}
| {:close, reason, new_state}
| {:ok, new_state}
when reason: String.t(), state: term(), new_state: term()

# The keepalive option is used to maintain the connection active.
# This is important because proxies might close idle connections after a few seconds.
Expand All @@ -81,20 +87,12 @@ defmodule Xogmios.ChainSync do
def start_link(client, opts) do
{url, opts} = Keyword.pop(opts, :url)
{name, opts} = Keyword.pop(opts, :name, client)
initial_state = Keyword.merge(opts, handler: client, notify_on_connect: self())

initial_state = Keyword.merge(opts, handler: client)

with {:ok, process_name} <- build_process_name(name),
{:ok, ws_pid} <- start_link(process_name, url, client, initial_state) do
# Blocks until the connection with the Ogmios server
# is established or until timeout is reached.
receive do
{:connected, _connection} -> {:ok, ws_pid}
after
_timeout = 5_000 ->
Logger.warning("Timeout connecting to Ogmios server")
send(ws_pid, :close)
{:error, :connection_timeout}
end
{:ok, ws_pid}
else
{:error, :invalid_process_name} = error ->
error
Expand Down
15 changes: 10 additions & 5 deletions lib/xogmios/chain_sync/connection.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ defmodule Xogmios.ChainSync.Connection do
id: Keyword.get(opts, :id, __MODULE__),
start: {__MODULE__, :start_link, [opts]},
shutdown: 5_000,
restart: Keyword.get(opts, :restart, :transient),
restart: Keyword.get(opts, :restart, :temporary),
type: :worker
}
end
Expand All @@ -41,7 +41,6 @@ defmodule Xogmios.ChainSync.Connection do

start_message = Messages.initial_sync()
:websocket_client.cast(self(), {:text, start_message})
send(state.notify_on_connect, {:connected, connection})

case state.handler.handle_connect(state) do
{:ok, new_state} ->
Expand All @@ -55,11 +54,17 @@ defmodule Xogmios.ChainSync.Connection do
@impl true
def ondisconnect(reason, state) do
case state.handler.handle_disconnect(reason, state) do
{:ok, state} ->
{:ok, state}

# Attempt to reconnect after interval in ms
{:reconnect, reconnect_interval_in_ms, new_state} ->
{:reconnect, reconnect_interval_in_ms, new_state}

# Shut the process down cleanly
{:close, reason, state} ->
{:close, reason, state}

# Disconnect but keeps process alive
{:ok, state} ->
{:ok, state}
end
end

Expand Down
Loading