Current section

Files

Jump to
mongodb_driver lib mongo error.ex
Raw

lib/mongo/error.ex

defmodule Mongo.Error do
alias Mongo.Events
defexception [:message, :code, :host, :error_labels, :resumable, :retryable_reads, :retryable_writes]
@host_unreachable 6
@host_not_found 7
@network_timeout 89
@shutdown_in_progress 91
@primary_stepped_down 189
@exceeded_time_limit 262
@socket_exception 9001
@not_master 10107
@interrupted_at_shutdown 11600
@interrupted_due_to_repl_state_change 11602
@not_master_no_slaveok 13435
@not_master_or_secondary 13436
@stale_shard_version 63
@stale_epoch 150
@stale_config 13388
@retry_change_stream 234
@failed_to_satisfy_read_preference 133
@retryable_writes [@interrupted_at_shutdown, @interrupted_due_to_repl_state_change, @not_master, @not_master_no_slaveok,
@not_master_or_secondary, @primary_stepped_down, @shutdown_in_progress, @host_not_found,
@host_unreachable, @network_timeout, @socket_exception, @exceeded_time_limit ]
@retryable_reads [@interrupted_at_shutdown, @interrupted_due_to_repl_state_change, @not_master,
@not_master_no_slaveok, @not_master_or_secondary, @primary_stepped_down,
@host_not_found, @host_unreachable , @network_timeout, @socket_exception]
@resumable [@host_unreachable, @host_not_found, @network_timeout, @shutdown_in_progress, @primary_stepped_down,
@exceeded_time_limit, @socket_exception, @not_master, @interrupted_at_shutdown, @interrupted_at_shutdown,
@interrupted_due_to_repl_state_change, @not_master_no_slaveok, @not_master_or_secondary, @stale_shard_version,
@stale_epoch, @stale_config, @retry_change_stream, @failed_to_satisfy_read_preference]
@type t :: %__MODULE__{
message: String.t,
code: number,
host: String.t,
error_labels: [String.t] | nil,
resumable: boolean,
retryable_reads: boolean,
retryable_writes: boolean
}
def message(e) do
code = if e.code, do: " #{e.code}"
"#{e.message}#{code}"
end
def exception(tag: :tcp, action: action, reason: reason, host: host) do
formatted_reason = :inet.format_error(reason)
%Mongo.Error{message: "#{host} tcp #{action}: #{formatted_reason} - #{inspect(reason)}", host: host, resumable: true}
end
def exception(tag: :ssl, action: action, reason: reason, host: host) do
formatted_reason = :ssl.format_error(reason)
%Mongo.Error{message: "#{host} ssl #{action}: #{formatted_reason} - #{inspect(reason)}", host: host, resumable: false}
end
def exception(%{"code" => code, "errmsg" => msg} = doc) do
errorLabels = doc["errorLabels"] || []
resumable = Enum.any?(@resumable, &(&1 == code)) || Enum.any?(errorLabels, &(&1 == "ResumableChangeStreamError"))
retryable_reads = Enum.any?(@retryable_reads, &(&1 == code)) || Enum.any?(errorLabels, &(&1 == "RetryableReadError"))
retryable_writes = Enum.any?(@retryable_writes, &(&1 == code)) || Enum.any?(errorLabels, &(&1 == "RetryableWriteError"))
%Mongo.Error{message: msg, code: code, error_labels: errorLabels, resumable: resumable, retryable_reads: retryable_reads, retryable_writes: retryable_writes}
end
def exception(message: message, code: code) do
%Mongo.Error{message: message, code: code, resumable: Enum.any?(@resumable, &(&1 == code))}
end
def exception(message) do
%Mongo.Error{message: message, resumable: false}
end
@doc """
Return true if the error is retryalble for read operations.
"""
def should_retry_read(%Mongo.Error{retryable_reads: true}, cmd, opts) do
[{command_name,_}|_] = cmd
result = (command_name != :getMore and opts[:read_counter] == 1)
if result do
Events.notify(%Mongo.Events.RetryReadEvent{command_name: command_name, command: cmd}, :commands)
end
result
end
def should_retry_read(_error, _cmd, _opts) do
false
end
@doc """
Return true if the error is retryalble for writes operations.
"""
def should_retry_write(%Mongo.Error{retryable_writes: true}, cmd, opts) do
[{command_name,_}|_] = cmd
result = opts[:write_counter] == 1
if result do
Events.notify(%Mongo.Events.RetryWriteEvent{command_name: command_name, command: cmd}, :commands)
end
result
end
def should_retry_write(_error, _cmd, _opts) do
false
end
def has_label(%Mongo.Error{error_labels: labels}, label) when is_list(labels)do
Enum.any?(labels, fn l -> l == label end)
end
def has_label(_other, _label) do
false
end
end
defmodule Mongo.WriteError do
defexception [:n, :ok, :write_errors]
def message(e) do
"n: #{e.n}, ok: #{e.ok}, write_errors: #{inspect e.write_errors}"
end
end